0eb335a0b90640787325d5272deb725508c134f9806007371e5ed4a88c23afd32980e69b9ccc6830573462010aa59f7e3659f00774afd371f37a18f5771a45 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. import zeroFill from '../utils/zero-fill';
  2. import { createDuration } from '../duration/create';
  3. import { addSubtract } from '../moment/add-subtract';
  4. import { isMoment, copyConfig } from '../moment/constructor';
  5. import { addFormatToken } from '../format/format';
  6. import { addRegexToken, matchOffset, matchShortOffset } from '../parse/regex';
  7. import { addParseToken } from '../parse/token';
  8. import { createLocal } from '../create/local';
  9. import { prepareConfig } from '../create/from-anything';
  10. import { createUTC } from '../create/utc';
  11. import isDate from '../utils/is-date';
  12. import toInt from '../utils/to-int';
  13. import isUndefined from '../utils/is-undefined';
  14. import compareArrays from '../utils/compare-arrays';
  15. import { hooks } from '../utils/hooks';
  16. // FORMATTING
  17. function offset(token, separator) {
  18. addFormatToken(token, 0, 0, function () {
  19. var offset = this.utcOffset(),
  20. sign = '+';
  21. if (offset < 0) {
  22. offset = -offset;
  23. sign = '-';
  24. }
  25. return (
  26. sign +
  27. zeroFill(~~(offset / 60), 2) +
  28. separator +
  29. zeroFill(~~offset % 60, 2)
  30. );
  31. });
  32. }
  33. offset('Z', ':');
  34. offset('ZZ', '');
  35. // PARSING
  36. addRegexToken('Z', matchShortOffset);
  37. addRegexToken('ZZ', matchShortOffset);
  38. addParseToken(['Z', 'ZZ'], function (input, array, config) {
  39. config._useUTC = true;
  40. config._tzm = offsetFromString(matchShortOffset, input);
  41. });
  42. // HELPERS
  43. // timezone chunker
  44. // '+10:00' > ['10', '00']
  45. // '-1530' > ['-15', '30']
  46. var chunkOffset = /([\+\-]|\d\d)/gi;
  47. function offsetFromString(matcher, string) {
  48. var matches = (string || '').match(matcher),
  49. chunk,
  50. parts,
  51. minutes;
  52. if (matches === null) {
  53. return null;
  54. }
  55. chunk = matches[matches.length - 1] || [];
  56. parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
  57. minutes = +(parts[1] * 60) + toInt(parts[2]);
  58. return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes;
  59. }
  60. // Return a moment from input, that is local/utc/zone equivalent to model.
  61. export function cloneWithOffset(input, model) {
  62. var res, diff;
  63. if (model._isUTC) {
  64. res = model.clone();
  65. diff =
  66. (isMoment(input) || isDate(input)
  67. ? input.valueOf()
  68. : createLocal(input).valueOf()) - res.valueOf();
  69. // Use low-level api, because this fn is low-level api.
  70. res._d.setTime(res._d.valueOf() + diff);
  71. hooks.updateOffset(res, false);
  72. return res;
  73. } else {
  74. return createLocal(input).local();
  75. }
  76. }
  77. function getDateOffset(m) {
  78. // On Firefox.24 Date#getTimezoneOffset returns a floating point.
  79. // https://github.com/moment/moment/pull/1871
  80. return -Math.round(m._d.getTimezoneOffset());
  81. }
  82. // HOOKS
  83. // This function will be called whenever a moment is mutated.
  84. // It is intended to keep the offset in sync with the timezone.
  85. hooks.updateOffset = function () {};
  86. // MOMENTS
  87. // keepLocalTime = true means only change the timezone, without
  88. // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
  89. // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
  90. // +0200, so we adjust the time as needed, to be valid.
  91. //
  92. // Keeping the time actually adds/subtracts (one hour)
  93. // from the actual represented time. That is why we call updateOffset
  94. // a second time. In case it wants us to change the offset again
  95. // _changeInProgress == true case, then we have to adjust, because
  96. // there is no such time in the given timezone.
  97. export function getSetOffset(input, keepLocalTime, keepMinutes) {
  98. var offset = this._offset || 0,
  99. localAdjust;
  100. if (!this.isValid()) {
  101. return input != null ? this : NaN;
  102. }
  103. if (input != null) {
  104. if (typeof input === 'string') {
  105. input = offsetFromString(matchShortOffset, input);
  106. if (input === null) {
  107. return this;
  108. }
  109. } else if (Math.abs(input) < 16 && !keepMinutes) {
  110. input = input * 60;
  111. }
  112. if (!this._isUTC && keepLocalTime) {
  113. localAdjust = getDateOffset(this);
  114. }
  115. this._offset = input;
  116. this._isUTC = true;
  117. if (localAdjust != null) {
  118. this.add(localAdjust, 'm');
  119. }
  120. if (offset !== input) {
  121. if (!keepLocalTime || this._changeInProgress) {
  122. addSubtract(
  123. this,
  124. createDuration(input - offset, 'm'),
  125. 1,
  126. false
  127. );
  128. } else if (!this._changeInProgress) {
  129. this._changeInProgress = true;
  130. hooks.updateOffset(this, true);
  131. this._changeInProgress = null;
  132. }
  133. }
  134. return this;
  135. } else {
  136. return this._isUTC ? offset : getDateOffset(this);
  137. }
  138. }
  139. export function getSetZone(input, keepLocalTime) {
  140. if (input != null) {
  141. if (typeof input !== 'string') {
  142. input = -input;
  143. }
  144. this.utcOffset(input, keepLocalTime);
  145. return this;
  146. } else {
  147. return -this.utcOffset();
  148. }
  149. }
  150. export function setOffsetToUTC(keepLocalTime) {
  151. return this.utcOffset(0, keepLocalTime);
  152. }
  153. export function setOffsetToLocal(keepLocalTime) {
  154. if (this._isUTC) {
  155. this.utcOffset(0, keepLocalTime);
  156. this._isUTC = false;
  157. if (keepLocalTime) {
  158. this.subtract(getDateOffset(this), 'm');
  159. }
  160. }
  161. return this;
  162. }
  163. export function setOffsetToParsedOffset() {
  164. if (this._tzm != null) {
  165. this.utcOffset(this._tzm, false, true);
  166. } else if (typeof this._i === 'string') {
  167. var tZone = offsetFromString(matchOffset, this._i);
  168. if (tZone != null) {
  169. this.utcOffset(tZone);
  170. } else {
  171. this.utcOffset(0, true);
  172. }
  173. }
  174. return this;
  175. }
  176. export function hasAlignedHourOffset(input) {
  177. if (!this.isValid()) {
  178. return false;
  179. }
  180. input = input ? createLocal(input).utcOffset() : 0;
  181. return (this.utcOffset() - input) % 60 === 0;
  182. }
  183. export function isDaylightSavingTime() {
  184. return (
  185. this.utcOffset() > this.clone().month(0).utcOffset() ||
  186. this.utcOffset() > this.clone().month(5).utcOffset()
  187. );
  188. }
  189. export function isDaylightSavingTimeShifted() {
  190. if (!isUndefined(this._isDSTShifted)) {
  191. return this._isDSTShifted;
  192. }
  193. var c = {},
  194. other;
  195. copyConfig(c, this);
  196. c = prepareConfig(c);
  197. if (c._a) {
  198. other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
  199. this._isDSTShifted =
  200. this.isValid() && compareArrays(c._a, other.toArray()) > 0;
  201. } else {
  202. this._isDSTShifted = false;
  203. }
  204. return this._isDSTShifted;
  205. }
  206. export function isLocal() {
  207. return this.isValid() ? !this._isUTC : false;
  208. }
  209. export function isUtcOffset() {
  210. return this.isValid() ? this._isUTC : false;
  211. }
  212. export function isUtc() {
  213. return this.isValid() ? this._isUTC && this._offset === 0 : false;
  214. }