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