From fb5ecec15c07834b3683edcf0ce56a045ecbbd9f Mon Sep 17 00:00:00 2001 From: upstream Date: Fri, 2 Oct 2026 15:56:00 +0200 Subject: [PATCH] Upstream spencermountain/spacetime state of the touched files before b6fbec9c97 --- src/timezone/index.js | 96 +++++++++++++++++++++++++++ src/whereIts.js | 38 +++++++++++ tests/timezones/timezone-name.test.js | 25 +++++++ 3 files changed, 159 insertions(+) create mode 100644 src/timezone/index.js create mode 100644 src/whereIts.js create mode 100644 tests/timezones/timezone-name.test.js diff --git a/src/timezone/index.js b/src/timezone/index.js new file mode 100644 index 0000000..206a91a --- /dev/null +++ b/src/timezone/index.js @@ -0,0 +1,96 @@ + +import findTz from './find.js' +import inSummerTime from './summerTime.js' +import getDstShift from './dstShift.js' + +const parseDst = dst => { + if (!dst) { + return [] + } + return dst.split('->') +} + +//iana codes are case-sensitive, technically +const titleCase = str => { + str = str[0].toUpperCase() + str.substr(1) + str = str.replace(/[/_-]([a-z])/gi, s => { + return s.toUpperCase() + }) + str = str.replace(/_(of|es)_/i, (s) => s.toLowerCase()) + str = str.replace(/\/gmt/i, '/GMT') + str = str.replace(/\/utc/i, '/UTC') + str = str.replace(/\/Dumontdurville$/i, '/DumontDUrville') + str = str.replace(/\/Mcmurdo$/i, '/McMurdo') + str = str.replace(/\/Port-au-prince$/i, '/Port-au-Prince') + if (str === 'Utc') { + str = 'UTC' + } + return str +} + +//get metadata about this timezone +const timezone = s => { + const zones = s.timezones + let tz = s.tz + if (zones.hasOwnProperty(tz) === false) { + tz = findTz(s.tz, zones) + } + if (tz === null) { + if (s.silent === false) { + console.warn("Warn: could not find given or local timezone - '" + s.tz + "'") // eslint-disable-line no-console + } + return { + current: { + epochShift: 0 + } + } + } + const found = zones[tz] + const result = { + name: titleCase(tz), + hasDst: Boolean(found.dst), + default_offset: found.offset, + //do north-hemisphere version as default (sorry!) + hemisphere: found.hem === 's' ? 'South' : 'North', + current: {} + } + + if (result.hasDst) { + const arr = parseDst(found.dst) + result.change = { + start: arr[0], + back: arr[1] + } + } + //find the offsets for summer/winter times + //(these variable names are north-centric) + const summer = found.offset // (july) + let winter = summer // (january) assume it's the same for now + //most zones shift by 1hr on dst, but Lord Howe is a ½-hour shift + //and Troll (Antarctica) makes a 2-hour jump between +00 and +02 + const dstShift = getDstShift(tz) + if (result.hasDst === true) { + if (result.hemisphere === 'North') { + winter = summer - dstShift + } else { + //southern hemisphere + winter = found.offset + dstShift + } + } + + //find out which offset to use right now + //use 'summer' time july-time + if (result.hasDst === false) { + result.current.offset = summer + result.current.isDST = false + } else if (inSummerTime(s.epoch, result.change.start, result.change.back, summer, winter) === true) { + result.current.offset = summer + result.current.isDST = result.hemisphere === 'North' //dst 'on' in winter in north + } else { + //use 'winter' january-time + result.current.offset = winter + result.current.isDST = result.hemisphere === 'South' //dst 'on' in summer in south + } + return result +} +export default timezone diff --git a/src/whereIts.js b/src/whereIts.js new file mode 100644 index 0000000..0b186ab --- /dev/null +++ b/src/whereIts.js @@ -0,0 +1,38 @@ +import Spacetime from './spacetime.js' +// const timezones = require('../data'); + +const whereIts = (a, b) => { + let start = new Spacetime(null) + let end = new Spacetime(null) + start = start.time(a) + //if b is undefined, use as 'within one hour' + if (b) { + end = end.time(b) + } else { + end = start.add(59, 'minutes') + } + + const startHour = start.hour() + const endHour = end.hour() + const tzs = Object.keys(start.timezones).filter((tz) => { + if (tz.indexOf('/') === -1) { + return false + } + const m = new Spacetime(null, tz) + const hour = m.hour() + //do 'calendar-compare' not real-time-compare + if (hour >= startHour && hour <= endHour) { + //test minutes too, if applicable + if (hour === startHour && m.minute() < start.minute()) { + return false + } + if (hour === endHour && m.minute() > end.minute()) { + return false + } + return true + } + return false + }) + return tzs +} +export default whereIts diff --git a/tests/timezones/timezone-name.test.js b/tests/timezones/timezone-name.test.js new file mode 100644 index 0000000..b0f5a08 --- /dev/null +++ b/tests/timezones/timezone-name.test.js @@ -0,0 +1,25 @@ +import test from 'tape' +import spacetime from '../_lib/index.js' + +test('titlecase', (t) => { + const arr = [ + 'Africa/Dar_es_Salaam', + 'Africa/Porto-Novo', + 'America/Blanc-Sablon', + 'America/Port-au-Prince', + 'America/Port_of_Spain', + 'Europe/Isle_of_Man', + 'Antarctica/DumontDUrville', + 'Antarctica/McMurdo', + 'Asia/Ust-Nera', + 'Europe/Zagreb', + 'America/Bahia_Banderas', + 'Asia/Kuching', + 'Etc/GMT+7', + ] + arr.forEach(tz => { + const s = spacetime.now(tz) + t.equal(s.timezone().name, tz, tz) + }) + t.end() +})