timezone-soft 1.5.2 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +166 -107
- package/builds/timezone-soft.cjs +1141 -1036
- package/builds/timezone-soft.js +1210 -0
- package/builds/timezone-soft.min.js +2 -0
- package/package.json +61 -40
- package/types/index.d.cts +25 -0
- package/types/index.d.ts +14 -2
- package/builds/timezone-soft.min.cjs +0 -1
- package/builds/timezone-soft.mjs +0 -1099
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 spencer kelly
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,160 +1,219 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
|
|
3
|
-
<div>
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
<img src="https://codecov.io/gh/spencermountain/timezone-soft/branch/master/graph/badge.svg" />
|
|
12
|
-
</a> -->
|
|
13
|
-
<a href="https://unpkg.com/timezone-soft/builds/timezone-soft.min.js">
|
|
14
|
-
<img src="https://badge-size.herokuapp.com/spencermountain/timezone-soft/master/builds/timezone-soft.min.js" />
|
|
15
|
-
</a>
|
|
16
|
-
</div>
|
|
17
|
-
<div align="center">
|
|
18
|
-
<code>npm install timezone-soft</code>
|
|
19
|
-
</div>
|
|
20
|
-
<sub>
|
|
21
|
-
by
|
|
22
|
-
<a href="https://spencermountain.github.io/">Spencer Kelly</a>
|
|
23
|
-
</sub>
|
|
24
|
-
<div align="center">
|
|
25
|
-
<sup><i>(formerly called 'spacetime-informal')</i></sup>
|
|
26
|
-
</div>
|
|
2
|
+
<img src="https://cloud.githubusercontent.com/assets/399657/23590290/ede73772-01aa-11e7-8915-181ef21027bc.png" />
|
|
3
|
+
<div>informal timezone lookup</div>
|
|
4
|
+
<a href="https://npmjs.org/package/timezone-soft">
|
|
5
|
+
<img src="https://img.shields.io/npm/v/timezone-soft.svg?style=flat-square" />
|
|
6
|
+
</a>
|
|
7
|
+
<a href="https://bundlephobia.com/result?p=timezone-soft@latest">
|
|
8
|
+
<img src="https://badgen.net/bundlejs/min/timezone-soft" />
|
|
9
|
+
</a>
|
|
10
|
+
<div><code>npm install timezone-soft</code></div>
|
|
27
11
|
</div>
|
|
28
|
-
<p></p>
|
|
29
12
|
|
|
30
13
|
<!-- spacer -->
|
|
31
|
-
<img height="
|
|
14
|
+
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/>
|
|
32
15
|
|
|
33
16
|
```js
|
|
34
|
-
import
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
/*[{
|
|
39
|
-
iana: 'America/Chicago',
|
|
40
|
-
standard: { name: 'Central Standard Time', abbrev: 'CST' },
|
|
41
|
-
daylight: { name: 'Central Daylight Time', abbrev: 'CDT' }
|
|
42
|
-
}
|
|
43
|
-
]*/
|
|
17
|
+
import tzSoft from 'timezone-soft'
|
|
18
|
+
|
|
19
|
+
const matches = tzSoft('milwaukee')
|
|
20
|
+
matches[0].iana // 'America/Chicago'
|
|
44
21
|
```
|
|
45
22
|
|
|
46
|
-
|
|
47
|
-
<img height="25px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/>
|
|
23
|
+
People are not often aware of timezone [IANA IDs](https://www.iana.org/time-zones), and tend to use informal schemes to refer to timezones - things like `'PST'`, `'eastern time'`, `'vancouver bc'`, and `'china'`.
|
|
48
24
|
|
|
49
|
-
|
|
25
|
+
These names have cultural overlap, and their meaning can depend on the date.
|
|
50
26
|
|
|
51
|
-
|
|
27
|
+
This library applies opinionated heuristics to help turn this user-input into ranked matching IANA candidates.
|
|
52
28
|
|
|
53
|
-
|
|
29
|
+
Originally built for [spacetime](https://github.com/spencermountain/spacetime),
|
|
30
|
+
and formerly called `timezone-soft-informal`. This is a compressed dictionary of lookup terms for timezone ids, and some basic ranking heuristics when >1 results.
|
|
54
31
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
- in Africa: **EAT, CAT, WAST**...
|
|
58
|
-
- in Australia: **AWST, AEDT, ACST**...
|
|
32
|
+
<!-- spacer -->
|
|
33
|
+
<img height="25px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/>
|
|
59
34
|
|
|
60
|
-
|
|
35
|
+
<div align="center">
|
|
36
|
+
<img src="https://cloud.githubusercontent.com/assets/399657/23590290/ede73772-01aa-11e7-8915-181ef21027bc.png" />
|
|
37
|
+
</div>
|
|
61
38
|
|
|
62
|
-
|
|
39
|
+
### Usage
|
|
40
|
+
```js
|
|
41
|
+
const tzSoft = require('timezone-soft') //commonjs supported
|
|
63
42
|
|
|
64
|
-
|
|
43
|
+
tzSoft('EST')[0].iana // 'America/New_York'
|
|
44
|
+
tzSoft('central')[0].iana // 'America/Chicago'
|
|
45
|
+
tzSoft('venezuela')[0].iana // 'America/Caracas'
|
|
46
|
+
tzSoft('south east asia')[0].iana // 'Asia/Bangkok'
|
|
47
|
+
```
|
|
65
48
|
|
|
66
|
-
|
|
67
|
-
<img height="15px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/>
|
|
49
|
+
`tzSoft(input: string)`
|
|
68
50
|
|
|
69
|
-
|
|
51
|
+
This returns an array of matching timezone objects, ordered by preference. An empty or
|
|
52
|
+
unrecognized string returns `[]`
|
|
70
53
|
|
|
71
|
-
|
|
54
|
+
A match looks like this:
|
|
55
|
+
```js
|
|
56
|
+
{
|
|
57
|
+
name: 'Central Time',
|
|
58
|
+
iana: 'America/Chicago',
|
|
59
|
+
standard: {
|
|
60
|
+
name: 'Central Standard Time',
|
|
61
|
+
abbr: 'CST',
|
|
62
|
+
offset: -6
|
|
63
|
+
},
|
|
64
|
+
daylight: {
|
|
65
|
+
name: 'Central Daylight Time',
|
|
66
|
+
abbr: 'CDT',
|
|
67
|
+
offset: -5,
|
|
68
|
+
start: '2nd-sun-mar-2h',
|
|
69
|
+
end: '1st-sun-nov-2h'
|
|
70
|
+
},
|
|
71
|
+
long: '(UTC-06:00) Central Time (US & Canada)'
|
|
72
|
+
}
|
|
73
|
+
```
|
|
72
74
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
- '_Israeli Stardard Time_'
|
|
75
|
+
Offsets are hours east of UTC; negative values are west of UTC. `daylight` can be
|
|
76
|
+
`null`.
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
`start` and `end` values are descriptive rule strings.
|
|
78
79
|
|
|
79
|
-
Both Winnipeg and Mexico City are **CST**, but have a much different DST schedule:
|
|
80
|
-

|
|
81
80
|
|
|
82
|
-
|
|
81
|
+
## Ambiguous inputs
|
|
83
82
|
|
|
84
|
-
|
|
83
|
+
Abbreviations can describe several places. For example:
|
|
85
84
|
|
|
86
|
-
|
|
85
|
+
```js
|
|
86
|
+
soft('IST').map(zone => zone.iana)
|
|
87
|
+
// ['Asia/Kolkata', 'Asia/Jerusalem', 'Europe/Dublin', 'Asia/Colombo']
|
|
88
|
+
```
|
|
87
89
|
|
|
88
|
-
|
|
90
|
+
Explicit IANA IDs containing `/` are resolved case-insensitively through the pinned
|
|
91
|
+
IANA **2026d** Zone/Link table before informal matching. Unknown IDs are not guessed
|
|
92
|
+
from their city component. A recognized ID without bundled display metadata returns
|
|
93
|
+
`[]`. Curated non-IANA phrases containing `/` can still match registered aliases.
|
|
89
94
|
|
|
90
|
-
|
|
95
|
+
All returned IDs use that table's canonical targets. For example, `Europe/Kiev`
|
|
96
|
+
returns `Europe/Kyiv`, `Asia/Kashgar` returns `Asia/Urumqi` (UTC+6, distinct from
|
|
97
|
+
Shanghai's UTC+8), and `America/Yellowknife` returns `America/Edmonton`.
|
|
98
|
+
This policy uses the main IANA files plus `backward`, not the optional `backzone`
|
|
99
|
+
historical split. Ordinary abbreviations such as `EST` remain informal queries.
|
|
91
100
|
|
|
92
|
-
|
|
93
|
-
|
|
101
|
+
Alias matches are sorted by
|
|
102
|
+
the number of packed aliases associated with each zone, descending. Ties preserve
|
|
103
|
+
insertion order in the source data. Canonicalization then merges duplicate targets
|
|
104
|
+
while preserving their first occurrence. This is a heuristic, not a population ranking
|
|
105
|
+
or a confidence score; adding aliases can change the preferred result.
|
|
94
106
|
|
|
95
|
-
|
|
107
|
+
Show all candidates when ambiguity matters, or ask for a city or IANA ID. The
|
|
108
|
+
library does not use the user's location to choose a result. Regression fixtures
|
|
109
|
+
cover the ordering of `CST`, `IST`, and `BST`.
|
|
110
|
+
|
|
111
|
+
## Combined lookup strings
|
|
112
|
+
|
|
113
|
+
When the whole string does not match, commas and parentheses split it into
|
|
114
|
+
additional lookups using the existing aliases:
|
|
96
115
|
|
|
97
116
|
```js
|
|
98
|
-
|
|
117
|
+
soft('Springfield, Missouri')[0].iana // 'America/Chicago' (matches Missouri)
|
|
118
|
+
soft('Springfield (Missouri)')[0].iana // 'America/Chicago'
|
|
119
|
+
soft('Toronto, Ontario, Canada')[0].iana // 'America/Toronto'
|
|
120
|
+
soft('CST China')[0].iana // 'Asia/Shanghai'
|
|
121
|
+
```
|
|
99
122
|
|
|
100
|
-
|
|
101
|
-
|
|
123
|
+
Recognized parts are intersected, preserving the first part's result order.
|
|
124
|
+
Unknown comma-separated or parenthesized parts are ignored; conflicting known
|
|
125
|
+
parts return `[]`. Without punctuation, both sides of a word-boundary split must
|
|
126
|
+
match, so `Springfield Missouri` still returns `[]` while `CST China` resolves.
|
|
102
127
|
|
|
103
|
-
|
|
104
|
-
|
|
128
|
+
These are alias fallbacks, not geographic validation. No additional city/country
|
|
129
|
+
dataset is stored: the Springfield examples resolve through `Missouri`, not through
|
|
130
|
+
a Springfield city record. Existing whole-string matches take precedence.
|
|
105
131
|
|
|
106
|
-
|
|
107
|
-
// 'America/Caracas'
|
|
132
|
+
## UTC and GMT offsets
|
|
108
133
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
134
|
+
`UTC` (including lowercase or surrounding whitespace) resolves only to `Etc/UTC`,
|
|
135
|
+
with abbreviation `UTC` and name `Coordinated Universal Time`. The aliases `UCT`,
|
|
136
|
+
`universal`, `zulu`, and `coordinated universal time` resolve to the same record.
|
|
137
|
+
`GMT` resolves to `Etc/GMT`. Geographic aliases cannot outrank these inputs.
|
|
112
138
|
|
|
113
|
-
|
|
139
|
+
Whole-hour offsets from UTC-12 through UTC+14 are supported:
|
|
114
140
|
|
|
115
141
|
```js
|
|
116
|
-
|
|
142
|
+
soft('UTC+0')[0].iana // 'Etc/GMT'
|
|
143
|
+
soft('UTC+14')[0].iana // 'Etc/GMT-14'
|
|
144
|
+
soft('-5h')[0].iana // 'Etc/GMT+5'
|
|
117
145
|
```
|
|
118
146
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
147
|
+
Surrounding whitespace is accepted for offset inputs. `UTC-5` means five hours
|
|
148
|
+
behind UTC. For compatibility, `GMT+5` follows the reversed IANA `Etc/GMT+5`
|
|
149
|
+
convention; its numeric offset and `long` description use the normal UTC sign.
|
|
150
|
+
`Etc/GMT+13` and `Etc/GMT+14` return `[]` because they are not IANA IDs;
|
|
151
|
+
`Etc/GMT-13` and `Etc/GMT-14` remain valid.
|
|
124
152
|
|
|
125
|
-
|
|
153
|
+
Fractional offset strings such as `UTC+5:30` return `[]`: the IANA fixed-offset
|
|
154
|
+
`Etc/GMT` IDs have whole-hour precision. Use a named zone such as `Asia/Kolkata` or
|
|
155
|
+
`india` instead. See the [IANA definitions](https://data.iana.org/time-zones/tzdb/etcetera).
|
|
126
156
|
|
|
127
|
-
|
|
128
|
-
<img height="25px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/>
|
|
157
|
+
## Dates and daylight saving time
|
|
129
158
|
|
|
130
|
-
|
|
159
|
+
This package finds timezone names and supplies curated display metadata. Its
|
|
160
|
+
bundled DST rules are approximate, are not versioned by year, and are not suitable
|
|
161
|
+
for calculating historical or future transitions. See the
|
|
162
|
+
[data notes](data/README.md) for the rule syntax and provenance limitations.
|
|
131
163
|
|
|
132
|
-
|
|
133
|
-
|
|
164
|
+
Use a date-aware timezone library to determine the applicable abbreviation at a
|
|
165
|
+
specific instant. For example, with [spacetime](https://github.com/spencermountain/timezone-soft):
|
|
134
166
|
|
|
135
167
|
```js
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (display.daylight && s.isDST()) {
|
|
145
|
-
show = display.daylight.abbrev
|
|
168
|
+
import spacetime from 'spacetime'
|
|
169
|
+
import tzSoft from 'timezone-soft'
|
|
170
|
+
|
|
171
|
+
const display = tzSoft('montreal')[0]
|
|
172
|
+
if (display) {
|
|
173
|
+
const now = spacetime.now(display.iana)
|
|
174
|
+
const info = now.isDST() && display.daylight ? display.daylight : display.standard
|
|
175
|
+
console.log(now.time() + ' ' + info.abbr)
|
|
146
176
|
}
|
|
147
|
-
console.log(s.time() + ' ' + show)
|
|
148
|
-
// '4:20pm EDT'
|
|
149
177
|
```
|
|
150
178
|
|
|
151
|
-
|
|
152
|
-
|
|
179
|
+
The `standard` and `daylight` fields are conventional display categories, not
|
|
180
|
+
IANA's `tm_isdst` flags. In Dublin, `standard` means winter GMT (UTC+0, Greenwich
|
|
181
|
+
Mean Time), and `daylight` means summer IST (UTC+1, Irish Standard Time). IANA's
|
|
182
|
+
native model treats Irish summer as standard and winter as negative DST; this API
|
|
183
|
+
retains its existing winter/summer arrangement for compatibility. Do not select a
|
|
184
|
+
field using a raw IANA DST flag without reconciling those conventions.
|
|
185
|
+
|
|
186
|
+
The identifier table is versioned independently of display metadata. The returned
|
|
187
|
+
metadata is only as current as this package's curated data. Coverage includes
|
|
188
|
+
`America/Ciudad_Juarez` (Mountain time with US DST rules) and
|
|
189
|
+
`America/Coyhaique` (permanent UTC−3). Runtime coverage checks flag new missing
|
|
190
|
+
records.
|
|
191
|
+
|
|
153
192
|
|
|
154
|
-
|
|
193
|
+
## TypeScript
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
import tzSoft, { type DisplayFormat } from 'timezone-soft'
|
|
197
|
+
|
|
198
|
+
const matches: DisplayFormat[] = tzSoft('montreal')
|
|
199
|
+
const zone = matches[0]
|
|
200
|
+
|
|
201
|
+
if (zone) {
|
|
202
|
+
console.log(zone.iana) // 'America/Toronto'
|
|
203
|
+
console.log(zone.standard.abbr) // 'EST'
|
|
204
|
+
console.log(zone.daylight?.abbr) // 'EDT'; undefined for zones without DST
|
|
205
|
+
} else {
|
|
206
|
+
console.log('No matching timezone')
|
|
207
|
+
}
|
|
208
|
+
```
|
|
155
209
|
|
|
156
210
|
### See also
|
|
157
211
|
|
|
158
|
-
- [
|
|
212
|
+
- [city-timezones](https://github.com/kevinroberts/city-timezones) — find IANA timezones by city, state, or country.
|
|
213
|
+
- [@vvo/tzdb](https://github.com/vvo/tzdb) — timezone data with friendly names and major cities for timezone selectors.
|
|
214
|
+
- [@coroboros/location-timezone](https://github.com/elysiumphase/node-location-timezone) — timezone lookups by city, country, or capital.
|
|
215
|
+
- [chrono-node](https://github.com/wanasit/chrono) — natural-language date parsing with timezone abbreviation support.
|
|
216
|
+
- [tz-lookup](https://github.com/darkskyapp/tz-lookup-oss) — approximate timezone lookup from latitude and longitude.
|
|
217
|
+
- [TimeZoneNames](https://github.com/mattjohnsonpint/TimeZoneNames) for .NET.
|
|
159
218
|
|
|
160
|
-
MIT
|
|
219
|
+
MIT, PRs welcome
|