moment-timezone-rails 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,605 @@
1
+ //! moment-timezone.js
2
+ //! version : 0.5.14
3
+ //! Copyright (c) JS Foundation and other contributors
4
+ //! license : MIT
5
+ //! github.com/moment/moment-timezone
6
+
7
+ (function (root, factory) {
8
+ "use strict";
9
+
10
+ /*global define*/
11
+ if (typeof define === 'function' && define.amd) {
12
+ define(['moment'], factory); // AMD
13
+ } else if (typeof module === 'object' && module.exports) {
14
+ module.exports = factory(require('moment')); // Node
15
+ } else {
16
+ factory(root.moment); // Browser
17
+ }
18
+ }(this, function (moment) {
19
+ "use strict";
20
+
21
+ // Do not load moment-timezone a second time.
22
+ // if (moment.tz !== undefined) {
23
+ // logError('Moment Timezone ' + moment.tz.version + ' was already loaded ' + (moment.tz.dataVersion ? 'with data from ' : 'without any data') + moment.tz.dataVersion);
24
+ // return moment;
25
+ // }
26
+
27
+ var VERSION = "0.5.14",
28
+ zones = {},
29
+ links = {},
30
+ names = {},
31
+ guesses = {},
32
+ cachedGuess,
33
+
34
+ momentVersion = moment.version.split('.'),
35
+ major = +momentVersion[0],
36
+ minor = +momentVersion[1];
37
+
38
+ // Moment.js version check
39
+ if (major < 2 || (major === 2 && minor < 6)) {
40
+ logError('Moment Timezone requires Moment.js >= 2.6.0. You are using Moment.js ' + moment.version + '. See momentjs.com');
41
+ }
42
+
43
+ /************************************
44
+ Unpacking
45
+ ************************************/
46
+
47
+ function charCodeToInt(charCode) {
48
+ if (charCode > 96) {
49
+ return charCode - 87;
50
+ } else if (charCode > 64) {
51
+ return charCode - 29;
52
+ }
53
+ return charCode - 48;
54
+ }
55
+
56
+ function unpackBase60(string) {
57
+ var i = 0,
58
+ parts = string.split('.'),
59
+ whole = parts[0],
60
+ fractional = parts[1] || '',
61
+ multiplier = 1,
62
+ num,
63
+ out = 0,
64
+ sign = 1;
65
+
66
+ // handle negative numbers
67
+ if (string.charCodeAt(0) === 45) {
68
+ i = 1;
69
+ sign = -1;
70
+ }
71
+
72
+ // handle digits before the decimal
73
+ for (i; i < whole.length; i++) {
74
+ num = charCodeToInt(whole.charCodeAt(i));
75
+ out = 60 * out + num;
76
+ }
77
+
78
+ // handle digits after the decimal
79
+ for (i = 0; i < fractional.length; i++) {
80
+ multiplier = multiplier / 60;
81
+ num = charCodeToInt(fractional.charCodeAt(i));
82
+ out += num * multiplier;
83
+ }
84
+
85
+ return out * sign;
86
+ }
87
+
88
+ function arrayToInt (array) {
89
+ for (var i = 0; i < array.length; i++) {
90
+ array[i] = unpackBase60(array[i]);
91
+ }
92
+ }
93
+
94
+ function intToUntil (array, length) {
95
+ for (var i = 0; i < length; i++) {
96
+ array[i] = Math.round((array[i - 1] || 0) + (array[i] * 60000)); // minutes to milliseconds
97
+ }
98
+
99
+ array[length - 1] = Infinity;
100
+ }
101
+
102
+ function mapIndices (source, indices) {
103
+ var out = [], i;
104
+
105
+ for (i = 0; i < indices.length; i++) {
106
+ out[i] = source[indices[i]];
107
+ }
108
+
109
+ return out;
110
+ }
111
+
112
+ function unpack (string) {
113
+ var data = string.split('|'),
114
+ offsets = data[2].split(' '),
115
+ indices = data[3].split(''),
116
+ untils = data[4].split(' ');
117
+
118
+ arrayToInt(offsets);
119
+ arrayToInt(indices);
120
+ arrayToInt(untils);
121
+
122
+ intToUntil(untils, indices.length);
123
+
124
+ return {
125
+ name : data[0],
126
+ abbrs : mapIndices(data[1].split(' '), indices),
127
+ offsets : mapIndices(offsets, indices),
128
+ untils : untils,
129
+ population : data[5] | 0
130
+ };
131
+ }
132
+
133
+ /************************************
134
+ Zone object
135
+ ************************************/
136
+
137
+ function Zone (packedString) {
138
+ if (packedString) {
139
+ this._set(unpack(packedString));
140
+ }
141
+ }
142
+
143
+ Zone.prototype = {
144
+ _set : function (unpacked) {
145
+ this.name = unpacked.name;
146
+ this.abbrs = unpacked.abbrs;
147
+ this.untils = unpacked.untils;
148
+ this.offsets = unpacked.offsets;
149
+ this.population = unpacked.population;
150
+ },
151
+
152
+ _index : function (timestamp) {
153
+ var target = +timestamp,
154
+ untils = this.untils,
155
+ i;
156
+
157
+ for (i = 0; i < untils.length; i++) {
158
+ if (target < untils[i]) {
159
+ return i;
160
+ }
161
+ }
162
+ },
163
+
164
+ parse : function (timestamp) {
165
+ var target = +timestamp,
166
+ offsets = this.offsets,
167
+ untils = this.untils,
168
+ max = untils.length - 1,
169
+ offset, offsetNext, offsetPrev, i;
170
+
171
+ for (i = 0; i < max; i++) {
172
+ offset = offsets[i];
173
+ offsetNext = offsets[i + 1];
174
+ offsetPrev = offsets[i ? i - 1 : i];
175
+
176
+ if (offset < offsetNext && tz.moveAmbiguousForward) {
177
+ offset = offsetNext;
178
+ } else if (offset > offsetPrev && tz.moveInvalidForward) {
179
+ offset = offsetPrev;
180
+ }
181
+
182
+ if (target < untils[i] - (offset * 60000)) {
183
+ return offsets[i];
184
+ }
185
+ }
186
+
187
+ return offsets[max];
188
+ },
189
+
190
+ abbr : function (mom) {
191
+ return this.abbrs[this._index(mom)];
192
+ },
193
+
194
+ offset : function (mom) {
195
+ logError("zone.offset has been deprecated in favor of zone.utcOffset");
196
+ return this.offsets[this._index(mom)];
197
+ },
198
+
199
+ utcOffset : function (mom) {
200
+ return this.offsets[this._index(mom)];
201
+ }
202
+ };
203
+
204
+ /************************************
205
+ Current Timezone
206
+ ************************************/
207
+
208
+ function OffsetAt(at) {
209
+ var timeString = at.toTimeString();
210
+ var abbr = timeString.match(/\([a-z ]+\)/i);
211
+ if (abbr && abbr[0]) {
212
+ // 17:56:31 GMT-0600 (CST)
213
+ // 17:56:31 GMT-0600 (Central Standard Time)
214
+ abbr = abbr[0].match(/[A-Z]/g);
215
+ abbr = abbr ? abbr.join('') : undefined;
216
+ } else {
217
+ // 17:56:31 CST
218
+ // 17:56:31 GMT+0800 (台北標準時間)
219
+ abbr = timeString.match(/[A-Z]{3,5}/g);
220
+ abbr = abbr ? abbr[0] : undefined;
221
+ }
222
+
223
+ if (abbr === 'GMT') {
224
+ abbr = undefined;
225
+ }
226
+
227
+ this.at = +at;
228
+ this.abbr = abbr;
229
+ this.offset = at.getTimezoneOffset();
230
+ }
231
+
232
+ function ZoneScore(zone) {
233
+ this.zone = zone;
234
+ this.offsetScore = 0;
235
+ this.abbrScore = 0;
236
+ }
237
+
238
+ ZoneScore.prototype.scoreOffsetAt = function (offsetAt) {
239
+ this.offsetScore += Math.abs(this.zone.utcOffset(offsetAt.at) - offsetAt.offset);
240
+ if (this.zone.abbr(offsetAt.at).replace(/[^A-Z]/g, '') !== offsetAt.abbr) {
241
+ this.abbrScore++;
242
+ }
243
+ };
244
+
245
+ function findChange(low, high) {
246
+ var mid, diff;
247
+
248
+ while ((diff = ((high.at - low.at) / 12e4 | 0) * 6e4)) {
249
+ mid = new OffsetAt(new Date(low.at + diff));
250
+ if (mid.offset === low.offset) {
251
+ low = mid;
252
+ } else {
253
+ high = mid;
254
+ }
255
+ }
256
+
257
+ return low;
258
+ }
259
+
260
+ function userOffsets() {
261
+ var startYear = new Date().getFullYear() - 2,
262
+ last = new OffsetAt(new Date(startYear, 0, 1)),
263
+ offsets = [last],
264
+ change, next, i;
265
+
266
+ for (i = 1; i < 48; i++) {
267
+ next = new OffsetAt(new Date(startYear, i, 1));
268
+ if (next.offset !== last.offset) {
269
+ change = findChange(last, next);
270
+ offsets.push(change);
271
+ offsets.push(new OffsetAt(new Date(change.at + 6e4)));
272
+ }
273
+ last = next;
274
+ }
275
+
276
+ for (i = 0; i < 4; i++) {
277
+ offsets.push(new OffsetAt(new Date(startYear + i, 0, 1)));
278
+ offsets.push(new OffsetAt(new Date(startYear + i, 6, 1)));
279
+ }
280
+
281
+ return offsets;
282
+ }
283
+
284
+ function sortZoneScores (a, b) {
285
+ if (a.offsetScore !== b.offsetScore) {
286
+ return a.offsetScore - b.offsetScore;
287
+ }
288
+ if (a.abbrScore !== b.abbrScore) {
289
+ return a.abbrScore - b.abbrScore;
290
+ }
291
+ return b.zone.population - a.zone.population;
292
+ }
293
+
294
+ function addToGuesses (name, offsets) {
295
+ var i, offset;
296
+ arrayToInt(offsets);
297
+ for (i = 0; i < offsets.length; i++) {
298
+ offset = offsets[i];
299
+ guesses[offset] = guesses[offset] || {};
300
+ guesses[offset][name] = true;
301
+ }
302
+ }
303
+
304
+ function guessesForUserOffsets (offsets) {
305
+ var offsetsLength = offsets.length,
306
+ filteredGuesses = {},
307
+ out = [],
308
+ i, j, guessesOffset;
309
+
310
+ for (i = 0; i < offsetsLength; i++) {
311
+ guessesOffset = guesses[offsets[i].offset] || {};
312
+ for (j in guessesOffset) {
313
+ if (guessesOffset.hasOwnProperty(j)) {
314
+ filteredGuesses[j] = true;
315
+ }
316
+ }
317
+ }
318
+
319
+ for (i in filteredGuesses) {
320
+ if (filteredGuesses.hasOwnProperty(i)) {
321
+ out.push(names[i]);
322
+ }
323
+ }
324
+
325
+ return out;
326
+ }
327
+
328
+ function rebuildGuess () {
329
+
330
+ // use Intl API when available and returning valid time zone
331
+ try {
332
+ var intlName = Intl.DateTimeFormat().resolvedOptions().timeZone;
333
+ if (intlName && intlName.length > 3) {
334
+ var name = names[normalizeName(intlName)];
335
+ if (name) {
336
+ return name;
337
+ }
338
+ logError("Moment Timezone found " + intlName + " from the Intl api, but did not have that data loaded.");
339
+ }
340
+ } catch (e) {
341
+ // Intl unavailable, fall back to manual guessing.
342
+ }
343
+
344
+ var offsets = userOffsets(),
345
+ offsetsLength = offsets.length,
346
+ guesses = guessesForUserOffsets(offsets),
347
+ zoneScores = [],
348
+ zoneScore, i, j;
349
+
350
+ for (i = 0; i < guesses.length; i++) {
351
+ zoneScore = new ZoneScore(getZone(guesses[i]), offsetsLength);
352
+ for (j = 0; j < offsetsLength; j++) {
353
+ zoneScore.scoreOffsetAt(offsets[j]);
354
+ }
355
+ zoneScores.push(zoneScore);
356
+ }
357
+
358
+ zoneScores.sort(sortZoneScores);
359
+
360
+ return zoneScores.length > 0 ? zoneScores[0].zone.name : undefined;
361
+ }
362
+
363
+ function guess (ignoreCache) {
364
+ if (!cachedGuess || ignoreCache) {
365
+ cachedGuess = rebuildGuess();
366
+ }
367
+ return cachedGuess;
368
+ }
369
+
370
+ /************************************
371
+ Global Methods
372
+ ************************************/
373
+
374
+ function normalizeName (name) {
375
+ return (name || '').toLowerCase().replace(/\//g, '_');
376
+ }
377
+
378
+ function addZone (packed) {
379
+ var i, name, split, normalized;
380
+
381
+ if (typeof packed === "string") {
382
+ packed = [packed];
383
+ }
384
+
385
+ for (i = 0; i < packed.length; i++) {
386
+ split = packed[i].split('|');
387
+ name = split[0];
388
+ normalized = normalizeName(name);
389
+ zones[normalized] = packed[i];
390
+ names[normalized] = name;
391
+ addToGuesses(normalized, split[2].split(' '));
392
+ }
393
+ }
394
+
395
+ function getZone (name, caller) {
396
+ name = normalizeName(name);
397
+
398
+ var zone = zones[name];
399
+ var link;
400
+
401
+ if (zone instanceof Zone) {
402
+ return zone;
403
+ }
404
+
405
+ if (typeof zone === 'string') {
406
+ zone = new Zone(zone);
407
+ zones[name] = zone;
408
+ return zone;
409
+ }
410
+
411
+ // Pass getZone to prevent recursion more than 1 level deep
412
+ if (links[name] && caller !== getZone && (link = getZone(links[name], getZone))) {
413
+ zone = zones[name] = new Zone();
414
+ zone._set(link);
415
+ zone.name = names[name];
416
+ return zone;
417
+ }
418
+
419
+ return null;
420
+ }
421
+
422
+ function getNames () {
423
+ var i, out = [];
424
+
425
+ for (i in names) {
426
+ if (names.hasOwnProperty(i) && (zones[i] || zones[links[i]]) && names[i]) {
427
+ out.push(names[i]);
428
+ }
429
+ }
430
+
431
+ return out.sort();
432
+ }
433
+
434
+ function addLink (aliases) {
435
+ var i, alias, normal0, normal1;
436
+
437
+ if (typeof aliases === "string") {
438
+ aliases = [aliases];
439
+ }
440
+
441
+ for (i = 0; i < aliases.length; i++) {
442
+ alias = aliases[i].split('|');
443
+
444
+ normal0 = normalizeName(alias[0]);
445
+ normal1 = normalizeName(alias[1]);
446
+
447
+ links[normal0] = normal1;
448
+ names[normal0] = alias[0];
449
+
450
+ links[normal1] = normal0;
451
+ names[normal1] = alias[1];
452
+ }
453
+ }
454
+
455
+ function loadData (data) {
456
+ addZone(data.zones);
457
+ addLink(data.links);
458
+ tz.dataVersion = data.version;
459
+ }
460
+
461
+ function zoneExists (name) {
462
+ if (!zoneExists.didShowError) {
463
+ zoneExists.didShowError = true;
464
+ logError("moment.tz.zoneExists('" + name + "') has been deprecated in favor of !moment.tz.zone('" + name + "')");
465
+ }
466
+ return !!getZone(name);
467
+ }
468
+
469
+ function needsOffset (m) {
470
+ var isUnixTimestamp = (m._f === 'X' || m._f === 'x');
471
+ return !!(m._a && (m._tzm === undefined) && !isUnixTimestamp);
472
+ }
473
+
474
+ function logError (message) {
475
+ if (typeof console !== 'undefined' && typeof console.error === 'function') {
476
+ console.error(message);
477
+ }
478
+ }
479
+
480
+ /************************************
481
+ moment.tz namespace
482
+ ************************************/
483
+
484
+ function tz (input) {
485
+ var args = Array.prototype.slice.call(arguments, 0, -1),
486
+ name = arguments[arguments.length - 1],
487
+ zone = getZone(name),
488
+ out = moment.utc.apply(null, args);
489
+
490
+ if (zone && !moment.isMoment(input) && needsOffset(out)) {
491
+ out.add(zone.parse(out), 'minutes');
492
+ }
493
+
494
+ out.tz(name);
495
+
496
+ return out;
497
+ }
498
+
499
+ tz.version = VERSION;
500
+ tz.dataVersion = '';
501
+ tz._zones = zones;
502
+ tz._links = links;
503
+ tz._names = names;
504
+ tz.add = addZone;
505
+ tz.link = addLink;
506
+ tz.load = loadData;
507
+ tz.zone = getZone;
508
+ tz.zoneExists = zoneExists; // deprecated in 0.1.0
509
+ tz.guess = guess;
510
+ tz.names = getNames;
511
+ tz.Zone = Zone;
512
+ tz.unpack = unpack;
513
+ tz.unpackBase60 = unpackBase60;
514
+ tz.needsOffset = needsOffset;
515
+ tz.moveInvalidForward = true;
516
+ tz.moveAmbiguousForward = false;
517
+
518
+ /************************************
519
+ Interface with Moment.js
520
+ ************************************/
521
+
522
+ var fn = moment.fn;
523
+
524
+ moment.tz = tz;
525
+
526
+ moment.defaultZone = null;
527
+
528
+ moment.updateOffset = function (mom, keepTime) {
529
+ var zone = moment.defaultZone,
530
+ offset;
531
+
532
+ if (mom._z === undefined) {
533
+ if (zone && needsOffset(mom) && !mom._isUTC) {
534
+ mom._d = moment.utc(mom._a)._d;
535
+ mom.utc().add(zone.parse(mom), 'minutes');
536
+ }
537
+ mom._z = zone;
538
+ }
539
+ if (mom._z) {
540
+ offset = mom._z.utcOffset(mom);
541
+ if (Math.abs(offset) < 16) {
542
+ offset = offset / 60;
543
+ }
544
+ if (mom.utcOffset !== undefined) {
545
+ mom.utcOffset(-offset, keepTime);
546
+ } else {
547
+ mom.zone(offset, keepTime);
548
+ }
549
+ }
550
+ };
551
+
552
+ fn.tz = function (name, keepTime) {
553
+ if (name) {
554
+ this._z = getZone(name);
555
+ if (this._z) {
556
+ moment.updateOffset(this, keepTime);
557
+ } else {
558
+ logError("Moment Timezone has no data for " + name + ". See http://momentjs.com/timezone/docs/#/data-loading/.");
559
+ }
560
+ return this;
561
+ }
562
+ if (this._z) { return this._z.name; }
563
+ };
564
+
565
+ function abbrWrap (old) {
566
+ return function () {
567
+ if (this._z) { return this._z.abbr(this); }
568
+ return old.call(this);
569
+ };
570
+ }
571
+
572
+ function resetZoneWrap (old) {
573
+ return function () {
574
+ this._z = null;
575
+ return old.apply(this, arguments);
576
+ };
577
+ }
578
+
579
+ fn.zoneName = abbrWrap(fn.zoneName);
580
+ fn.zoneAbbr = abbrWrap(fn.zoneAbbr);
581
+ fn.utc = resetZoneWrap(fn.utc);
582
+
583
+ moment.tz.setDefault = function(name) {
584
+ if (major < 2 || (major === 2 && minor < 9)) {
585
+ logError('Moment Timezone setDefault() requires Moment.js >= 2.9.0. You are using Moment.js ' + moment.version + '.');
586
+ }
587
+ moment.defaultZone = name ? getZone(name) : null;
588
+ return moment;
589
+ };
590
+
591
+ // Cloning a moment should include the _z property.
592
+ var momentProperties = moment.momentProperties;
593
+ if (Object.prototype.toString.call(momentProperties) === '[object Array]') {
594
+ // moment 2.8.1+
595
+ momentProperties.push('_z');
596
+ momentProperties.push('_a');
597
+ } else if (momentProperties) {
598
+ // moment 2.7.0
599
+ momentProperties._z = null;
600
+ }
601
+
602
+ // INJECT DATA
603
+
604
+ return moment;
605
+ }));