Last active
January 22, 2024 03:56
-
-
Save Lazialize/ee5969a85995c39e593b5132d85c76db to your computer and use it in GitHub Desktop.
特定の日付からn営業日分の配列を返す関数
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 適当タイムゾーン | |
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())) |
やったわよ
n営業日後も出せるようにした。
全タイムゾーンに対応(笑)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
タイムゾーンを渡すと曜日計算と
custom
がタイムゾーン考慮になるようにすると良さそうわね。