@phensley/timezone
Advanced tools
Comparing version 1.0.9 to 1.1.0
@@ -38,2 +38,15 @@ import { RawData } from './types'; | ||
/** | ||
* Get the info for a time zone using a Wall Clock timestamp. This returns | ||
* the corresponding UTC timestamp and the timezone info record, or undefined | ||
* if the zone lookup fails. | ||
* | ||
* Since daylight savings time can result in a clock being moved backwards, | ||
* there is some ambiguity in resolving a wall clock time to the corresponding | ||
* UTC time. For example, on November 8 2020 in New York, the time 1:30 AM | ||
* occurs twice: once before the timezone boundary of 2:00 AM is reached, and | ||
* again after the clock is set back 1 hour to 1:00 AM. This method attempts | ||
* to resolve the ambiguity in the most intuitive way. | ||
*/ | ||
fromWall(zoneid: string, wall: number): [number, ZoneInfo] | undefined; | ||
/** | ||
* Resolve a lowercase time zone id or alias into the canonical proper-cased id. | ||
@@ -52,4 +65,4 @@ */ | ||
/** | ||
* Implements the time zone lookup. | ||
* | ||
* | ||
* @public | ||
@@ -78,4 +91,6 @@ */ | ||
/** | ||
* Get the info for a time zone using a local "wall clock" timestamp. | ||
* Get the info for a time zone using a local "wall clock" timestamp | ||
* for that zone. | ||
*/ | ||
fromWall(zoneid: string, wall: number): [number, ZoneInfo] | undefined; | ||
/** | ||
@@ -82,0 +97,0 @@ * UTC zone info. |
@@ -6,4 +6,4 @@ import { __assign } from "tslib"; | ||
/** | ||
* Implements the time zone lookup. | ||
* | ||
* | ||
* @public | ||
@@ -54,10 +54,12 @@ */ | ||
TzImpl.prototype.fromUTC = function (zoneid, utc) { | ||
return this.lookup(zoneid, utc, true); | ||
var r = this.lookup(zoneid, utc, true); | ||
return r ? r[1] : r; | ||
}; | ||
/** | ||
* Get the info for a time zone using a local "wall clock" timestamp. | ||
* Get the info for a time zone using a local "wall clock" timestamp | ||
* for that zone. | ||
*/ | ||
// fromWall(zoneid: string, wall: number): ZoneInfo | undefined { | ||
// return this.lookup(zoneid, wall, false); | ||
// } | ||
TzImpl.prototype.fromWall = function (zoneid, wall) { | ||
return this.lookup(zoneid, wall, false); | ||
}; | ||
/** | ||
@@ -84,10 +86,8 @@ * UTC zone info. | ||
*/ | ||
TzImpl.prototype.lookup = function (id, t, _isutc) { | ||
TzImpl.prototype.lookup = function (id, t, isutc) { | ||
var rec = this.record(id); | ||
if (rec) { | ||
var zoneid = rec[0], r = rec[1]; | ||
var res = r.fromUTC(t); | ||
// TODO: rework wall -> utc since it can require some guessing | ||
// const res = isutc ? r.fromUTC(t) : r.fromWall(t); | ||
return __assign(__assign({}, res), { zoneid: zoneid }); | ||
var _a = isutc ? r.fromUTC(t) : r.fromWall(t), utc = _a[0], res = _a[1]; | ||
return [utc, __assign(__assign({}, res), { zoneid: zoneid })]; | ||
} | ||
@@ -151,5 +151,59 @@ return undefined; | ||
var type = i === -1 ? 0 : this.types[i]; | ||
return this.localtime[type]; | ||
return [utc, this.localtime[type]]; | ||
}; | ||
/** | ||
* Resolve the zone info using a wall clock timestamp in the given zone. | ||
* | ||
* We have to determine the nearest DST transition boundary in wall clock | ||
* time, and choose one side of the boundary based on whether the clock moved | ||
* backwards or forwards, and where our wall time falls relative to | ||
* the boundary, or within the transitional gap. | ||
*/ | ||
ZoneRecord.prototype.fromWall = function (wall) { | ||
// Find the until one day before our wall time | ||
var i = binarySearch(this.untils, true, wall - 86400000); | ||
var r0 = this.localtime[i === -1 ? 0 : this.types[i]]; | ||
i++; | ||
// Check if we hit the end of the untils array and return | ||
if (i === this.types.length) { | ||
return [wall - r0.offset, r0]; | ||
} | ||
// Get the next until. | ||
var r1 = this.localtime[this.types[i]]; | ||
var u1 = this.untils[i]; | ||
// Adjust the next until using the prior offset to find the wall clock time of the boundary. | ||
// | ||
// Example for New York on Mar 8, 2020 with DST boundary at 7:00 AM UTC: | ||
// 1:59 AM NY time is UTC 6:59 AM minus 5 hours | ||
// | ||
// 1 minute later the offset changes to -04:00: | ||
// 2:00 AM NY time is UTC 7:00 AM minus 5 hours, so local time becomes 3:00 AM | ||
// | ||
// Example for New York on Nov 1, 2020 with DST boundary at 7:00 AM UTC: | ||
// 1:59 AM NY time is UTC 5:59 AM minus 4 hours | ||
// | ||
// 1 minute later the offset changes to -05:00: | ||
// 2:00 AM NY time is UTC 6:00 AM minus 4 hours, so local time becomes 1:00 AM | ||
// Wall time instantaneously at zone boundary | ||
var w0 = u1 + r0.offset; | ||
// New wall time after boundary is crossed | ||
var w1 = u1 + r1.offset; | ||
// Wall time is before the gap, return pre-boundary offset | ||
if (wall < w0 && wall < w1) { | ||
return [wall - r0.offset, r0]; | ||
} | ||
// When local time jumps forward, the resulting gap contains many "impossible" | ||
// times. In our example for New York, Mar 8 2020 at 2:30 AM is invalid. | ||
// We return a UTC timestamp and offset that will make the local time 3:30 AM. | ||
if (w0 < w1) { | ||
// Wall time is either in the gap of impossible times or after the gap. | ||
return wall < w1 ? [wall - r0.offset, r1] : [wall - r1.offset, r1]; | ||
} | ||
// When local time jumps backwards, many times occur twice. | ||
// In our example for New York, Nov 1 2020, 1:30 AM occurs once as local | ||
// time moves towards 2:00 AM, and occurs again after the time has been | ||
// moved back to 1:00 AM. | ||
return wall < w0 ? [wall - r0.offset, r0] : [wall - r1.offset, r1]; | ||
}; | ||
/** | ||
* Decode a single zone info record. | ||
@@ -156,0 +210,0 @@ */ |
@@ -38,2 +38,15 @@ import { RawData } from './types'; | ||
/** | ||
* Get the info for a time zone using a Wall Clock timestamp. This returns | ||
* the corresponding UTC timestamp and the timezone info record, or undefined | ||
* if the zone lookup fails. | ||
* | ||
* Since daylight savings time can result in a clock being moved backwards, | ||
* there is some ambiguity in resolving a wall clock time to the corresponding | ||
* UTC time. For example, on November 8 2020 in New York, the time 1:30 AM | ||
* occurs twice: once before the timezone boundary of 2:00 AM is reached, and | ||
* again after the clock is set back 1 hour to 1:00 AM. This method attempts | ||
* to resolve the ambiguity in the most intuitive way. | ||
*/ | ||
fromWall(zoneid: string, wall: number): [number, ZoneInfo] | undefined; | ||
/** | ||
* Resolve a lowercase time zone id or alias into the canonical proper-cased id. | ||
@@ -52,4 +65,4 @@ */ | ||
/** | ||
* Implements the time zone lookup. | ||
* | ||
* | ||
* @public | ||
@@ -78,4 +91,6 @@ */ | ||
/** | ||
* Get the info for a time zone using a local "wall clock" timestamp. | ||
* Get the info for a time zone using a local "wall clock" timestamp | ||
* for that zone. | ||
*/ | ||
fromWall(zoneid: string, wall: number): [number, ZoneInfo] | undefined; | ||
/** | ||
@@ -82,0 +97,0 @@ * UTC zone info. |
@@ -8,4 +8,4 @@ "use strict"; | ||
/** | ||
* Implements the time zone lookup. | ||
* | ||
* | ||
* @public | ||
@@ -56,10 +56,12 @@ */ | ||
TzImpl.prototype.fromUTC = function (zoneid, utc) { | ||
return this.lookup(zoneid, utc, true); | ||
var r = this.lookup(zoneid, utc, true); | ||
return r ? r[1] : r; | ||
}; | ||
/** | ||
* Get the info for a time zone using a local "wall clock" timestamp. | ||
* Get the info for a time zone using a local "wall clock" timestamp | ||
* for that zone. | ||
*/ | ||
// fromWall(zoneid: string, wall: number): ZoneInfo | undefined { | ||
// return this.lookup(zoneid, wall, false); | ||
// } | ||
TzImpl.prototype.fromWall = function (zoneid, wall) { | ||
return this.lookup(zoneid, wall, false); | ||
}; | ||
/** | ||
@@ -86,10 +88,8 @@ * UTC zone info. | ||
*/ | ||
TzImpl.prototype.lookup = function (id, t, _isutc) { | ||
TzImpl.prototype.lookup = function (id, t, isutc) { | ||
var rec = this.record(id); | ||
if (rec) { | ||
var zoneid = rec[0], r = rec[1]; | ||
var res = r.fromUTC(t); | ||
// TODO: rework wall -> utc since it can require some guessing | ||
// const res = isutc ? r.fromUTC(t) : r.fromWall(t); | ||
return tslib_1.__assign(tslib_1.__assign({}, res), { zoneid: zoneid }); | ||
var _a = isutc ? r.fromUTC(t) : r.fromWall(t), utc = _a[0], res = _a[1]; | ||
return [utc, tslib_1.__assign(tslib_1.__assign({}, res), { zoneid: zoneid })]; | ||
} | ||
@@ -153,5 +153,59 @@ return undefined; | ||
var type = i === -1 ? 0 : this.types[i]; | ||
return this.localtime[type]; | ||
return [utc, this.localtime[type]]; | ||
}; | ||
/** | ||
* Resolve the zone info using a wall clock timestamp in the given zone. | ||
* | ||
* We have to determine the nearest DST transition boundary in wall clock | ||
* time, and choose one side of the boundary based on whether the clock moved | ||
* backwards or forwards, and where our wall time falls relative to | ||
* the boundary, or within the transitional gap. | ||
*/ | ||
ZoneRecord.prototype.fromWall = function (wall) { | ||
// Find the until one day before our wall time | ||
var i = cldr_utils_1.binarySearch(this.untils, true, wall - 86400000); | ||
var r0 = this.localtime[i === -1 ? 0 : this.types[i]]; | ||
i++; | ||
// Check if we hit the end of the untils array and return | ||
if (i === this.types.length) { | ||
return [wall - r0.offset, r0]; | ||
} | ||
// Get the next until. | ||
var r1 = this.localtime[this.types[i]]; | ||
var u1 = this.untils[i]; | ||
// Adjust the next until using the prior offset to find the wall clock time of the boundary. | ||
// | ||
// Example for New York on Mar 8, 2020 with DST boundary at 7:00 AM UTC: | ||
// 1:59 AM NY time is UTC 6:59 AM minus 5 hours | ||
// | ||
// 1 minute later the offset changes to -04:00: | ||
// 2:00 AM NY time is UTC 7:00 AM minus 5 hours, so local time becomes 3:00 AM | ||
// | ||
// Example for New York on Nov 1, 2020 with DST boundary at 7:00 AM UTC: | ||
// 1:59 AM NY time is UTC 5:59 AM minus 4 hours | ||
// | ||
// 1 minute later the offset changes to -05:00: | ||
// 2:00 AM NY time is UTC 6:00 AM minus 4 hours, so local time becomes 1:00 AM | ||
// Wall time instantaneously at zone boundary | ||
var w0 = u1 + r0.offset; | ||
// New wall time after boundary is crossed | ||
var w1 = u1 + r1.offset; | ||
// Wall time is before the gap, return pre-boundary offset | ||
if (wall < w0 && wall < w1) { | ||
return [wall - r0.offset, r0]; | ||
} | ||
// When local time jumps forward, the resulting gap contains many "impossible" | ||
// times. In our example for New York, Mar 8 2020 at 2:30 AM is invalid. | ||
// We return a UTC timestamp and offset that will make the local time 3:30 AM. | ||
if (w0 < w1) { | ||
// Wall time is either in the gap of impossible times or after the gap. | ||
return wall < w1 ? [wall - r0.offset, r1] : [wall - r1.offset, r1]; | ||
} | ||
// When local time jumps backwards, many times occur twice. | ||
// In our example for New York, Nov 1 2020, 1:30 AM occurs once as local | ||
// time moves towards 2:00 AM, and occurs again after the time has been | ||
// moved back to 1:00 AM. | ||
return wall < w0 ? [wall - r0.offset, r0] : [wall - r1.offset, r1]; | ||
}; | ||
/** | ||
* Decode a single zone info record. | ||
@@ -158,0 +212,0 @@ */ |
{ | ||
"name": "@phensley/timezone", | ||
"version": "1.0.9", | ||
"version": "1.1.0", | ||
"description": "Compact timezone lib based on tz database", | ||
@@ -40,24 +40,24 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"@phensley/cldr-utils": "1.0.9", | ||
"@phensley/cldr-utils": "1.1.0", | ||
"tslib": "^1.11.1" | ||
}, | ||
"devDependencies": { | ||
"@microsoft/api-extractor": "^7.7.8", | ||
"@types/jest": "^25.1.3", | ||
"@types/node": "^13.9.2", | ||
"@types/rimraf": "^2.0.2", | ||
"@types/yargs": "^13.0.3", | ||
"@microsoft/api-extractor": "^7.7.13", | ||
"@types/jest": "^25.2.1", | ||
"@types/node": "^13.11.1", | ||
"@types/rimraf": "^3.0.0", | ||
"@types/yargs": "^15.0.4", | ||
"beautify-benchmark": "^0.2.4", | ||
"benchmark": "^2.1.4", | ||
"chalk": "^2.3.2", | ||
"dts-bundle-generator": "^3.1.0", | ||
"jest": "^25.1.0", | ||
"rimraf": "^3.0.0", | ||
"ts-jest": "^25.2.1", | ||
"ts-node": "^8.3.0", | ||
"tslint": "^6.1.0", | ||
"chalk": "^4.0.0", | ||
"dts-bundle-generator": "^4.1.0", | ||
"jest": "^25.3.0", | ||
"rimraf": "^3.0.2", | ||
"ts-jest": "^25.3.1", | ||
"ts-node": "^8.8.2", | ||
"tslint": "^6.1.1", | ||
"tslint-no-circular-imports": "^0.7.0", | ||
"typescript": "^3.8.x", | ||
"typescript": "^3.8.3", | ||
"uglify-es": "^3.3.9", | ||
"yargs": "^14.2.0" | ||
"yargs": "^15.3.1" | ||
}, | ||
@@ -81,3 +81,3 @@ "jest": { | ||
}, | ||
"gitHead": "3c5f9737f7ca1034d3e87121e5d5b378595ca1ed" | ||
"gitHead": "6aeccdd49b8740c95f97edae93a063306c271c57" | ||
} |
@@ -5,3 +5,3 @@ # @phensley/timezone | ||
Compact timezone library provides the full range of tzdb data. Supports all years for which rules exist, with currently-active rules extended into the future through year 2499. https://data.iana.org/time-zones/tz-link.html | ||
Compact timezone library provides the full range of tzdb data. https://data.iana.org/time-zones/tz-link.html | ||
@@ -37,4 +37,6 @@ ## Installation | ||
Lookup the zone info for a timezone id at a given UTC time. Timezone offsets are in milliseconds. | ||
#### Lookup the zone info for a timezone id at a given UTC time. | ||
Timezone offsets are in milliseconds. | ||
```typescript | ||
@@ -47,3 +49,3 @@ const ZONES = [ | ||
'Asia/Tokyo', | ||
'Europe/Paris' | ||
'Europe/Paris', | ||
]; | ||
@@ -66,1 +68,19 @@ | ||
``` | ||
#### Lookup the zone info for a timezone id and a local "wall clock" timestamp. | ||
Returns the corresponding UTC timestamp along with a zone info record. | ||
```typescript | ||
// Sun Mar 8 2020 02:10:00 AM NY time | ||
const epoch = 1583633400000; | ||
const zoneid = 'America/New_York'; | ||
const [utc, info] = TZ.fromUTC(zoneid, now)!; | ||
console.log(utc); | ||
console.log(JSON.stringify(info)); | ||
``` | ||
``` | ||
1583651400000 | ||
{"abbr":"EDT","dst":1,"offset":-14400000,"zoneid":"America/New_York"} | ||
``` |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
342330
2048
83
+ Added@phensley/cldr-utils@1.1.0(transitive)
- Removed@phensley/cldr-utils@1.0.9(transitive)
Updated@phensley/cldr-utils@1.1.0