quiet-hours.js
1.95 KB
/**
* 安静时段内的通知推迟到安静时段结束的整点;不在安静时段则立即发送。
* 起止相同表示没有安静时段。
* ponytail: 用「距结束还有几小时几分」推算,夏令时切换当晚会差一小时;要精确就换成按时区构造目标时刻。
*
* @param {Date} now
* @param {{ timezone: string, quiet_start_hour: number, quiet_end_hour: number }} settings
* @returns {Date}
*/
export function nextAllowedSendTime(now, { timezone, quiet_start_hour, quiet_end_hour }) {
const parts = new Intl.DateTimeFormat('en-US', { timeZone: timezone, hour: 'numeric', minute: 'numeric', second: 'numeric', hourCycle: 'h23' }).formatToParts(now)
const part = (/** @type {string} */ type) => Number(parts.find((item) => item.type === type).value)
const hour = part('hour')
const quiet = quiet_start_hour < quiet_end_hour ? hour >= quiet_start_hour && hour < quiet_end_hour : quiet_start_hour > quiet_end_hour && (hour >= quiet_start_hour || hour < quiet_end_hour)
if (!quiet) return now
const secondsLeft = ((quiet_end_hour - hour + 24) % 24) * 3600 - part('minute') * 60 - part('second')
return new Date(now.getTime() - now.getMilliseconds() + secondsLeft * 1000)
}
/**
* 该时区下一个 `hour` 点整(严格晚于 now),用于每日定时通知。夏令时的近似同上。
* @param {Date} now
* @param {string} timezone
* @param {number} hour 0–23
* @returns {Date}
*/
export function nextLocalHour(now, timezone, hour) {
const parts = new Intl.DateTimeFormat('en-US', { timeZone: timezone, hour: 'numeric', minute: 'numeric', second: 'numeric', hourCycle: 'h23' }).formatToParts(now)
const part = (/** @type {string} */ type) => Number(parts.find((item) => item.type === type).value)
const secondsLeft = ((hour - part('hour') + 24) % 24) * 3600 - part('minute') * 60 - part('second')
return new Date(now.getTime() - now.getMilliseconds() + (secondsLeft <= 0 ? secondsLeft + 86400 : secondsLeft) * 1000)
}