Skip to content

Instantly share code, notes, and snippets.

@Lazialize
Last active January 22, 2024 03:56
Show Gist options
  • Save Lazialize/ee5969a85995c39e593b5132d85c76db to your computer and use it in GitHub Desktop.
Save Lazialize/ee5969a85995c39e593b5132d85c76db to your computer and use it in GitHub Desktop.
特定の日付からn営業日分の配列を返す関数
// 適当タイムゾーン
const Timezone = {
"Africa/Johannesburg": 2,
"Africa/Lagos": 1,
"Africa/Windhoek": 1,
"America/Adak": -10,
"America/Anchorage": -9,
"America/Argentina/Buenos_Aires": -3,
"America/Bogota": -5,
"America/Caracas": -4.5,
"America/Chicago": -6,
"America/Denver": -7,
"America/Godthab": -3,
"America/Guatemala": -6,
"America/Halifax": -4,
"America/Los_Angeles": -8,
"America/Montevideo": -3,
"America/New_York": -5,
"America/Noronha": -2,
"America/Phoenix": -7,
"America/Santiago": -4,
"America/Santo_Domingo": -4,
"America/St_Johns": -3.5,
"Asia/Baghdad": 3,
"Asia/Baku": 4,
"Asia/Beirut": 2,
"Asia/Dhaka": 6,
"Asia/Dubai": 4,
"Asia/Irkutsk": 9,
"Asia/Jakarta": 7,
"Asia/Kabul": 4.5,
"Asia/Kamchatka": 12,
"Asia/Karachi": 5,
"Asia/Kathmandu": 5.75,
"Asia/Kolkata": 5.5,
"Asia/Krasnoyarsk": 8,
"Asia/Omsk": 7,
"Asia/Rangoon": 6.5,
"Asia/Shanghai": 8,
"Asia/Tehran": 3.5,
"Asia/Tokyo": 9,
"Asia/Vladivostok": 11,
"Asia/Yakutsk": 10,
"Asia/Yekaterinburg": 6,
"Atlantic/Azores": -1,
"Atlantic/Cape_Verde": -1,
"Australia/Adelaide": 9.5,
"Australia/Brisbane": 10,
"Australia/Darwin": 9.5,
"Australia/Eucla": 8.75,
"Australia/Lord_Howe": 10.5,
"Australia/Sydney": 10,
"Etc/GMT+12": -12,
"Europe/Berlin": 1,
"Europe/London": 0,
"Europe/Moscow": 4,
"Pacific/Apia": 13,
"Pacific/Auckland": 12,
"Pacific/Chatham": 12.75,
"Pacific/Easter": -6,
"Pacific/Gambier": -9,
"Pacific/Honolulu": -10,
"Pacific/Kiritimati": 14,
"Pacific/Majuro": 12,
"Pacific/Marquesas": -9.5,
"Pacific/Norfolk": 11.5,
"Pacific/Noumea": 11,
"Pacific/Pago_Pago": -11,
"Pacific/Pitcairn": -8,
"Pacific/Tongatapu": 13,
"UTC": 0,
} as const;
enum DayOfWeek {
SUNDAY=0,
SATURDAY=6
}
type Direction = 'before' | 'after'
const initDates = (initial: Date[], baseDate: Date, length: number, direction: Direction): Date[] => {
const copiedDates = [...initial];
const copiedBaseDate = new Date(baseDate);
// 日付だけ考慮したいので時間を0に設定する
copiedBaseDate.setHours(0, 0, 0, 0)
for (let i = 1; i <= length - (initial.length); i++) {
const diffTime = 1000 * 60 * 60 * 24 * i;
copiedDates.push(new Date(copiedBaseDate.getTime() - (direction === 'before' ? diffTime : -diffTime)))
}
return copiedDates;
}
/**
* 指定の日から n 営業日(後|前)までの日付のリストを返却する。
*
* @param daysCount 数える日数
* @param baseDate 基準の日時
* @param direction n日前,n日後
* @param options その他の設定
* @returns 日付のリスト
*/
const calc = (
daysCount: number,
baseDate: Date,
direction: Direction,
options: {
timezone?: keyof typeof Timezone;
customs?: Date[];
initialValue?: Date[];
}
): Date[] => {
const { timezone, customs, initialValue } = options;
const dates = initDates(initialValue ?? [], baseDate, daysCount, direction);
const mostOldDate = dates[dates.length - 1]
// リストの操作をForで行うので,Forで回すリストと実際に操作するリストを分離する。
const copiedDates = [...dates]
for (const date of copiedDates) {
// タイムゾーンを考慮した時間に変更する
const zoned = new Date(date.getTime() + 1000 * 60 * 60 * Timezone[timezone || 'UTC'])
// 休日,またはカスタムの休日に該当する日をリストから除外する
if ([DayOfWeek.SUNDAY, DayOfWeek.SATURDAY].includes(zoned.getDay())) {
dates.splice(dates.indexOf(date), 1)
} else if (customs?.some(custom => {
const zonedCustom = new Date(custom.getTime() - 1000 * 60 * 60 * Timezone[timezone || 'UTC'])
return zonedCustom.getTime() === date.getTime()
})) {
dates.splice(dates.indexOf(date), 1)
}
}
// 求める日数と同じであれば返却し,そうでなければ処理を続行する
if (dates.length === daysCount) {
return dates;
}
return calc(
daysCount,
mostOldDate,
direction,
{
customs: customs,
timezone: timezone,
initialValue: dates
}
)
}
// 今日
const result = calc(7, new Date(), 'after', {
// 休日にしたい日付の配列。時間は指定のtimezoneで解釈される。
customs: [new Date('2024-01-25')],
timezone: 'Asia/Tokyo'
})
console.log(result.map(date => date.toLocaleString()))
@Lazialize
Copy link
Author

タイムゾーンを渡すと曜日計算とcustomがタイムゾーン考慮になるようにすると良さそうわね。

@Lazialize
Copy link
Author

やったわよ

@Lazialize
Copy link
Author

n営業日後も出せるようにした。

@Lazialize
Copy link
Author

全タイムゾーンに対応(笑)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment