1 | import dayjs from "dayjs";
|
2 | import { Weekday, Month } from "./types.js";
|
3 | export const TIMEZONE_ABBR_MAP = {
|
4 | ACDT: 630,
|
5 | ACST: 570,
|
6 | ADT: -180,
|
7 | AEDT: 660,
|
8 | AEST: 600,
|
9 | AFT: 270,
|
10 | AKDT: -480,
|
11 | AKST: -540,
|
12 | ALMT: 360,
|
13 | AMST: -180,
|
14 | AMT: -240,
|
15 | ANAST: 720,
|
16 | ANAT: 720,
|
17 | AQTT: 300,
|
18 | ART: -180,
|
19 | AST: -240,
|
20 | AWDT: 540,
|
21 | AWST: 480,
|
22 | AZOST: 0,
|
23 | AZOT: -60,
|
24 | AZST: 300,
|
25 | AZT: 240,
|
26 | BNT: 480,
|
27 | BOT: -240,
|
28 | BRST: -120,
|
29 | BRT: -180,
|
30 | BST: 60,
|
31 | BTT: 360,
|
32 | CAST: 480,
|
33 | CAT: 120,
|
34 | CCT: 390,
|
35 | CDT: -300,
|
36 | CEST: 120,
|
37 | CET: {
|
38 | timezoneOffsetDuringDst: 2 * 60,
|
39 | timezoneOffsetNonDst: 60,
|
40 | dstStart: (year) => getLastWeekdayOfMonth(year, Month.MARCH, Weekday.SUNDAY, 2),
|
41 | dstEnd: (year) => getLastWeekdayOfMonth(year, Month.OCTOBER, Weekday.SUNDAY, 3),
|
42 | },
|
43 | CHADT: 825,
|
44 | CHAST: 765,
|
45 | CKT: -600,
|
46 | CLST: -180,
|
47 | CLT: -240,
|
48 | COT: -300,
|
49 | CST: -360,
|
50 | CT: {
|
51 | timezoneOffsetDuringDst: -5 * 60,
|
52 | timezoneOffsetNonDst: -6 * 60,
|
53 | dstStart: (year) => getNthWeekdayOfMonth(year, Month.MARCH, Weekday.SUNDAY, 2, 2),
|
54 | dstEnd: (year) => getNthWeekdayOfMonth(year, Month.NOVEMBER, Weekday.SUNDAY, 1, 2),
|
55 | },
|
56 | CVT: -60,
|
57 | CXT: 420,
|
58 | ChST: 600,
|
59 | DAVT: 420,
|
60 | EASST: -300,
|
61 | EAST: -360,
|
62 | EAT: 180,
|
63 | ECT: -300,
|
64 | EDT: -240,
|
65 | EEST: 180,
|
66 | EET: 120,
|
67 | EGST: 0,
|
68 | EGT: -60,
|
69 | EST: -300,
|
70 | ET: {
|
71 | timezoneOffsetDuringDst: -4 * 60,
|
72 | timezoneOffsetNonDst: -5 * 60,
|
73 | dstStart: (year) => getNthWeekdayOfMonth(year, Month.MARCH, Weekday.SUNDAY, 2, 2),
|
74 | dstEnd: (year) => getNthWeekdayOfMonth(year, Month.NOVEMBER, Weekday.SUNDAY, 1, 2),
|
75 | },
|
76 | FJST: 780,
|
77 | FJT: 720,
|
78 | FKST: -180,
|
79 | FKT: -240,
|
80 | FNT: -120,
|
81 | GALT: -360,
|
82 | GAMT: -540,
|
83 | GET: 240,
|
84 | GFT: -180,
|
85 | GILT: 720,
|
86 | GMT: 0,
|
87 | GST: 240,
|
88 | GYT: -240,
|
89 | HAA: -180,
|
90 | HAC: -300,
|
91 | HADT: -540,
|
92 | HAE: -240,
|
93 | HAP: -420,
|
94 | HAR: -360,
|
95 | HAST: -600,
|
96 | HAT: -90,
|
97 | HAY: -480,
|
98 | HKT: 480,
|
99 | HLV: -210,
|
100 | HNA: -240,
|
101 | HNC: -360,
|
102 | HNE: -300,
|
103 | HNP: -480,
|
104 | HNR: -420,
|
105 | HNT: -150,
|
106 | HNY: -540,
|
107 | HOVT: 420,
|
108 | ICT: 420,
|
109 | IDT: 180,
|
110 | IOT: 360,
|
111 | IRDT: 270,
|
112 | IRKST: 540,
|
113 | IRKT: 540,
|
114 | IRST: 210,
|
115 | IST: 330,
|
116 | JST: 540,
|
117 | KGT: 360,
|
118 | KRAST: 480,
|
119 | KRAT: 480,
|
120 | KST: 540,
|
121 | KUYT: 240,
|
122 | LHDT: 660,
|
123 | LHST: 630,
|
124 | LINT: 840,
|
125 | MAGST: 720,
|
126 | MAGT: 720,
|
127 | MART: -510,
|
128 | MAWT: 300,
|
129 | MDT: -360,
|
130 | MESZ: 120,
|
131 | MEZ: 60,
|
132 | MHT: 720,
|
133 | MMT: 390,
|
134 | MSD: 240,
|
135 | MSK: 180,
|
136 | MST: -420,
|
137 | MT: {
|
138 | timezoneOffsetDuringDst: -6 * 60,
|
139 | timezoneOffsetNonDst: -7 * 60,
|
140 | dstStart: (year) => getNthWeekdayOfMonth(year, Month.MARCH, Weekday.SUNDAY, 2, 2),
|
141 | dstEnd: (year) => getNthWeekdayOfMonth(year, Month.NOVEMBER, Weekday.SUNDAY, 1, 2),
|
142 | },
|
143 | MUT: 240,
|
144 | MVT: 300,
|
145 | MYT: 480,
|
146 | NCT: 660,
|
147 | NDT: -90,
|
148 | NFT: 690,
|
149 | NOVST: 420,
|
150 | NOVT: 360,
|
151 | NPT: 345,
|
152 | NST: -150,
|
153 | NUT: -660,
|
154 | NZDT: 780,
|
155 | NZST: 720,
|
156 | OMSST: 420,
|
157 | OMST: 420,
|
158 | PDT: -420,
|
159 | PET: -300,
|
160 | PETST: 720,
|
161 | PETT: 720,
|
162 | PGT: 600,
|
163 | PHOT: 780,
|
164 | PHT: 480,
|
165 | PKT: 300,
|
166 | PMDT: -120,
|
167 | PMST: -180,
|
168 | PONT: 660,
|
169 | PST: -480,
|
170 | PT: {
|
171 | timezoneOffsetDuringDst: -7 * 60,
|
172 | timezoneOffsetNonDst: -8 * 60,
|
173 | dstStart: (year) => getNthWeekdayOfMonth(year, Month.MARCH, Weekday.SUNDAY, 2, 2),
|
174 | dstEnd: (year) => getNthWeekdayOfMonth(year, Month.NOVEMBER, Weekday.SUNDAY, 1, 2),
|
175 | },
|
176 | PWT: 540,
|
177 | PYST: -180,
|
178 | PYT: -240,
|
179 | RET: 240,
|
180 | SAMT: 240,
|
181 | SAST: 120,
|
182 | SBT: 660,
|
183 | SCT: 240,
|
184 | SGT: 480,
|
185 | SRT: -180,
|
186 | SST: -660,
|
187 | TAHT: -600,
|
188 | TFT: 300,
|
189 | TJT: 300,
|
190 | TKT: 780,
|
191 | TLT: 540,
|
192 | TMT: 300,
|
193 | TVT: 720,
|
194 | ULAT: 480,
|
195 | UTC: 0,
|
196 | UYST: -120,
|
197 | UYT: -180,
|
198 | UZT: 300,
|
199 | VET: -210,
|
200 | VLAST: 660,
|
201 | VLAT: 660,
|
202 | VUT: 660,
|
203 | WAST: 120,
|
204 | WAT: 60,
|
205 | WEST: 60,
|
206 | WESZ: 60,
|
207 | WET: 0,
|
208 | WEZ: 0,
|
209 | WFT: 720,
|
210 | WGST: -120,
|
211 | WGT: -180,
|
212 | WIB: 420,
|
213 | WIT: 540,
|
214 | WITA: 480,
|
215 | WST: 780,
|
216 | WT: 0,
|
217 | YAKST: 600,
|
218 | YAKT: 600,
|
219 | YAPT: 600,
|
220 | YEKST: 360,
|
221 | YEKT: 360,
|
222 | };
|
223 | export function getNthWeekdayOfMonth(year, month, weekday, n, hour = 0) {
|
224 | let dayOfMonth = 0;
|
225 | let i = 0;
|
226 | while (i < n) {
|
227 | dayOfMonth++;
|
228 | const date = new Date(year, month - 1, dayOfMonth);
|
229 | if (date.getDay() === weekday)
|
230 | i++;
|
231 | }
|
232 | return new Date(year, month - 1, dayOfMonth, hour);
|
233 | }
|
234 | export function getLastWeekdayOfMonth(year, month, weekday, hour = 0) {
|
235 | const oneIndexedWeekday = weekday === 0 ? 7 : weekday;
|
236 | const date = new Date(year, month - 1 + 1, 1, 12);
|
237 | const firstWeekdayNextMonth = date.getDay() === 0 ? 7 : date.getDay();
|
238 | let dayDiff;
|
239 | if (firstWeekdayNextMonth === oneIndexedWeekday)
|
240 | dayDiff = 7;
|
241 | else if (firstWeekdayNextMonth < oneIndexedWeekday)
|
242 | dayDiff = 7 + firstWeekdayNextMonth - oneIndexedWeekday;
|
243 | else
|
244 | dayDiff = firstWeekdayNextMonth - oneIndexedWeekday;
|
245 | date.setDate(date.getDate() - dayDiff);
|
246 | return new Date(year, month - 1, date.getDate(), hour);
|
247 | }
|
248 | export function toTimezoneOffset(timezoneInput, date, timezoneOverrides = {}) {
|
249 | if (timezoneInput == null) {
|
250 | return null;
|
251 | }
|
252 | if (typeof timezoneInput === "number") {
|
253 | return timezoneInput;
|
254 | }
|
255 | const matchedTimezone = timezoneOverrides[timezoneInput] ?? TIMEZONE_ABBR_MAP[timezoneInput];
|
256 | if (matchedTimezone == null) {
|
257 | return null;
|
258 | }
|
259 | if (typeof matchedTimezone == "number") {
|
260 | return matchedTimezone;
|
261 | }
|
262 | if (date == null) {
|
263 | return null;
|
264 | }
|
265 | if (dayjs(date).isAfter(matchedTimezone.dstStart(date.getFullYear())) &&
|
266 | !dayjs(date).isAfter(matchedTimezone.dstEnd(date.getFullYear()))) {
|
267 | return matchedTimezone.timezoneOffsetDuringDst;
|
268 | }
|
269 | return matchedTimezone.timezoneOffsetNonDst;
|
270 | }
|
271 |
|
\ | No newline at end of file |