index.js 5.5 KB

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