liudong
2023-05-29 340f156319b863525e50e900c58e59b86ecb3d5e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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));
}