76 lines
2.9 KiB
JavaScript
76 lines
2.9 KiB
JavaScript
// Generated, do not edit. sha256:f7c492e9043516674843077cdedb9f9190b5176696652a8825a3e593c111d7ea
|
|||
|
|
import { localeTag } from '../i18n/index.js';
|
||
|
|
|
||
|
|
const MIN = 60 * 1000;
|
||
|
|
const WEEKDAY_NUM = { Sun: 0, Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6 };
|
||
|
|
|
||
|
|
const _partsFmt = new Map();
|
||
|
|
function wallParts(tz, instant) {
|
||
|
|
let f = _partsFmt.get(tz);
|
||
|
|
if (!f) {
|
||
|
|
f = new Intl.DateTimeFormat('en-US', {
|
||
|
|
timeZone: tz, hourCycle: 'h23', weekday: 'short',
|
||
|
|
year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit',
|
||
|
|
});
|
||
|
|
_partsFmt.set(tz, f);
|
||
|
|
}
|
||
|
|
const p = {};
|
||
|
|
for (const part of f.formatToParts(instant)) p[part.type] = part.value;
|
||
|
|
return { y: +p.year, mo: +p.month, d: +p.day, wd: WEEKDAY_NUM[p.weekday], h: +p.hour % 24, mi: +p.minute };
|
||
|
|
}
|
||
|
|
|
||
|
|
export function wallToInstant(tz, y, mo, d, h, mi) {
|
||
|
|
const target = Date.UTC(y, mo - 1, d, h, mi);
|
||
|
|
let t = target;
|
||
|
|
for (let i = 0; i < 2; i++) {
|
||
|
|
const w = wallParts(tz, new Date(t));
|
||
|
|
t += target - Date.UTC(w.y, w.mo - 1, w.d, w.h, w.mi);
|
||
|
|
}
|
||
|
|
return new Date(t);
|
||
|
|
}
|
||
|
|
|
||
|
|
const hm = (s) => s.split(':').map(Number);
|
||
|
|
|
||
|
|
export function exchangeStatus(ex, now = new Date()) {
|
||
|
|
const [oh, om] = hm(ex.open);
|
||
|
|
const [ch, cm] = hm(ex.close);
|
||
|
|
const today = wallParts(ex.tz, now);
|
||
|
|
for (let d = 0; d < 8; d++) {
|
||
|
|
const day = new Date(Date.UTC(today.y, today.mo - 1, today.d + d));
|
||
|
|
if (!ex.days.includes(day.getUTCDay())) continue;
|
||
|
|
const y = day.getUTCFullYear(), mo = day.getUTCMonth() + 1, dd = day.getUTCDate();
|
||
|
|
const opens = wallToInstant(ex.tz, y, mo, dd, oh, om);
|
||
|
|
const closes = wallToInstant(ex.tz, y, mo, dd, ch, cm);
|
||
|
|
if (now < opens) return { isOpen: false, openedAt: null, closesAt: null, opensAt: opens };
|
||
|
|
if (now < closes) return { isOpen: true, openedAt: opens, closesAt: closes, opensAt: null };
|
||
|
|
}
|
||
|
|
return { isOpen: false, openedAt: null, closesAt: null, opensAt: null };
|
||
|
|
}
|
||
|
|
|
||
|
|
export function durationParts(ms) {
|
||
|
|
const minutes = Math.max(1, Math.ceil(ms / MIN));
|
||
|
|
if (minutes < 60) return { unit: 'min', n: minutes };
|
||
|
|
if (minutes < 180) return { unit: 'hourMin', n: Math.floor(minutes / 60), m: minutes % 60 };
|
||
|
|
if (minutes < 24 * 60) return { unit: 'hours', n: Math.round(minutes / 60) };
|
||
|
|
return { unit: 'days', n: Math.round(minutes / (24 * 60)) };
|
||
|
|
}
|
||
|
|
|
||
|
|
const _clockFmt = new Map();
|
||
|
|
export function localClock(instant, now = new Date(), tz = undefined) {
|
||
|
|
const tag = localeTag();
|
||
|
|
const key = `${tag}|${tz || ''}`;
|
||
|
|
let f = _clockFmt.get(key);
|
||
|
|
if (!f) {
|
||
|
|
f = {
|
||
|
|
time: new Intl.DateTimeFormat(tag, { timeZone: tz, hour: '2-digit', minute: '2-digit', hourCycle: 'h23' }),
|
||
|
|
day: new Intl.DateTimeFormat('en-CA', { timeZone: tz, year: 'numeric', month: '2-digit', day: '2-digit' }),
|
||
|
|
weekday: new Intl.DateTimeFormat(tag, { timeZone: tz, weekday: 'short' }),
|
||
|
|
};
|
||
|
|
_clockFmt.set(key, f);
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
time: f.time.format(instant),
|
||
|
|
otherDay: f.day.format(instant) !== f.day.format(now),
|
||
|
|
weekday: f.weekday.format(instant),
|
||
|
|
};
|
||
|
|
}
|