UNPKG

5.59 kBJavaScriptView Raw
1import { MIN, MS } from '../../constant';
2var typeToPos = {
3 year: 0,
4 month: 1,
5 day: 2,
6 hour: 3,
7 minute: 4,
8 second: 5
9}; // Cache time-zone lookups from Intl.DateTimeFormat,
10// as it is a *very* slow method.
11
12var dtfCache = {};
13
14var getDateTimeFormat = function getDateTimeFormat(timezone, options) {
15 if (options === void 0) {
16 options = {};
17 }
18
19 var timeZoneName = options.timeZoneName || 'short';
20 var key = timezone + "|" + timeZoneName;
21 var dtf = dtfCache[key];
22
23 if (!dtf) {
24 dtf = new Intl.DateTimeFormat('en-US', {
25 hour12: false,
26 timeZone: timezone,
27 year: 'numeric',
28 month: '2-digit',
29 day: '2-digit',
30 hour: '2-digit',
31 minute: '2-digit',
32 second: '2-digit',
33 timeZoneName: timeZoneName
34 });
35 dtfCache[key] = dtf;
36 }
37
38 return dtf;
39};
40
41export default (function (o, c, d) {
42 var defaultTimezone;
43
44 var makeFormatParts = function makeFormatParts(timestamp, timezone, options) {
45 if (options === void 0) {
46 options = {};
47 }
48
49 var date = new Date(timestamp);
50 var dtf = getDateTimeFormat(timezone, options);
51 return dtf.formatToParts(date);
52 };
53
54 var tzOffset = function tzOffset(timestamp, timezone) {
55 var formatResult = makeFormatParts(timestamp, timezone);
56 var filled = [];
57
58 for (var i = 0; i < formatResult.length; i += 1) {
59 var _formatResult$i = formatResult[i],
60 type = _formatResult$i.type,
61 value = _formatResult$i.value;
62 var pos = typeToPos[type];
63
64 if (pos >= 0) {
65 filled[pos] = parseInt(value, 10);
66 }
67 }
68
69 var hour = filled[3]; // Workaround for the same behavior in different node version
70 // https://github.com/nodejs/node/issues/33027
71
72 /* istanbul ignore next */
73
74 var fixedHour = hour === 24 ? 0 : hour;
75 var utcString = filled[0] + "-" + filled[1] + "-" + filled[2] + " " + fixedHour + ":" + filled[4] + ":" + filled[5] + ":000";
76 var utcTs = d.utc(utcString).valueOf();
77 var asTS = +timestamp;
78 var over = asTS % 1000;
79 asTS -= over;
80 return (utcTs - asTS) / (60 * 1000);
81 }; // find the right offset a given local time. The o input is our guess, which determines which
82 // offset we'll pick in ambiguous cases (e.g. there are two 3 AMs b/c Fallback DST)
83 // https://github.com/moment/luxon/blob/master/src/datetime.js#L76
84
85
86 var fixOffset = function fixOffset(localTS, o0, tz) {
87 // Our UTC time is just a guess because our offset is just a guess
88 var utcGuess = localTS - o0 * 60 * 1000; // Test whether the zone matches the offset for this ts
89
90 var o2 = tzOffset(utcGuess, tz); // If so, offset didn't change and we're done
91
92 if (o0 === o2) {
93 return [utcGuess, o0];
94 } // If not, change the ts by the difference in the offset
95
96
97 utcGuess -= (o2 - o0) * 60 * 1000; // If that gives us the local time we want, we're done
98
99 var o3 = tzOffset(utcGuess, tz);
100
101 if (o2 === o3) {
102 return [utcGuess, o2];
103 } // If it's different, we're in a hole time.
104 // The offset has changed, but the we don't adjust the time
105
106
107 return [localTS - Math.min(o2, o3) * 60 * 1000, Math.max(o2, o3)];
108 };
109
110 var proto = c.prototype;
111
112 proto.tz = function (timezone, keepLocalTime) {
113 if (timezone === void 0) {
114 timezone = defaultTimezone;
115 }
116
117 var oldOffset = this.utcOffset();
118 var date = this.toDate();
119 var target = date.toLocaleString('en-US', {
120 timeZone: timezone
121 });
122 var diff = Math.round((date - new Date(target)) / 1000 / 60);
123 var offset = -Math.round(date.getTimezoneOffset() / 15) * 15 - diff;
124 var isUTC = !Number(offset);
125 var ins;
126
127 if (isUTC) {
128 // if utcOffset is 0, turn it to UTC mode
129 ins = this.utcOffset(0, keepLocalTime);
130 } else {
131 ins = d(target, {
132 locale: this.$L
133 }).$set(MS, this.$ms).utcOffset(offset, true);
134
135 if (keepLocalTime) {
136 var newOffset = ins.utcOffset();
137 ins = ins.add(oldOffset - newOffset, MIN);
138 }
139 }
140
141 ins.$x.$timezone = timezone;
142 return ins;
143 };
144
145 proto.offsetName = function (type) {
146 // type: short(default) / long
147 var zone = this.$x.$timezone || d.tz.guess();
148 var result = makeFormatParts(this.valueOf(), zone, {
149 timeZoneName: type
150 }).find(function (m) {
151 return m.type.toLowerCase() === 'timezonename';
152 });
153 return result && result.value;
154 };
155
156 var oldStartOf = proto.startOf;
157
158 proto.startOf = function (units, startOf) {
159 if (!this.$x || !this.$x.$timezone) {
160 return oldStartOf.call(this, units, startOf);
161 }
162
163 var withoutTz = d(this.format('YYYY-MM-DD HH:mm:ss:SSS'), {
164 locale: this.$L
165 });
166 var startOfWithoutTz = oldStartOf.call(withoutTz, units, startOf);
167 return startOfWithoutTz.tz(this.$x.$timezone, true);
168 };
169
170 d.tz = function (input, arg1, arg2) {
171 var parseFormat = arg2 && arg1;
172 var timezone = arg2 || arg1 || defaultTimezone;
173 var previousOffset = tzOffset(+d(), timezone);
174
175 if (typeof input !== 'string') {
176 // timestamp number || js Date || Day.js
177 return d(input).tz(timezone);
178 }
179
180 var localTs = d.utc(input, parseFormat).valueOf();
181
182 var _fixOffset = fixOffset(localTs, previousOffset, timezone),
183 targetTs = _fixOffset[0],
184 targetOffset = _fixOffset[1];
185
186 var ins = d(targetTs).utcOffset(targetOffset);
187 ins.$x.$timezone = timezone;
188 return ins;
189 };
190
191 d.tz.guess = function () {
192 return Intl.DateTimeFormat().resolvedOptions().timeZone;
193 };
194
195 d.tz.setDefault = function (timezone) {
196 defaultTimezone = timezone;
197 };
198});
\No newline at end of file