webservices/node_modules/cronosjs/dist-src/date.js

130 lines
6 KiB
JavaScript

export class CronosDate {
constructor(year, month = 1, day = 1, hour = 0, minute = 0, second = 0) {
this.year = year;
this.month = month;
this.day = day;
this.hour = hour;
this.minute = minute;
this.second = second;
}
static fromDate(date, timezone) {
if (!timezone) {
return new CronosDate(date.getFullYear(), date.getMonth() + 1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());
}
return timezone['nativeDateToCronosDate'](date);
}
toDate(timezone) {
if (!timezone) {
return new Date(this.year, this.month - 1, this.day, this.hour, this.minute, this.second);
}
return timezone['cronosDateToNativeDate'](this);
}
static fromUTCTimestamp(timestamp) {
const date = new Date(timestamp);
return new CronosDate(date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
}
toUTCTimestamp() {
return Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second);
}
copyWith({ year = this.year, month = this.month, day = this.day, hour = this.hour, minute = this.minute, second = this.second } = {}) {
return new CronosDate(year, month, day, hour, minute, second);
}
}
// Adapted from Intl.DateTimeFormat timezone handling in https://github.com/moment/luxon
const ZoneCache = new Map();
export class CronosTimezone {
constructor(IANANameOrOffset) {
if (typeof IANANameOrOffset === 'number') {
if (IANANameOrOffset > 840 || IANANameOrOffset < -840)
throw new Error('Invalid offset');
this.fixedOffset = IANANameOrOffset;
return this;
}
const offsetMatch = IANANameOrOffset.match(/^([+-]?)(0[1-9]|1[0-4])(?::?([0-5][0-9]))?$/);
if (offsetMatch) {
this.fixedOffset = (offsetMatch[1] === '-' ? -1 : 1) * ((parseInt(offsetMatch[2], 10) * 60) + (parseInt(offsetMatch[3], 10) || 0));
return this;
}
if (ZoneCache.has(IANANameOrOffset)) {
return ZoneCache.get(IANANameOrOffset);
}
try {
this.dateTimeFormat = new Intl.DateTimeFormat("en-US", {
hour12: false,
timeZone: IANANameOrOffset,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
});
}
catch (err) {
throw new Error('Invalid IANA name or offset');
}
this.zoneName = IANANameOrOffset;
const currentYear = new Date().getUTCFullYear();
this.winterOffset = this.offset(Date.UTC(currentYear, 0, 1));
this.summerOffset = this.offset(Date.UTC(currentYear, 5, 1));
ZoneCache.set(IANANameOrOffset, this);
}
toString() {
if (this.fixedOffset) {
const absOffset = Math.abs(this.fixedOffset);
return [
this.fixedOffset < 0 ? '-' : '+',
Math.floor(absOffset / 60).toString().padStart(2, '0'),
(absOffset % 60).toString().padStart(2, '0')
].join('');
}
return this.zoneName;
}
offset(ts) {
if (!this.dateTimeFormat)
return this.fixedOffset || 0;
const date = new Date(ts);
const { year, month, day, hour, minute, second } = this.nativeDateToCronosDate(date);
const asUTC = Date.UTC(year, month - 1, day, hour, minute, second), asTS = ts - (ts % 1000);
return (asUTC - asTS) / 60000;
}
nativeDateToCronosDate(date) {
if (!this.dateTimeFormat) {
return CronosDate['fromUTCTimestamp'](date.getTime() + (this.fixedOffset || 0) * 60000);
}
return this.dateTimeFormat['formatToParts']
? partsOffset(this.dateTimeFormat, date)
: hackyOffset(this.dateTimeFormat, date);
}
cronosDateToNativeDate(date) {
if (!this.dateTimeFormat) {
return new Date(date['toUTCTimestamp']() - (this.fixedOffset || 0) * 60000);
}
const provisionalOffset = ((date.month > 3 || date.month < 11) ? this.summerOffset : this.winterOffset) || 0;
const UTCTimestamp = date['toUTCTimestamp']();
// Find the right offset a given local time.
// Our UTC time is just a guess because our offset is just a guess
let utcGuess = UTCTimestamp - provisionalOffset * 60000;
// Test whether the zone matches the offset for this ts
const o2 = this.offset(utcGuess);
// If so, offset didn't change and we're done
if (provisionalOffset === o2)
return new Date(utcGuess);
// If not, change the ts by the difference in the offset
utcGuess -= (o2 - provisionalOffset) * 60000;
// If that gives us the local time we want, we're done
const o3 = this.offset(utcGuess);
if (o2 === o3)
return new Date(utcGuess);
// If it's different, we're in a hole time. The offset has changed, but the we don't adjust the time
return new Date(UTCTimestamp - Math.min(o2, o3) * 60000);
}
}
function hackyOffset(dtf, date) {
const formatted = dtf.format(date).replace(/\u200E/g, ""), parsed = formatted.match(/(\d+)\/(\d+)\/(\d+),? (\d+):(\d+):(\d+)/), [, month, day, year, hour, minute, second] = (parsed !== null && parsed !== void 0 ? parsed : []).map(n => parseInt(n, 10));
return new CronosDate(year, month, day, hour % 24, minute, second);
}
function partsOffset(dtf, date) {
const formatted = dtf.formatToParts(date);
return new CronosDate(parseInt(formatted[4].value, 10), parseInt(formatted[0].value, 10), parseInt(formatted[2].value, 10), parseInt(formatted[6].value, 10) % 24, parseInt(formatted[8].value, 10), parseInt(formatted[10].value, 10));
}