Upstream spencermountain/spacetime state of the touched files before fe90cae667
This commit is contained in:
1 parent
081c965030
commit
d47824c8f3
6 files changed
+2406
No files matched your search
@@ -0,0 +1,212 @@
|
|||||||
|
// CLI orchestration: read zoneinfo, normalize records, report differences, then write.
|
||||||
|
import { execFileSync } from 'node:child_process'
|
||||||
|
import {
|
||||||
|
existsSync,
|
||||||
|
readFileSync,
|
||||||
|
readdirSync,
|
||||||
|
renameSync,
|
||||||
|
statSync,
|
||||||
|
unlinkSync,
|
||||||
|
writeFileSync
|
||||||
|
} from 'node:fs'
|
||||||
|
import { dirname, join, resolve } from 'node:path'
|
||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
import data from '../../zonefile/iana.js'
|
||||||
|
import aliases from '../../zonefile/aliases.js'
|
||||||
|
import { parseIntervals, normalizeZone } from './lib.js'
|
||||||
|
import { printHeader, printReport, printResult, printError, printHelp } from './report.js'
|
||||||
|
|
||||||
|
const root = fileURLToPath(new URL('../../', import.meta.url))
|
||||||
|
// Directory-only legacy keys may be retained with --allow-unsupported.
|
||||||
|
// Missing or malformed files remain fatal because their timezone state is unknown.
|
||||||
|
export class UnsupportedZoneError extends Error {}
|
||||||
|
|
||||||
|
export const parseArgs = (args) => {
|
||||||
|
const options = {
|
||||||
|
year: new Date().getUTCFullYear(),
|
||||||
|
zoneinfoDir: '/usr/share/zoneinfo',
|
||||||
|
check: false,
|
||||||
|
verbose: false,
|
||||||
|
allowUnsupported: false
|
||||||
|
}
|
||||||
|
for (let i = 0; i < args.length; i += 1) {
|
||||||
|
const arg = args[i]
|
||||||
|
if (arg === '--check') {
|
||||||
|
options.check = true
|
||||||
|
} else if (arg === '--verbose') {
|
||||||
|
options.verbose = true
|
||||||
|
} else if (arg === '--allow-unsupported') {
|
||||||
|
options.allowUnsupported = true
|
||||||
|
} else if (arg === '--help') {
|
||||||
|
options.help = true
|
||||||
|
} else if (['--year', '--zoneinfo-dir', '--output'].includes(arg)) {
|
||||||
|
const value = args[++i]
|
||||||
|
if (!value || value.startsWith('--')) {
|
||||||
|
throw new Error('Missing value for ' + arg)
|
||||||
|
}
|
||||||
|
if (arg === '--year') {
|
||||||
|
if (!/^\d{4}$/.test(value) || Number(value) < 1900 || Number(value) > 9998) {
|
||||||
|
throw new Error('Year must be 1900–9998')
|
||||||
|
}
|
||||||
|
options.year = Number(value)
|
||||||
|
} else {
|
||||||
|
options[arg === '--output' ? 'output' : 'zoneinfoDir'] = resolve(value)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('Unknown option: ' + arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
options.output ||= join(root, `zonefile.${options.year}.js`)
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
|
// Library keys are lowercase; zoneinfo paths are case-sensitive on many systems.
|
||||||
|
// Apply known aliases, then resolve every component using its actual spelling.
|
||||||
|
export const resolveZone = (directory, name) => {
|
||||||
|
name = aliases[name] || name
|
||||||
|
let path = directory
|
||||||
|
for (const component of name.split('/')) {
|
||||||
|
if (!component || component === '.' || component === '..') {
|
||||||
|
throw new Error('Invalid zone name')
|
||||||
|
}
|
||||||
|
const matches = readdirSync(path).filter(
|
||||||
|
(entry) => entry.toLowerCase() === component.toLowerCase()
|
||||||
|
)
|
||||||
|
if (matches.length !== 1) {
|
||||||
|
throw new Error('Missing or ambiguous zone: ' + name)
|
||||||
|
}
|
||||||
|
path = join(path, matches[0])
|
||||||
|
}
|
||||||
|
const stats = statSync(path)
|
||||||
|
// zdump can silently report UTC for a directory. Reject it before invocation.
|
||||||
|
if (stats.isDirectory()) {
|
||||||
|
throw Object.assign(new UnsupportedZoneError('Zone name resolves to a directory, not a timezone: ' + name), {
|
||||||
|
details: [
|
||||||
|
`Resolved path: ${path}`,
|
||||||
|
`Available entries: ${readdirSync(path).sort().join(', ')}`,
|
||||||
|
'Choose a specific timezone or define an explicit library alias; a directory has no offset or transitions.'
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (!stats.isFile() || readFileSync(path).subarray(0, 4).toString() !== 'TZif') {
|
||||||
|
throw new Error('Not a compiled TZif file: ' + name)
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
// macOS provides +VERSION; common Linux distributions embed it in tzdata.zi.
|
||||||
|
// File modification times are not reliable tzdata release identifiers.
|
||||||
|
const sourceVersion = (directory) => {
|
||||||
|
for (const name of ['+VERSION', 'tzdata.zi']) {
|
||||||
|
const path = join(directory, name)
|
||||||
|
if (existsSync(path)) {
|
||||||
|
const text = readFileSync(path, 'utf8')
|
||||||
|
const version = name === '+VERSION' ? text.trim() : /^# version (\S+)/m.exec(text)?.[1]
|
||||||
|
if (version) {
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'unknown'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inject the reader so callers can supply fixtures without invoking zdump.
|
||||||
|
// Build a fresh result and retain diagnostic context without mutating source data.
|
||||||
|
export const updateZones = (zones, year, readZone) => {
|
||||||
|
const result = {}
|
||||||
|
const changes = []
|
||||||
|
const unsupported = []
|
||||||
|
for (const [name, previous] of Object.entries(zones)) {
|
||||||
|
// Acquisition and parsing errors must fail, even with --allow-unsupported.
|
||||||
|
let intervals
|
||||||
|
try {
|
||||||
|
intervals = parseIntervals(readZone(name))
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof UnsupportedZoneError) {
|
||||||
|
unsupported.push({ name, reason: error.message, previous, details: error.details })
|
||||||
|
result[name] = { ...previous }
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
throw new Error(`${name}: ${error.message}`)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
result[name] = normalizeZone(intervals, previous, name, year)
|
||||||
|
} catch (error) {
|
||||||
|
unsupported.push({ name, reason: error.message, previous, intervals, details: error.details })
|
||||||
|
result[name] = { ...previous }
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (JSON.stringify(previous) !== JSON.stringify(result[name])) {
|
||||||
|
changes.push({ name, before: previous, after: result[name] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { result, changes, unsupported }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const main = (args = process.argv.slice(2)) => {
|
||||||
|
const options = parseArgs(args)
|
||||||
|
if (options.help) {
|
||||||
|
printHelp()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { year, zoneinfoDir } = options
|
||||||
|
const version = sourceVersion(zoneinfoDir)
|
||||||
|
const total = Object.keys(data).length
|
||||||
|
printHeader({ ...options, version, total })
|
||||||
|
const { result, changes, unsupported } = updateZones(data, year, (name) => {
|
||||||
|
const path = resolveZone(zoneinfoDir, name)
|
||||||
|
// Bound extraction to one UTC year; argument arrays avoid shell interpretation.
|
||||||
|
// Interval output includes an initial offset even for zones with no transitions.
|
||||||
|
return execFileSync('zdump', ['-i', '-c', `${year},${year + 1}`, path], {
|
||||||
|
encoding: 'utf8',
|
||||||
|
timeout: 10000,
|
||||||
|
maxBuffer: 1024 * 1024,
|
||||||
|
env: { ...process.env, LC_ALL: 'C' },
|
||||||
|
stdio: ['ignore', 'pipe', 'pipe']
|
||||||
|
})
|
||||||
|
})
|
||||||
|
printReport({ changes, unsupported, total, verbose: options.verbose })
|
||||||
|
// Check mode and the unsupported-zone gate must run before any file write.
|
||||||
|
if (options.check) {
|
||||||
|
if (changes.length > 0 || unsupported.length > 0) {
|
||||||
|
process.exitCode = 1
|
||||||
|
}
|
||||||
|
printResult(
|
||||||
|
changes.length > 0 || unsupported.length > 0 ? 'Check needs attention. No files written.' : 'Check passed. No files written.',
|
||||||
|
Boolean(changes.length > 0 || unsupported.length > 0)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (unsupported.length > 0 && !options.allowUnsupported) {
|
||||||
|
throw new Error(
|
||||||
|
'No output written. Resolve unsupported zones or explicitly preserve them with --allow-unsupported.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const source = JSON.stringify({
|
||||||
|
year,
|
||||||
|
tzdata: version,
|
||||||
|
unsupported: unsupported.map((o) => o.name)
|
||||||
|
})
|
||||||
|
const text = `// Generated by scripts/tz/update.js: ${source}\nexport default ${JSON.stringify(result, null, 2)}\n`
|
||||||
|
// Rename within the destination directory so readers never see a partial file.
|
||||||
|
// Only remove a temporary file created by this run (exclusive creation may fail).
|
||||||
|
const temporary = join(dirname(options.output), `.zonefile-${process.pid}.tmp`)
|
||||||
|
let created = false
|
||||||
|
try {
|
||||||
|
writeFileSync(temporary, text, { encoding: 'utf8', flag: 'wx' })
|
||||||
|
created = true
|
||||||
|
renameSync(temporary, options.output)
|
||||||
|
} finally {
|
||||||
|
if (created && existsSync(temporary)) {
|
||||||
|
unlinkSync(temporary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printResult(`Wrote ${options.output}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
main()
|
||||||
|
} catch (error) {
|
||||||
|
printError(error.message)
|
||||||
|
process.exitCode = 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import Spacetime from './spacetime.js'
|
||||||
|
import whereIts from './whereIts.js'
|
||||||
|
import version from './_version.js'
|
||||||
|
|
||||||
|
const main = (input, tz, options) => new Spacetime(input, tz, options)
|
||||||
|
|
||||||
|
// set all properties of a given 'today' object
|
||||||
|
const setToday = function (s) {
|
||||||
|
const today = s._today || {}
|
||||||
|
Object.keys(today).forEach((k) => {
|
||||||
|
s = s[k](today[k])
|
||||||
|
})
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
//some helper functions on the main method
|
||||||
|
main.now = (tz, options) => {
|
||||||
|
let s = new Spacetime(new Date().getTime(), tz, options)
|
||||||
|
s = setToday(s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
main.today = (tz, options) => {
|
||||||
|
let s = new Spacetime(new Date().getTime(), tz, options)
|
||||||
|
s = setToday(s)
|
||||||
|
return s.startOf('day')
|
||||||
|
}
|
||||||
|
main.tomorrow = (tz, options) => {
|
||||||
|
let s = new Spacetime(new Date().getTime(), tz, options)
|
||||||
|
s = setToday(s)
|
||||||
|
return s.add(1, 'day').startOf('day')
|
||||||
|
}
|
||||||
|
main.yesterday = (tz, options) => {
|
||||||
|
let s = new Spacetime(new Date().getTime(), tz, options)
|
||||||
|
s = setToday(s)
|
||||||
|
return s.subtract(1, 'day').startOf('day')
|
||||||
|
}
|
||||||
|
main.fromUnixSeconds = (secs, tz, options) => {
|
||||||
|
return new Spacetime(secs * 1000, tz, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
main.extend = function (obj = {}) {
|
||||||
|
Object.keys(obj).forEach((k) => {
|
||||||
|
Spacetime.prototype[k] = obj[k]
|
||||||
|
})
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
main.timezones = function () {
|
||||||
|
const s = new Spacetime()
|
||||||
|
return s.timezones
|
||||||
|
}
|
||||||
|
main.max = function (tz, options) {
|
||||||
|
const s = new Spacetime(null, tz, options)
|
||||||
|
s.epoch = 8640000000000000
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
main.min = function (tz, options) {
|
||||||
|
const s = new Spacetime(null, tz, options)
|
||||||
|
s.epoch = -8640000000000000
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
//find tz by time
|
||||||
|
main.whereIts = whereIts
|
||||||
|
main.version = version
|
||||||
|
|
||||||
|
//aliases:
|
||||||
|
main.plugin = main.extend
|
||||||
|
export default main
|
||||||
Vendored
+94
@@ -0,0 +1,94 @@
|
|||||||
|
import type { Spacetime, ParsableDate, TimezoneSet } from './types.js'
|
||||||
|
|
||||||
|
export interface SpacetimeConstructorOptions {
|
||||||
|
/** javascript dates use millisecond-epochs, instead of second-epochs, like some other languages. This is a common bug, and by default spacetime warns if you set an epoch within January 1970. to disable set to true */
|
||||||
|
silent?: boolean
|
||||||
|
|
||||||
|
/** the day number, between 0-6, that the week starts on. (Sunday is 0) */
|
||||||
|
weekStart?: number
|
||||||
|
|
||||||
|
/** pass true to change parsing behaviour to dd/mm/yyyy. By default American interpretation will be used. */
|
||||||
|
dmy?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SpacetimeConstructor {
|
||||||
|
/**
|
||||||
|
* @param epoch Timestamp in **milliseconds**. If you are getting a date in 1970, you are likely using seconds.
|
||||||
|
* @param timezone Optional timezone. If omitted uses the browser timezone.
|
||||||
|
* @param options Options for silencing warnings.
|
||||||
|
*/
|
||||||
|
(epoch: number, timezone?: string, options?: SpacetimeConstructorOptions): Spacetime
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param arr Date values in an array such as [yyyy, m, d].
|
||||||
|
*
|
||||||
|
* ```typescript
|
||||||
|
* let d = spacetime([2011, 1, 15]);
|
||||||
|
* d.format('nice-year'); // "Feb 15th, 2011"
|
||||||
|
* ```
|
||||||
|
* @param timezone Optional timezone. If omitted uses the browser timezone.
|
||||||
|
* @param options Options for silencing warnings.
|
||||||
|
*/
|
||||||
|
(arr: Array<number>, timezone?: string, options?: SpacetimeConstructorOptions): Spacetime
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param obj Date as a key-value object. ex {month:'june', year:2019}
|
||||||
|
* @param timezone Optional timezone. If omitted uses the browser timezone.
|
||||||
|
* @param options Options for silencing warnings.
|
||||||
|
*/
|
||||||
|
(
|
||||||
|
obj: { [unit: string]: string | number },
|
||||||
|
timezone?: string,
|
||||||
|
options?: SpacetimeConstructorOptions
|
||||||
|
): Spacetime
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param iso Date as an iso string. ex '2017-04-03T08:00:00'
|
||||||
|
* @param timezone Optional timezone. If omitted uses the browser timezone.
|
||||||
|
* @param options Options for silencing warnings.
|
||||||
|
*/
|
||||||
|
(iso: string, timezone?: string, options?: SpacetimeConstructorOptions): Spacetime
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param parsableDate a parsable date like object
|
||||||
|
* @param timezone Optional timezone. If omitted uses the browser timezone.
|
||||||
|
* @param options Options for silencing warnings.
|
||||||
|
*/
|
||||||
|
(
|
||||||
|
parsableDate?: ParsableDate | null,
|
||||||
|
timezone?: string,
|
||||||
|
options?: SpacetimeConstructorOptions
|
||||||
|
): Spacetime
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SpacetimeStatic extends SpacetimeConstructor {
|
||||||
|
/** set as the current time */
|
||||||
|
now: (timezone?: string, options?: SpacetimeConstructorOptions) => Spacetime
|
||||||
|
|
||||||
|
/** set as this morning */
|
||||||
|
today: (timezone?: string, options?: SpacetimeConstructorOptions) => Spacetime
|
||||||
|
|
||||||
|
/** set as tomorrow morning */
|
||||||
|
tomorrow: (timezone?: string, options?: SpacetimeConstructorOptions) => Spacetime
|
||||||
|
|
||||||
|
/** set as yesterday morning */
|
||||||
|
yesterday: (timezone?: string, options?: SpacetimeConstructorOptions) => Spacetime
|
||||||
|
|
||||||
|
/** set epoch using seconds instead of milliseconds */
|
||||||
|
fromUnixSeconds: (seconds: number, timezone?: string, options?: SpacetimeConstructorOptions) => Spacetime
|
||||||
|
|
||||||
|
/** Extend Spacetime with a custom function/object. */
|
||||||
|
extend: (extension: { [key: string]: any } | {}) => SpacetimeStatic
|
||||||
|
|
||||||
|
/** get a list of current timezones and their offsets */
|
||||||
|
timezones: () => TimezoneSet
|
||||||
|
|
||||||
|
/** list timezones by their time */
|
||||||
|
whereIts: (a: string, b?: string) => string[]
|
||||||
|
|
||||||
|
/** set as earliest-possible date */
|
||||||
|
min: (timezone?: string, options?: SpacetimeConstructorOptions) => Spacetime
|
||||||
|
|
||||||
|
/** set as furthest-possible future date */
|
||||||
|
max: (timezone?: string, options?: SpacetimeConstructorOptions) => Spacetime
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
export default {
|
||||||
|
"9|s": "2/dili,2/jayapura",
|
||||||
|
"9|n": "2/chita,2/khandyga,2/pyongyang,2/seoul,2/tokyo,2/yakutsk,11/palau,japan,rok",
|
||||||
|
"9.5|s|04/05:03->10/04:02": "4/adelaide,4/broken_hill,4/south,4/yancowinna",
|
||||||
|
"9.5|s": "4/darwin,4/north",
|
||||||
|
"8|s": "12/casey,2/makassar,4/perth,2/ujung_pandang,4/west",
|
||||||
|
"8|n": "2/brunei,2/hong_kong,2/irkutsk,2/kuala_lumpur,2/kuching,2/macau,2/manila,2/shanghai,2/singapore,2/taipei,2/ulaanbaatar,2/chongqing,2/chungking,2/harbin,2/macao,2/ulan_bator,2/choibalsan,hongkong,prc,roc,singapore",
|
||||||
|
"8.75|s": "4/eucla",
|
||||||
|
"7|s": "12/davis,2/jakarta,2/pontianak,9/christmas",
|
||||||
|
"7|n": "2/bangkok,2/barnaul,2/hovd,2/krasnoyarsk,2/novokuznetsk,2/novosibirsk,2/phnom_penh,2/ho_chi_minh,2/tomsk,2/vientiane,2/saigon",
|
||||||
|
"6|s": "9/chagos",
|
||||||
|
"6|n": "2/bishkek,2/dhaka,2/omsk,2/thimphu,2/urumqi,2/dacca,2/kashgar,2/thimbu",
|
||||||
|
"6.5|s": "9/cocos",
|
||||||
|
"6.5|n": "2/yangon,2/rangoon",
|
||||||
|
"5|s": "12/mawson,12/vostok,9/kerguelen",
|
||||||
|
"5|n": "2/almaty,2/aqtau,2/aqtobe,2/ashgabat,2/atyrau,2/dushanbe,2/karachi,2/oral,2/qyzylorda,2/qostanay,2/samarkand,2/tashkent,2/yekaterinburg,9/maldives,2/ashkhabad",
|
||||||
|
"5.75|n": "2/kathmandu,2/katmandu",
|
||||||
|
"5.5|n": "2/kolkata,2/colombo,2/calcutta",
|
||||||
|
"4|s": "9/mahe,9/mauritius,9/reunion",
|
||||||
|
"4|n": "2/baku,2/dubai,2/muscat,2/tbilisi,2/yerevan,8/astrakhan,8/samara,8/saratov,8/ulyanovsk",
|
||||||
|
"4.5|n": "2/kabul",
|
||||||
|
"3|s": "0/dar_es_salaam,0/nairobi,12/syowa,9/antananarivo,9/comoro,9/mayotte",
|
||||||
|
"3|n|04/24:00->10/29:24": "0/cairo,egypt",
|
||||||
|
"3|n|03/29:03->10/25:04": "2/famagusta,2/nicosia,8/athens,8/bucharest,8/chisinau,8/helsinki,8/kyiv,8/mariehamn,8/riga,8/sofia,8/tallinn,8/uzhgorod,8/vilnius,8/zaporozhye,8/nicosia,8/tiraspol,8/kiev,eet",
|
||||||
|
"3|n|03/29:00->10/24:24": "2/beirut",
|
||||||
|
"3|n|03/28:02->10/24:02": "2/gaza,2/hebron",
|
||||||
|
"3|n|03/27:02->10/25:02": "2/jerusalem,2/tel_aviv,israel",
|
||||||
|
"3|n": "0/addis_ababa,0/asmara,0/asmera,0/djibouti,0/kampala,0/mogadishu,2/aden,2/amman,2/baghdad,2/bahrain,2/damascus,2/kuwait,2/qatar,2/riyadh,8/istanbul,8/kirov,8/minsk,8/moscow,8/simferopol,8/volgograd,2/volgograd,2/istanbul,turkey,w-su",
|
||||||
|
"3.5|n": "2/tehran,iran",
|
||||||
|
"2|s": "0/blantyre,0/bujumbura,0/gaborone,0/harare,0/johannesburg,0/kigali,0/lubumbashi,0/lusaka,0/maputo,0/maseru,0/mbabane,0/windhoek",
|
||||||
|
"2|n|03/29:02->10/25:03": "0/ceuta,arctic/longyearbyen,8/amsterdam,8/andorra,8/belgrade,8/berlin,8/bratislava,8/brussels,8/budapest,8/busingen,8/copenhagen,8/gibraltar,8/ljubljana,8/luxembourg,8/madrid,8/malta,8/monaco,8/oslo,8/paris,8/podgorica,8/prague,8/rome,8/san_marino,8/sarajevo,8/skopje,8/stockholm,8/tirane,8/vaduz,8/vatican,8/vienna,8/warsaw,8/zagreb,8/zurich,3/jan_mayen,poland,cet,met",
|
||||||
|
"2|n|03/29:01->10/25:03": "12/troll",
|
||||||
|
"2|n": "0/juba,0/khartoum,0/tripoli,8/kaliningrad,libya",
|
||||||
|
"1|s": "0/brazzaville,0/kinshasa,0/luanda",
|
||||||
|
"1|n|03/29:01->10/25:02": "3/canary,3/faroe,3/madeira,8/dublin,8/guernsey,8/isle_of_man,8/jersey,8/lisbon,8/london,3/faeroe,eire,8/belfast,gb-eire,gb,portugal,wet",
|
||||||
|
"1|n": "0/algiers,0/bangui,0/douala,0/lagos,0/libreville,0/malabo,0/ndjamena,0/niamey,0/porto-novo,0/tunis",
|
||||||
|
"14|n": "11/kiritimati",
|
||||||
|
"13|s": "11/apia,11/enderbury,11/kanton,11/fakaofo,11/tongatapu",
|
||||||
|
"12|s|04/05:03->09/27:02": "12/mcmurdo,11/auckland,12/south_pole,nz",
|
||||||
|
"12|s": "11/fiji,11/funafuti,11/nauru,11/wallis",
|
||||||
|
"12|n": "2/anadyr,2/kamchatka,11/kwajalein,11/majuro,11/tarawa,11/wake,kwajalein",
|
||||||
|
"12.75|s|04/05:03:45->09/27:02:45": "11/chatham,nz-chat",
|
||||||
|
"11|s|04/05:03->10/04:02": "11/norfolk",
|
||||||
|
"11|s": "11/bougainville,11/efate,11/guadalcanal,11/noumea",
|
||||||
|
"11|n": "2/magadan,2/sakhalin,2/srednekolymsk,11/kosrae,11/pohnpei,11/ponape",
|
||||||
|
"10|s|04/05:03->10/04:02": "12/macquarie,4/currie,4/hobart,4/melbourne,4/sydney,4/act,4/canberra,4/nsw,4/tasmania,4/victoria",
|
||||||
|
"10|s": "12/dumontdurville,4/brisbane,4/lindeman,11/port_moresby,4/queensland",
|
||||||
|
"10|n": "2/ust-nera,2/vladivostok,11/guam,11/saipan,11/chuuk,11/truk,11/yap",
|
||||||
|
"10.5|s|04/05:02->10/04:02": "4/lord_howe,4/lhi",
|
||||||
|
"0|s|02/15:03->09/20:02": "0/casablanca",
|
||||||
|
"0|s|02/15:03->03/22:02": "0/el_aaiun",
|
||||||
|
"0|s": "3/st_helena",
|
||||||
|
"0|n|03/29:00->10/25:01": "3/azores",
|
||||||
|
"0|n": "0/abidjan,0/accra,0/bamako,0/banjul,0/bissau,0/conakry,0/dakar,0/freetown,0/lome,0/monrovia,0/nouakchott,0/ouagadougou,0/sao_tome,1/danmarkshavn,3/reykjavik,13/gmt,13/utc,0/timbuktu,13/greenwich,13/uct,13/universal,13/zulu,gmt-0,gmt+0,gmt0,greenwich,iceland,uct,universal,utc,zulu,13/unknown,factory",
|
||||||
|
"-9|s": "11/gambier",
|
||||||
|
"-9|n|03/08:02->11/01:02": "1/adak,1/atka,us/aleutian",
|
||||||
|
"-9.5|s": "11/marquesas",
|
||||||
|
"-8|s": "11/pitcairn",
|
||||||
|
"-8|n|03/08:02->11/01:02": "1/anchorage,1/juneau,1/metlakatla,1/nome,1/sitka,1/yakutat,us/alaska",
|
||||||
|
"-7|n|03/08:02->12/31:23": "1/vancouver,6/pacific",
|
||||||
|
"-7|n|03/08:02->11/01:02": "1/los_angeles,1/santa_isabel,1/tijuana,1/ensenada,10/bajanorte,us/pacific-new,us/pacific,pst8pdt",
|
||||||
|
"-7|n": "1/creston,1/dawson,1/dawson_creek,1/fort_nelson,1/hermosillo,1/mazatlan,1/phoenix,1/whitehorse,6/yukon,10/bajasur,us/arizona,mst",
|
||||||
|
"-6|s|04/04:22->09/05:22": "11/easter,7/easterisland",
|
||||||
|
"-6|s": "11/galapagos",
|
||||||
|
"-6|n|03/08:02->12/31:23": "1/edmonton,1/yellowknife,6/mountain",
|
||||||
|
"-6|n|03/08:02->11/01:02": "1/boise,1/cambridge_bay,1/denver,1/inuvik,1/ciudad_juarez,1/shiprock,navajo,us/mountain,mst7mdt",
|
||||||
|
"-6|n": "1/bahia_banderas,1/belize,1/chihuahua,1/costa_rica,1/el_salvador,1/guatemala,1/managua,1/merida,1/mexico_city,1/monterrey,1/regina,1/swift_current,1/tegucigalpa,6/east-saskatchewan,6/saskatchewan,10/general",
|
||||||
|
"-5|s": "1/eirunepe,1/guayaquil,1/lima,1/rio_branco,1/porto_acre,5/acre",
|
||||||
|
"-5|n|03/08:02->11/01:02": "1/chicago,1/matamoros,1/menominee,1/north_dakota,1/ojinaga,1/rainy_river,1/rankin_inlet,1/resolute,1/winnipeg,1/indiana/knox,1/indiana/tell_city,1/north_dakota/beulah,1/north_dakota/center,1/north_dakota/new_salem,1/knox_in,6/central,us/central,us/indiana-starke,cst6cdt",
|
||||||
|
"-5|n": "1/bogota,1/cancun,1/cayman,1/coral_harbour,1/jamaica,1/panama,1/atikokan,jamaica,est",
|
||||||
|
"-4|s|04/04:24->09/06:00": "1/santiago,7/continental",
|
||||||
|
"-4|s": "1/campo_grande,1/cuiaba,1/la_paz,1/manaus,1/porto_velho,5/west",
|
||||||
|
"-4|n|03/08:02->11/01:02": "1/detroit,1/grand_turk,1/indiana,1/indianapolis,1/iqaluit,1/kentucky,1/louisville,1/montreal,1/nassau,1/new_york,1/nipigon,1/pangnirtung,1/port-au-prince,1/thunder_bay,1/toronto,1/indiana/marengo,1/indiana/petersburg,1/indiana/vevay,1/indiana/vincennes,1/indiana/winamac,1/kentucky/monticello,1/fort_wayne,1/indiana/indianapolis,1/kentucky/louisville,6/eastern,us/east-indiana,us/eastern,us/michigan,est5edt",
|
||||||
|
"-4|n|03/08:00->11/01:01": "1/havana,cuba",
|
||||||
|
"-4|n": "1/anguilla,1/antigua,1/aruba,1/barbados,1/blanc-sablon,1/boa_vista,1/caracas,1/curacao,1/dominica,1/grenada,1/guadeloupe,1/guyana,1/kralendijk,1/lower_princes,1/marigot,1/martinique,1/montserrat,1/port_of_spain,1/puerto_rico,1/santo_domingo,1/st_barthelemy,1/st_kitts,1/st_lucia,1/st_thomas,1/st_vincent,1/tortola,1/virgin",
|
||||||
|
"-3|s": "1/araguaina,1/argentina,1/asuncion,1/bahia,1/belem,1/buenos_aires,1/catamarca,1/cordoba,1/coyhaique,1/fortaleza,1/jujuy,1/maceio,1/mendoza,1/montevideo,1/punta_arenas,1/recife,1/santarem,1/sao_paulo,12/palmer,12/rothera,3/stanley,1/argentina/la_rioja,1/argentina/rio_gallegos,1/argentina/salta,1/argentina/san_juan,1/argentina/san_luis,1/argentina/tucuman,1/argentina/ushuaia,1/argentina/comodrivadavia,1/argentina/buenos_aires,1/argentina/catamarca,1/argentina/cordoba,1/argentina/jujuy,1/argentina/mendoza,1/argentina/rosario,1/rosario,5/east",
|
||||||
|
"-3|n|03/08:02->11/01:02": "1/glace_bay,1/goose_bay,1/halifax,1/moncton,1/thule,3/bermuda,6/atlantic",
|
||||||
|
"-3|n": "1/cayenne,1/paramaribo",
|
||||||
|
"-2|s": "1/noronha,3/south_georgia,5/denoronha",
|
||||||
|
"-2|n|03/08:02->11/01:02": "1/miquelon",
|
||||||
|
"-2.5|n|03/08:02->11/01:02": "1/st_johns,6/newfoundland",
|
||||||
|
"-1|n|03/28:23->10/24:24": "1/nuuk,1/scoresbysund,1/godthab",
|
||||||
|
"-1|n": "3/cape_verde",
|
||||||
|
"-11|s": "11/niue,11/pago_pago,11/samoa,us/samoa",
|
||||||
|
"-11|n": "11/midway",
|
||||||
|
"-10|s": "11/rarotonga,11/tahiti",
|
||||||
|
"-10|n": "11/honolulu,11/johnston,us/hawaii,hst"
|
||||||
|
}
|
||||||
+1897
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,47 @@
|
|||||||
|
//turn our timezone data into a small-as-possible string
|
||||||
|
import { writeFileSync } from 'node:fs'
|
||||||
|
import iana from './iana.js'
|
||||||
|
import aliases from './aliases.js'
|
||||||
|
import prefixes from './_prefixes.js'
|
||||||
|
const all = {}
|
||||||
|
|
||||||
|
// add aliases in
|
||||||
|
Object.keys(aliases).forEach((k) => {
|
||||||
|
const found = iana[aliases[k]]
|
||||||
|
if (!found) {
|
||||||
|
console.log('missing', aliases[k]) //eslint-disable-line
|
||||||
|
}
|
||||||
|
iana[k] = Object.assign({}, found)
|
||||||
|
})
|
||||||
|
|
||||||
|
//pack iana data into a [o|h] object
|
||||||
|
Object.keys(iana).forEach((k) => {
|
||||||
|
const o = iana[k]
|
||||||
|
let key = o.offset + '|' + o.hem
|
||||||
|
if (o.dst) {
|
||||||
|
key += '|' + o.dst
|
||||||
|
}
|
||||||
|
all[key] = all[key] || []
|
||||||
|
const name = k.replace(/(.*?)\//, (a, prefix) => {
|
||||||
|
const index = prefixes.indexOf(prefix)
|
||||||
|
if (index !== -1) {
|
||||||
|
return index + '/'
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
})
|
||||||
|
all[key].push(name)
|
||||||
|
})
|
||||||
|
|
||||||
|
//add-in informal abbreviations
|
||||||
|
// all = addHemisphere(all, informal.south, 's')
|
||||||
|
// all = addHemisphere(all, informal.north, 'n')
|
||||||
|
|
||||||
|
let keys = Object.keys(all)
|
||||||
|
keys = keys.sort((a, b) => (a < b ? 1 : -1))
|
||||||
|
const result = {}
|
||||||
|
keys.forEach((k) => {
|
||||||
|
result[k] = all[k].join(',')
|
||||||
|
})
|
||||||
|
|
||||||
|
// console.log(result)
|
||||||
|
writeFileSync('./zonefile/_build.js', 'export default ' + JSON.stringify(result, null, 2))
|
||||||
Reference in new issue
Block a user