v3 init push
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Every entry carries the timezone it was written in, and every stamp is
|
||||
* formatted in that timezone rather than in the reader's current one - a
|
||||
* journal written on a trip should still read as the local time of the moment.
|
||||
* Timestamps cross the wire as UNIX seconds, so nothing here parses a string.
|
||||
*/
|
||||
|
||||
const asFormatterCache = new Map();
|
||||
|
||||
function getFormatter(sLocale, sTimezone, asOptions) {
|
||||
const sKey = sLocale + '|' + sTimezone + '|' + JSON.stringify(asOptions);
|
||||
|
||||
if(!asFormatterCache.has(sKey)) {
|
||||
let oFormatter;
|
||||
try {
|
||||
oFormatter = new Intl.DateTimeFormat(sLocale, {...asOptions, timeZone: sTimezone});
|
||||
}
|
||||
catch{
|
||||
//An unknown IANA name (renamed zone, hand-edited row) must not take
|
||||
//the whole book down - fall back to the browser's own zone.
|
||||
oFormatter = new Intl.DateTimeFormat(sLocale, asOptions);
|
||||
}
|
||||
asFormatterCache.set(sKey, oFormatter);
|
||||
}
|
||||
|
||||
return asFormatterCache.get(sKey);
|
||||
}
|
||||
|
||||
export function getBrowserTimezone() {
|
||||
try {
|
||||
return Intl.DateTimeFormat().resolvedOptions().timeZone || '';
|
||||
}
|
||||
catch{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/** 'YYYY-MM-DD' for the given instant, as seen in the given timezone. */
|
||||
export function getDayKey(iUnix, sTimezone) {
|
||||
return getFormatter('en-CA', sTimezone, {year: 'numeric', month: '2-digit', day: '2-digit'}).format(iUnix * 1000);
|
||||
}
|
||||
|
||||
/** 'YYYY-MM-DD' for a local Date, without the UTC shift toISOString() adds. */
|
||||
export function getLocalDayKey(oDate) {
|
||||
const sMonth = String(oDate.getMonth() + 1).padStart(2, '0');
|
||||
const sDay = String(oDate.getDate()).padStart(2, '0');
|
||||
return oDate.getFullYear() + '-' + sMonth + '-' + sDay;
|
||||
}
|
||||
|
||||
export function formatDate(iUnix, sTimezone, sLocale) {
|
||||
return getFormatter(sLocale, sTimezone, {day: 'numeric', month: 'short', year: 'numeric'}).format(iUnix * 1000);
|
||||
}
|
||||
|
||||
export function formatShortDate(iUnix, sTimezone, sLocale) {
|
||||
return getFormatter(sLocale, sTimezone, {day: 'numeric', month: 'short'}).format(iUnix * 1000);
|
||||
}
|
||||
|
||||
export function formatTime(iUnix, sTimezone, sLocale) {
|
||||
return getFormatter(sLocale, sTimezone, {hour: '2-digit', minute: '2-digit'}).format(iUnix * 1000);
|
||||
}
|
||||
|
||||
export function formatWeekday(iUnix, sTimezone, sLocale) {
|
||||
return getFormatter(sLocale, sTimezone, {weekday: 'long'}).format(iUnix * 1000);
|
||||
}
|
||||
|
||||
export function formatFull(iUnix, sTimezone, sLocale) {
|
||||
return getFormatter(sLocale, sTimezone, {
|
||||
weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', hour: '2-digit', minute: '2-digit'
|
||||
}).format(iUnix * 1000);
|
||||
}
|
||||
|
||||
export function formatMonthTitle(oDate, sLocale) {
|
||||
return new Intl.DateTimeFormat(sLocale, {month: 'long', year: 'numeric'}).format(oDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Weekday initials starting on Monday, in the reader's locale.
|
||||
*/
|
||||
export function getWeekdayInitials(sLocale) {
|
||||
const oFormatter = new Intl.DateTimeFormat(sLocale, {weekday: 'short'});
|
||||
const asLabels = [];
|
||||
|
||||
//2024-01-01 was a Monday, which anchors the week without hard-coding names.
|
||||
for(let iDay = 0; iDay < 7; iDay++) {
|
||||
asLabels.push(oFormatter.format(new Date(Date.UTC(2024, 0, 1 + iDay))));
|
||||
}
|
||||
|
||||
return asLabels;
|
||||
}
|
||||
|
||||
/** Short "how long ago", used by the autosave indicator only. */
|
||||
export function formatSince(iUnix, sLocale, sJustNow) {
|
||||
const iSeconds = Math.round(Date.now() / 1000) - iUnix;
|
||||
if(iSeconds < 45) return sJustNow;
|
||||
|
||||
const oFormatter = new Intl.RelativeTimeFormat(sLocale, {numeric: 'auto'});
|
||||
if(iSeconds < 3600) return oFormatter.format(-Math.round(iSeconds / 60), 'minute');
|
||||
if(iSeconds < 86400) return oFormatter.format(-Math.round(iSeconds / 3600), 'hour');
|
||||
return oFormatter.format(-Math.round(iSeconds / 86400), 'day');
|
||||
}
|
||||
Reference in New Issue
Block a user