You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
5.2 KiB
185 lines
5.2 KiB
import { MIN, MS } from '../../constant'; |
|
var typeToPos = { |
|
year: 0, |
|
month: 1, |
|
day: 2, |
|
hour: 3, |
|
minute: 4, |
|
second: 5 |
|
}; // Cache time-zone lookups from Intl.DateTimeFormat, |
|
// as it is a *very* slow method. |
|
|
|
var dtfCache = {}; |
|
|
|
var getDateTimeFormat = function getDateTimeFormat(timezone, options) { |
|
if (options === void 0) { |
|
options = {}; |
|
} |
|
|
|
var timeZoneName = options.timeZoneName || 'short'; |
|
var key = timezone + "|" + timeZoneName; |
|
var dtf = dtfCache[key]; |
|
|
|
if (!dtf) { |
|
dtf = new Intl.DateTimeFormat('en-US', { |
|
hour12: false, |
|
timeZone: timezone, |
|
year: 'numeric', |
|
month: '2-digit', |
|
day: '2-digit', |
|
hour: '2-digit', |
|
minute: '2-digit', |
|
second: '2-digit', |
|
timeZoneName: timeZoneName |
|
}); |
|
dtfCache[key] = dtf; |
|
} |
|
|
|
return dtf; |
|
}; |
|
|
|
export default (function (o, c, d) { |
|
var defaultTimezone; |
|
|
|
var makeFormatParts = function makeFormatParts(timestamp, timezone, options) { |
|
if (options === void 0) { |
|
options = {}; |
|
} |
|
|
|
var date = new Date(timestamp); |
|
var dtf = getDateTimeFormat(timezone, options); |
|
return dtf.formatToParts(date); |
|
}; |
|
|
|
var tzOffset = function tzOffset(timestamp, timezone) { |
|
var formatResult = makeFormatParts(timestamp, timezone); |
|
var filled = []; |
|
|
|
for (var i = 0; i < formatResult.length; i += 1) { |
|
var _formatResult$i = formatResult[i], |
|
type = _formatResult$i.type, |
|
value = _formatResult$i.value; |
|
var pos = typeToPos[type]; |
|
|
|
if (pos >= 0) { |
|
filled[pos] = parseInt(value, 10); |
|
} |
|
} |
|
|
|
var hour = filled[3]; // Workaround for the same behavior in different node version |
|
// https://github.com/nodejs/node/issues/33027 |
|
|
|
/* istanbul ignore next */ |
|
|
|
var fixedHour = hour === 24 ? 0 : hour; |
|
var utcString = filled[0] + "-" + filled[1] + "-" + filled[2] + " " + fixedHour + ":" + filled[4] + ":" + filled[5] + ":000"; |
|
var utcTs = d.utc(utcString).valueOf(); |
|
var asTS = +timestamp; |
|
var over = asTS % 1000; |
|
asTS -= over; |
|
return (utcTs - asTS) / (60 * 1000); |
|
}; // find the right offset a given local time. The o input is our guess, which determines which |
|
// offset we'll pick in ambiguous cases (e.g. there are two 3 AMs b/c Fallback DST) |
|
// https://github.com/moment/luxon/blob/master/src/datetime.js#L76 |
|
|
|
|
|
var fixOffset = function fixOffset(localTS, o0, tz) { |
|
// Our UTC time is just a guess because our offset is just a guess |
|
var utcGuess = localTS - o0 * 60 * 1000; // Test whether the zone matches the offset for this ts |
|
|
|
var o2 = tzOffset(utcGuess, tz); // If so, offset didn't change and we're done |
|
|
|
if (o0 === o2) { |
|
return [utcGuess, o0]; |
|
} // If not, change the ts by the difference in the offset |
|
|
|
|
|
utcGuess -= (o2 - o0) * 60 * 1000; // If that gives us the local time we want, we're done |
|
|
|
var o3 = tzOffset(utcGuess, tz); |
|
|
|
if (o2 === o3) { |
|
return [utcGuess, o2]; |
|
} // If it's different, we're in a hole time. |
|
// The offset has changed, but the we don't adjust the time |
|
|
|
|
|
return [localTS - Math.min(o2, o3) * 60 * 1000, Math.max(o2, o3)]; |
|
}; |
|
|
|
var proto = c.prototype; |
|
|
|
proto.tz = function (timezone, keepLocalTime) { |
|
if (timezone === void 0) { |
|
timezone = defaultTimezone; |
|
} |
|
|
|
var oldOffset = this.utcOffset(); |
|
var date = this.toDate(); |
|
var target = date.toLocaleString('en-US', { |
|
timeZone: timezone |
|
}); |
|
var diff = Math.round((date - new Date(target)) / 1000 / 60); |
|
var ins = d(target).$set(MS, this.$ms).utcOffset(-Math.round(date.getTimezoneOffset() / 15) * 15 - diff, true); |
|
|
|
if (keepLocalTime) { |
|
var newOffset = ins.utcOffset(); |
|
ins = ins.add(oldOffset - newOffset, MIN); |
|
} |
|
|
|
ins.$x.$timezone = timezone; |
|
return ins; |
|
}; |
|
|
|
proto.offsetName = function (type) { |
|
// type: short(default) / long |
|
var zone = this.$x.$timezone || d.tz.guess(); |
|
var result = makeFormatParts(this.valueOf(), zone, { |
|
timeZoneName: type |
|
}).find(function (m) { |
|
return m.type.toLowerCase() === 'timezonename'; |
|
}); |
|
return result && result.value; |
|
}; |
|
|
|
var oldStartOf = proto.startOf; |
|
|
|
proto.startOf = function (units, startOf) { |
|
if (!this.$x || !this.$x.$timezone) { |
|
return oldStartOf.call(this, units, startOf); |
|
} |
|
|
|
var withoutTz = d(this.format('YYYY-MM-DD HH:mm:ss:SSS')); |
|
var startOfWithoutTz = oldStartOf.call(withoutTz, units, startOf); |
|
return startOfWithoutTz.tz(this.$x.$timezone, true); |
|
}; |
|
|
|
d.tz = function (input, arg1, arg2) { |
|
var parseFormat = arg2 && arg1; |
|
var timezone = arg2 || arg1 || defaultTimezone; |
|
var previousOffset = tzOffset(+d(), timezone); |
|
|
|
if (typeof input !== 'string') { |
|
// timestamp number || js Date || Day.js |
|
return d(input).tz(timezone); |
|
} |
|
|
|
var localTs = d.utc(input, parseFormat).valueOf(); |
|
|
|
var _fixOffset = fixOffset(localTs, previousOffset, timezone), |
|
targetTs = _fixOffset[0], |
|
targetOffset = _fixOffset[1]; |
|
|
|
var ins = d(targetTs).utcOffset(targetOffset); |
|
ins.$x.$timezone = timezone; |
|
return ins; |
|
}; |
|
|
|
d.tz.guess = function () { |
|
return Intl.DateTimeFormat().resolvedOptions().timeZone; |
|
}; |
|
|
|
d.tz.setDefault = function (timezone) { |
|
defaultTimezone = timezone; |
|
}; |
|
}); |