137 lines
3.7 KiB
JavaScript
137 lines
3.7 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", {
|
||
|
value: true
|
||
|
});
|
||
|
exports.default = tzParseTimezone;
|
||
|
|
||
|
var _index = _interopRequireDefault(require("../tzTokenizeDate/index.js"));
|
||
|
|
||
|
var _index2 = _interopRequireDefault(require("../newDateUTC/index.js"));
|
||
|
|
||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
|
||
|
var MILLISECONDS_IN_HOUR = 3600000;
|
||
|
var MILLISECONDS_IN_MINUTE = 60000;
|
||
|
var patterns = {
|
||
|
timezone: /([Z+-].*)$/,
|
||
|
timezoneZ: /^(Z)$/,
|
||
|
timezoneHH: /^([+-]\d{2})$/,
|
||
|
timezoneHHMM: /^([+-]\d{2}):?(\d{2})$/
|
||
|
}; // Parse various time zone offset formats to an offset in milliseconds
|
||
|
|
||
|
function tzParseTimezone(timezoneString, date, isUtcDate) {
|
||
|
var token;
|
||
|
var absoluteOffset; // Empty string
|
||
|
|
||
|
if (!timezoneString) {
|
||
|
return 0;
|
||
|
} // Z
|
||
|
|
||
|
|
||
|
token = patterns.timezoneZ.exec(timezoneString);
|
||
|
|
||
|
if (token) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
var hours; // ±hh
|
||
|
|
||
|
token = patterns.timezoneHH.exec(timezoneString);
|
||
|
|
||
|
if (token) {
|
||
|
hours = parseInt(token[1], 10);
|
||
|
|
||
|
if (!validateTimezone(hours)) {
|
||
|
return NaN;
|
||
|
}
|
||
|
|
||
|
return -(hours * MILLISECONDS_IN_HOUR);
|
||
|
} // ±hh:mm or ±hhmm
|
||
|
|
||
|
|
||
|
token = patterns.timezoneHHMM.exec(timezoneString);
|
||
|
|
||
|
if (token) {
|
||
|
hours = parseInt(token[1], 10);
|
||
|
var minutes = parseInt(token[2], 10);
|
||
|
|
||
|
if (!validateTimezone(hours, minutes)) {
|
||
|
return NaN;
|
||
|
}
|
||
|
|
||
|
absoluteOffset = Math.abs(hours) * MILLISECONDS_IN_HOUR + minutes * MILLISECONDS_IN_MINUTE;
|
||
|
return hours > 0 ? -absoluteOffset : absoluteOffset;
|
||
|
} // IANA time zone
|
||
|
|
||
|
|
||
|
if (isValidTimezoneIANAString(timezoneString)) {
|
||
|
date = new Date(date || Date.now());
|
||
|
var utcDate = isUtcDate ? date : toUtcDate(date);
|
||
|
var offset = calcOffset(utcDate, timezoneString);
|
||
|
var fixedOffset = isUtcDate ? offset : fixOffset(date, offset, timezoneString);
|
||
|
return -fixedOffset;
|
||
|
}
|
||
|
|
||
|
return NaN;
|
||
|
}
|
||
|
|
||
|
function toUtcDate(date) {
|
||
|
return (0, _index2.default)(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
|
||
|
}
|
||
|
|
||
|
function calcOffset(date, timezoneString) {
|
||
|
var tokens = (0, _index.default)(date, timezoneString); // ms dropped because it's not provided by tzTokenizeDate
|
||
|
|
||
|
var asUTC = (0, _index2.default)(tokens[0], tokens[1] - 1, tokens[2], tokens[3] % 24, tokens[4], tokens[5], 0).getTime();
|
||
|
var asTS = date.getTime();
|
||
|
var over = asTS % 1000;
|
||
|
asTS -= over >= 0 ? over : 1000 + over;
|
||
|
return asUTC - asTS;
|
||
|
}
|
||
|
|
||
|
function fixOffset(date, offset, timezoneString) {
|
||
|
var localTS = date.getTime(); // Our UTC time is just a guess because our offset is just a guess
|
||
|
|
||
|
var utcGuess = localTS - offset; // Test whether the zone matches the offset for this ts
|
||
|
|
||
|
var o2 = calcOffset(new Date(utcGuess), timezoneString); // If so, offset didn't change, and we're done
|
||
|
|
||
|
if (offset === o2) {
|
||
|
return offset;
|
||
|
} // If not, change the ts by the difference in the offset
|
||
|
|
||
|
|
||
|
utcGuess -= o2 - offset; // If that gives us the local time we want, we're done
|
||
|
|
||
|
var o3 = calcOffset(new Date(utcGuess), timezoneString);
|
||
|
|
||
|
if (o2 === o3) {
|
||
|
return o2;
|
||
|
} // If it's different, we're in a hole time. The offset has changed, but we don't adjust the time
|
||
|
|
||
|
|
||
|
return Math.max(o2, o3);
|
||
|
}
|
||
|
|
||
|
function validateTimezone(hours, minutes) {
|
||
|
return -23 <= hours && hours <= 23 && (minutes == null || 0 <= minutes && minutes <= 59);
|
||
|
}
|
||
|
|
||
|
var validIANATimezoneCache = {};
|
||
|
|
||
|
function isValidTimezoneIANAString(timeZoneString) {
|
||
|
if (validIANATimezoneCache[timeZoneString]) return true;
|
||
|
|
||
|
try {
|
||
|
new Intl.DateTimeFormat(undefined, {
|
||
|
timeZone: timeZoneString
|
||
|
});
|
||
|
validIANATimezoneCache[timeZoneString] = true;
|
||
|
return true;
|
||
|
} catch (error) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module.exports = exports.default;
|