99 lines
3.0 KiB
JavaScript
99 lines
3.0 KiB
JavaScript
import { TZDateMini } from "./mini.js";
|
|
|
|
/**
|
|
* UTC date class. It maps getters and setters to corresponding UTC methods,
|
|
* forcing all calculations in the UTC time zone.
|
|
*
|
|
* Combined with date-fns, it allows using the class the same way as
|
|
* the original date class.
|
|
*
|
|
* This complete version provides not only getters, setters,
|
|
* and `getTimezoneOffset`, but also the formatter functions, mirroring
|
|
* all original `Date` functionality. Use this version when you need to format
|
|
* a string or in an environment you don't fully control (a library).
|
|
* For a minimal version, see `UTCDateMini`.
|
|
*/
|
|
export class TZDate extends TZDateMini {
|
|
//#region static
|
|
|
|
static tz(tz, ...args) {
|
|
return args.length ? new TZDate(...args, tz) : new TZDate(Date.now(), tz);
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//#region representation
|
|
|
|
toISOString() {
|
|
const [sign, hours, minutes] = this.tzComponents();
|
|
const tz = `${sign}${hours}:${minutes}`;
|
|
return this.internal.toISOString().slice(0, -1) + tz;
|
|
}
|
|
toString() {
|
|
// "Tue Aug 13 2024 07:50:19 GMT+0800 (Singapore Standard Time)";
|
|
return `${this.toDateString()} ${this.toTimeString()}`;
|
|
}
|
|
toDateString() {
|
|
// toUTCString returns RFC 7231 ("Mon, 12 Aug 2024 23:36:08 GMT")
|
|
const [day, date, month, year] = this.internal.toUTCString().split(" ");
|
|
// "Tue Aug 13 2024"
|
|
return `${day?.slice(0, -1) /* Remove "," */} ${month} ${date} ${year}`;
|
|
}
|
|
toTimeString() {
|
|
// toUTCString returns RFC 7231 ("Mon, 12 Aug 2024 23:36:08 GMT")
|
|
const time = this.internal.toUTCString().split(" ")[4];
|
|
const [sign, hours, minutes] = this.tzComponents();
|
|
// "07:42:23 GMT+0800 (Singapore Standard Time)"
|
|
return `${time} GMT${sign}${hours}${minutes} (${tzName(this.timeZone, this)})`;
|
|
}
|
|
toLocaleString(locales, options) {
|
|
return Date.prototype.toLocaleString.call(this, locales, {
|
|
...options,
|
|
timeZone: options?.timeZone || this.timeZone
|
|
});
|
|
}
|
|
toLocaleDateString(locales, options) {
|
|
return Date.prototype.toLocaleDateString.call(this, locales, {
|
|
...options,
|
|
timeZone: options?.timeZone || this.timeZone
|
|
});
|
|
}
|
|
toLocaleTimeString(locales, options) {
|
|
return Date.prototype.toLocaleTimeString.call(this, locales, {
|
|
...options,
|
|
timeZone: options?.timeZone || this.timeZone
|
|
});
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//#region private
|
|
|
|
tzComponents() {
|
|
const offset = this.getTimezoneOffset();
|
|
const sign = offset > 0 ? "-" : "+";
|
|
const hours = String(Math.floor(Math.abs(offset) / 60)).padStart(2, "0");
|
|
const minutes = String(Math.abs(offset) % 60).padStart(2, "0");
|
|
return [sign, hours, minutes];
|
|
}
|
|
|
|
//#endregion
|
|
|
|
withTimeZone(timeZone) {
|
|
return new TZDate(+this, timeZone);
|
|
}
|
|
|
|
//#region date-fns integration
|
|
|
|
[Symbol.for("constructDateFrom")](date) {
|
|
return new TZDate(+new Date(date), this.timeZone);
|
|
}
|
|
|
|
//#endregion
|
|
}
|
|
function tzName(tz, date) {
|
|
return new Intl.DateTimeFormat("en-GB", {
|
|
timeZone: tz,
|
|
timeZoneName: "long"
|
|
}).format(date).slice(12);
|
|
} |