day: 'numeric',
})).toEqual('15. März 2024');
- expect(toAbsoluteLocaleDate('12345-03-15 01:02:03', '', {
- year: 'numeric',
- month: 'short',
- day: 'numeric',
- })).toEqual('Mar 15, 12345');
+ // these cases shouldn't happen
+ expect(toAbsoluteLocaleDate('2024-03-15 01:02:03', '', {})).toEqual('Invalid Date');
+ expect(toAbsoluteLocaleDate('10000-01-01', '', {})).toEqual('Invalid Date');
+
+ // test different timezone
+ const oldTZ = process.env.TZ;
+ process.env.TZ = 'America/New_York';
+ expect(new Date('2024-03-15').toLocaleString()).toEqual('3/14/2024, 8:00:00 PM');
+ expect(toAbsoluteLocaleDate('2024-03-15')).toEqual('3/15/2024, 12:00:00 AM');
+ process.env.TZ = oldTZ;
});
-export function toAbsoluteLocaleDate(date: string, lang: string, opts: Intl.DateTimeFormatOptions) {
- return new Date(date).toLocaleString(lang || [], opts);
+export function toAbsoluteLocaleDate(date: string, lang?: string, opts?: Intl.DateTimeFormatOptions) {
+ // only use the date part, it is guaranteed to be in ISO format (YYYY-MM-DDTHH:mm:ss.sssZ) or (YYYY-MM-DD)
+ // if there is an "Invalid Date" error, there must be something wrong in code and should be fixed.
+ // TODO: there is a root problem in backend code: the date "YYYY-MM-DD" is passed to backend without timezone (eg: deadline),
+ // then backend parses it in server's timezone and stores the parsed timestamp into database.
+ // If the user's timezone is different from the server's, the date might be displayed in the wrong day.
+ const dateSep = date.indexOf('T');
+ date = dateSep === -1 ? date : date.substring(0, dateSep);
+ return new Date(`${date}T00:00:00`).toLocaleString(lang || [], opts);
}
window.customElements.define('absolute-date', class extends HTMLElement {
const lang = this.closest('[lang]')?.getAttribute('lang') ||
this.ownerDocument.documentElement.getAttribute('lang') || '';
- // only use the date part, it is guaranteed to be in ISO format (YYYY-MM-DDTHH:mm:ss.sssZ)
- let date = this.getAttribute('date');
- let dateSep = date.indexOf('T');
- dateSep = dateSep === -1 ? date.indexOf(' ') : dateSep;
- date = dateSep === -1 ? date : date.substring(0, dateSep);
-
if (!this.shadowRoot) this.attachShadow({mode: 'open'});
- this.shadowRoot.textContent = toAbsoluteLocaleDate(date, lang, opt);
+ this.shadowRoot.textContent = toAbsoluteLocaleDate(this.getAttribute('date'), lang, opt);
};
attributeChangedCallback(_name, oldValue, newValue) {