Created
August 15, 2020 16:33
-
-
Save scorredoira/cf7caa1b0f347a0d33531f67e3b757e1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace S { | |
let formats: any = {} | |
let systemLocation = Intl.DateTimeFormat().resolvedOptions().timeZone | |
export class Date { | |
private _date: globalThis.Date | |
private _location: string | |
private _locationOffset: number | |
constructor(d?: number, location?: string) { | |
this._date = d ? new globalThis.Date(d) : new globalThis.Date() | |
if (location) { | |
this._location = location | |
this._locationOffset = this.getTimezoneOffset(this, location) | |
} else { | |
this._location = systemLocation | |
this._locationOffset = this._date.getTimezoneOffset() | |
} | |
} | |
get location() { | |
return this._location | |
} | |
get locationOffset() { | |
return this._locationOffset | |
} | |
getTime() { | |
return this._date.getTime() | |
} | |
getHours() { | |
return this._date.getHours() | |
} | |
getMinutes() { | |
return this._date.getMinutes() | |
} | |
getSeconds() { | |
return this._date.getSeconds() | |
} | |
getMilliseconds() { | |
return this._date.getMilliseconds() | |
} | |
getDate() { | |
return this._date.getDate() | |
} | |
getDay() { | |
return this._date.getDay() | |
} | |
getMonth() { | |
return this._date.getMonth() | |
} | |
getFullYear() { | |
return this._date.getFullYear() | |
} | |
isSameDay(d: Date) { | |
return this.getFullYear() === d.getFullYear() | |
&& this.getMonth() === d.getMonth() | |
&& this.getDate() === d.getDate() | |
} | |
addMilliseconds(millis: number) { | |
return new Date(this.getTime() + millis, this._location) | |
} | |
addMinutes(minutes: number) { | |
return new Date(this.getTime() + minutes * 60000, this._location) | |
} | |
addHours(hours: number) { | |
return new Date(this.getTime() + hours * 60 * 60000, this._location) | |
} | |
addDays(days: number) { | |
var d = new Date(this.getTime(), this._location) | |
d._date.setDate(d._date.getDate() + days) | |
return d; | |
} | |
setDay(day: number) { | |
var d = new Date(this.getTime(), this._location) | |
d._date.setDate(day) | |
return d | |
} | |
in(location: string) { | |
let utc = this.toUTC() | |
let offset = this.getTimezoneOffset(this, location) | |
let dl = new Date(utc - offset * 60 * 1000, location) | |
return dl | |
} | |
static newDate(year?: number, month?: number, day?: number, hour?: number, min?: number, secs?: number, millis?: number, location?: string) { | |
let d = new globalThis.Date(year || 1, month || 1, day || 1, hour || 0, min || 0, secs || 0, millis || 0) | |
return new Date(d.getTime(), location) | |
} | |
startOfDay() { | |
return Date.newDate(this.getFullYear(), this.getMonth(), this.getDate(), null, null, null, null, this._location) | |
} | |
endOfDay() { | |
let d = Date.newDate(this.getFullYear(), this.getMonth(), this.getDate(), null, null, null, null, this._location) | |
d._date.setDate(d._date.getDate() + 1) | |
return new Date(d.getTime() - 1, this.location) | |
} | |
copy() { | |
return new Date(this.getTime(), this.location) | |
} | |
toUTC() { | |
return this._date.getTime() + this._locationOffset * 60 * 1000 | |
} | |
private getTimezoneOffset(d: Date, location: string) { | |
const utcStr = this.formatTimezone("UTC", d) | |
const localStr = this.formatTimezone(location, d) | |
let localISO = this.parseISOLocal(localStr) | |
let utcISO = this.parseISOLocal(utcStr) | |
let offset = utcISO.getTime() - localISO.getTime() | |
return offset / 60 / 1000 | |
} | |
private formatTimezone(timeZone: string, d: Date) { | |
let f = this.getFormat(timeZone) | |
let s = f.format(d._date) | |
// handle Chrome80 bug: goes from 23:59:59 to 24:00:00 | |
var parts = s.splitEx(/\D/) | |
let hour = parseInt(parts[3], 10) | |
if (hour >= 24) { | |
hour -= 24 | |
s = parts[0] + "/" + parts[1] + "/" + parts[2] + ", " + hour + ":" + parts[4] + ":" + parts[5] | |
} | |
return s | |
} | |
toString() { | |
return this.format("yyyy/MM/dd HH:mm") + " (" + this._location + ")" | |
} | |
format(pattern: string) { | |
let parts: any[] = [] | |
for (let i = 0, l = pattern.length - 1; i <= l; i++) { | |
let c = pattern[i] | |
switch (c) { | |
case "d": | |
if (i < l && pattern[i + 1] == "d") { | |
if (i < l - 1 && pattern[i + 2] == "d") { | |
parts.push({ token: "ddd" }) | |
i += 2 | |
continue | |
} | |
parts.push({ token: "dd" }) | |
i++ | |
continue | |
} | |
parts.push({ token: "d" }) | |
continue | |
case "M": | |
if (i < l && pattern[i + 1] == "M") { | |
parts.push({ token: "MM" }) | |
i++ | |
continue | |
} | |
parts.push({ token: "M" }) | |
continue | |
case "y": | |
if (i < l && pattern[i + 1] == "y") { | |
if (i < l - 2 && pattern[i + 2] == "y" && pattern[i + 3] == "y") { | |
parts.push({ token: "yyyy" }) | |
i += 3 | |
continue | |
} | |
parts.push({ token: "yy" }) | |
i++ | |
continue | |
} | |
parts.push(c) | |
break | |
case "h": | |
if (i < l && pattern[i + 1] == "h") { | |
parts.push({ token: "hh" }) | |
i++ | |
continue | |
} | |
parts.push({ token: "h" }) | |
continue | |
case "H": | |
if (i < l && pattern[i + 1] == "H") { | |
parts.push({ token: "HH" }) | |
i++ | |
continue | |
} | |
parts.push({ token: "H" }) | |
continue | |
case "m": | |
if (i < l && pattern[i + 1] == "m") { | |
if (i < l - 1 && pattern[i + 2] == "m") { | |
parts.push({ token: "mmm" }) | |
i += 2 | |
continue | |
} | |
parts.push({ token: "mm" }) | |
i++ | |
continue | |
} | |
parts.push({ token: "m" }) | |
continue | |
case "s": | |
if (i < l && pattern[i + 1] == "s") { | |
parts.push({ token: "ss" }) | |
i++ | |
continue | |
} | |
parts.push({ token: "s" }) | |
continue | |
case "z": | |
if (i < l && pattern[i + 1] == "z") { | |
parts.push({ token: "zz" }) | |
i++ | |
continue | |
} | |
parts.push(c) | |
continue | |
case "\\": | |
if (i < l) { | |
parts.push(pattern[i + 1]) | |
i++ | |
continue | |
} | |
break | |
default: | |
parts.push(c) | |
break | |
} | |
} | |
let result = [] | |
for (let part of parts) { | |
switch (part.token) { | |
case "d": | |
result.push(this.getDate()) | |
break | |
case "dd": | |
result.push(padLeft(String(this.getDate()), "0", 2)) | |
break | |
case "ddd": | |
let day = weekDays[this.getDay()] | |
result.push(day) | |
break | |
case "M": | |
result.push(this.getMonth()) | |
break | |
case "MM": | |
result.push(padLeft(String(this.getMonth()), "0", 2)) | |
break | |
case "mmm": | |
let month = monthNames[this.getMonth()] | |
result.push(month) | |
break | |
case "yy": | |
result.push(padLeft(String(this.getFullYear() - 2000), "0", 2)) | |
break | |
case "yyyy": | |
result.push(this.getFullYear()) | |
break | |
case "h": | |
result.push(this.getHours()) | |
break | |
case "hh": | |
let hours = this.getHours() | |
if (hours > 12) { | |
hours -= 12 | |
} | |
result.push(padLeft(String(hours), "0", 2)) | |
break | |
case "HH": | |
result.push(padLeft(String(this.getHours()), "0", 2)) | |
break | |
case "m": | |
result.push(this.getMinutes()) | |
break | |
case "mm": | |
result.push(padLeft(String(this.getMinutes()), "0", 2)) | |
break | |
case "s": | |
result.push(this.getSeconds()) | |
break | |
case "ss": | |
result.push(padLeft(String(this.getSeconds()), "0", 2)) | |
break | |
case "zz": | |
result.push(this._location) | |
break | |
case undefined: | |
result.push(part) | |
break | |
default: | |
result.push(part.token) | |
break | |
} | |
} | |
return result.join("") | |
} | |
private getFormat(timeZone: string) { | |
let f = formats[timeZone] | |
if (!f) { | |
// 09/18/2019, 13:49:27 | |
f = new Intl.DateTimeFormat('en-US', { | |
year: 'numeric', | |
month: '2-digit', | |
day: '2-digit', | |
hour: '2-digit', | |
minute: '2-digit', | |
second: '2-digit', | |
hour12: false, | |
timeZone | |
}) | |
formats[timeZone] = f | |
} | |
return f | |
} | |
private parseISOLocal(s: string) { | |
var parts = s.splitEx(/\D/) | |
if (parts.length != 6) { | |
throw "Invalid ISO date" | |
} | |
let month = Number(parts[0]) - 1 | |
let day = Number(parts[1]) | |
let year = Number(parts[2]) | |
let hour = Number(parts[3]) | |
let min = Number(parts[4]) | |
let sec = Number(parts[5]) | |
return new globalThis.Date(year, month, day, hour, min, sec, 0) | |
} | |
} | |
export var weekDays = ["@@Sunday", "@@Monday", "@@Tuesday", "@@Wednesday", "@@Thursday", "@@Friday", "@@Saturday"] | |
export function getWeekdayName(dayOfWeek: number) { | |
return weekDays[dayOfWeek] | |
} | |
let monthNames = [ | |
"@@January", | |
"@@February", | |
"@@March", | |
"@@April", | |
"@@May", | |
"@@Jun", | |
"@@Julay", | |
"@@August", | |
"@@Sepember", | |
"@@October", | |
"@@November", | |
"@@December", | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment