34 lines
1.5 KiB
JavaScript
34 lines
1.5 KiB
JavaScript
import dayjs from 'dayjs';
|
|
|
|
/**
|
|
* Doormile timestamps are IST (Asia/Kolkata) wall-clock stored in Postgres
|
|
* `timestamp without time zone` columns. Some responses come back with a
|
|
* trailing Z/offset anyway — a known Go+pgx footgun where a naive DB timestamp
|
|
* loads into `time.Time` under the UTC location and gets marshalled with a
|
|
* false "Z" suffix. dayjs reads a Z-suffixed string as a real UTC instant and
|
|
* converts it to the browser's local time, adding a spurious +5:30 on top of
|
|
* digits that were already correct IST.
|
|
*
|
|
* Stripping any trailing zone marker before parsing makes both cases — truly
|
|
* naive, or naive-with-false-Z — render and bucket identically as the raw
|
|
* wall-clock digits. Every page that displays or buckets a Doormile timestamp
|
|
* must go through here, or two pages will disagree about which day a row is on.
|
|
*/
|
|
export const parseDoormileTimestamp = (raw) => {
|
|
if (!raw) return dayjs(null);
|
|
const stripped = String(raw).replace(/(Z|[+-]\d{2}:?\d{2})$/, '');
|
|
return dayjs(stripped);
|
|
};
|
|
|
|
/** `raw` rendered in `format`, or `fallback` when the timestamp is unusable. */
|
|
export const formatDoormileTimestamp = (raw, format = 'DD MMM YYYY, hh:mm A', fallback = '—') => {
|
|
const parsed = parseDoormileTimestamp(raw);
|
|
return parsed.isValid() ? parsed.format(format) : fallback;
|
|
};
|
|
|
|
/** The calendar day (`YYYY-MM-DD`) a Doormile timestamp falls on. */
|
|
export const doormileDay = (raw) => {
|
|
const parsed = parseDoormileTimestamp(raw);
|
|
return parsed.isValid() ? parsed.format('YYYY-MM-DD') : undefined;
|
|
};
|