Favivon - Correção

This commit is contained in:
2026-05-30 19:59:39 -03:00
parent 76ddaa815d
commit d7dfd221f0
32859 changed files with 5459654 additions and 404 deletions
+93
View File
@@ -0,0 +1,93 @@
# Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning].
This change log follows the format documented in [Keep a CHANGELOG].
[semantic versioning]: http://semver.org/
[keep a changelog]: http://keepachangelog.com/
## v1.4.1 - 2025-08-12
### Fixed
- Fixed incorrect `package.json` published with `@date-fns/tz@1.4.0`.
## v1.4.0 - 2025-08-12
### Added
- [Added support for time zones with seconds offset](https://github.com/date-fns/tz/pull/47). It allows to handle dates before the implementation of the GMT system in 1883. Huge kudos to [@GianlucaWassermeyer](https://github.com/GianlucaWassermeyer)!
## v1.3.1 - 2025-08-01
### Fixed
- Fixed TypeScript definitions missing in `@date-fns@1.3.0`.
## v1.3.0 - 2025-08-01
### Fixed
- Fixed Format.JS support when running in Hermes engine (React Native). Ensured compatibility with JavaScriptCore engine (Safari).
- Fixed TypeScript `node16` module resolution [#59](https://github.com/date-fns/tz/pull/59). Thanks to [@samchungy](https://github.com/samchungy).
### Added
- Added `tzName` function that formats time zone name in given date time and format. It supports `"short"`, `"long"`, `"shortGeneric"`, and `"longGeneric"` formats, corresponding to TR35 tokens `z..zzz`, `zzzz`, `v`, and `vvvv` respectively. See [README](./README.md) for more details.
## v1.2.0 - 2024-10-31
### Fixed
- Fixed issue with `setTime` not syncing the value to the internal date resulting in incorrect behavior [#16](https://github.com/date-fns/tz/issues/16), [#24](https://github.com/date-fns/tz/issues/24).
## v1.1.2 - 2024-09-24
### Fixed
- Improved compatibility with FormatJS Intl polifyll [#8](https://github.com/date-fns/tz/issues/8). Thanks to [@kevin-abiera](https://github.com/kevin-abiera).
## v1.1.1 - 2024-09-23
### Fixed
- Reworked DST handling to fix various bugs and edge cases. There might still be some issues, but I'm actively working on improving test coverage.
## v1.1.0 - 2024-09-22
This is yet another critical bug-fix release. Thank you to all the people who sent PRs and reported their issues. Special thanks to [@huextrat](https://github.com/huextrat), [@allohamora](https://github.com/allohamora) and [@lhermann](https://github.com/lhermann).
### Fixed
- [Fixed negative fractional time zones like `America/St_Johns`](https://github.com/date-fns/tz/pull/7) [@allohamora](https://github.com/allohamora).
- Fixed the DST bug when creating a date in the DST transition hour.
### Added
- Added support for `±HH:MM/±HHMM/±HH` time zone formats for Node.js below v22 (and other environments that has this problem) [#3](https://github.com/date-fns/tz/issues/3)
## v1.0.2 - 2024-09-14
This release fixes a couple of critical bugs in the previous release.
### Fixed
- Fixed UTC setters functions generation.
- Create `Invalid Date` instead of throwing an error on invalid arguments.
- Make all the number getters return `NaN` when the date or time zone is invalid.
- Make `tzOffset` return `NaN` when the date or the time zone is invalid.
## v1.0.1 - 2024-09-13
Initial version
```
```
+9
View File
@@ -0,0 +1,9 @@
MIT License
Copyright © 2024 Sasha Koss
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+287
View File
@@ -0,0 +1,287 @@
# @date-fns/tz
The package provides `Date` extensions `TZDate` and `TZDateMini` that perform all calculations in the given time zone rather than the system time zone.
Using it makes [date-fns](https://github.com/date-fns/date-fns) operate in given time zone but can also be used without it.
Like everything else in the date-fns ecosystem, the library is build-size aware. The smallest component, `TZDateMini,` is only `916 B`.
**Need only UTC?** See [@date-fns/utc](https://github.com/date-fns/utc) that provides lighter solution.
## Installation
```bash
npm install @date-fns/tz --save
```
## Usage
`TZDate` and `TZDateMini` have API similar to `Date`, but perform all calculations in the given time zone, which might be essential when operating across different time zones, calculating dates for users in different regions, or rendering chart or calendar component:
```ts
import { TZDate } from "@date-fns/tz";
import { addHours } from "date-fns";
// Given that the system time zone is America/Los_Angeles
// where DST happens at Sunday, 13 March 2022, 02:00:00
// Using system time zone will produce 03:00 instead of 02:00 because of DST:
const date = new Date(2022, 2, 13);
addHours(date, 2).toString();
//=> 'Sun Mar 13 2022 03:00:00 GMT-0700 (Pacific Daylight Time)'
// Using Asia/Singapore will provide expected 02:00:
const tzDate = new TZDate(2022, 2, 13, "Asia/Singapore");
addHours(tzDate, 2).toString();
//=> 'Sun Mar 13 2022 02:00:00 GMT+0800 (Singapore Standard Time)'
```
### Accepted time zone formats
You can pass IANA time zone name ("Asia/Singapore", "America/New_York", etc.) or UTC offset ("+01:00", "-2359", or "+23"):
```ts
new TZDate(2022, 2, 13, "Asia/Singapore");
new TZDate(2022, 2, 13, "+08:00");
new TZDate(2022, 2, 13, "-2359");
```
### Difference between `TZDate` and `TZDateMini`
The main difference between `TZDate` and `TZDateMini` is the build footprint. The `TZDateMini` is `916 B`, and the `TZDate` is `1.2 kB`. While the difference is slight it might be essential in some environments and use cases.
Unlike `TZDateMini` which implements only getters, setters, and `getTimezoneOffset`, `TZDate` also provides formatter functions, mirroring all original `Date` functionality:
```ts
import { TZDateMini, TZDate } from "@date-fns/tz";
// TZDateMini will format date-time in the system time zone:
new TZDateMini(2022, 2, 13).toString();
//=> 'Sat Mar 12 2022 16:00:00 GMT-0800 (Pacific Standard Time)'
// TZDate will format date-time in the Singapore time zone, like expected:
new TZDate(2022, 2, 13).toString();
//=> 'Sun Mar 13 2022 00:00:00 GMT+0800 (Singapore Standard Time)'
```
Even though `TZDate` has a complete API, developers rarely use the formatter functions outside of debugging, so we recommend you pick the more lightweight `TZDateMini` for internal use. However, in environments you don't control, i.e., when you expose the date from a library, using `TZDate` will be a safer choice.
### React Native / Hermes JS Engine
Starting with [v1.3.0](https://github.com/date-fns/tz/releases/tag/v1.3.0), `@date-fns/tz` supports [Format.JS polyfills](https://formatjs.github.io/docs/polyfills/intl-datetimeformat/) that are required for [Hermes JS Engine](https://github.com/facebook/hermes/blob/main/README.md) powering React Native runtime to work correctly.
To use it, you need to import the following polyfills in your entry point:
```ts
import "@formatjs/intl-getcanonicallocales/polyfill";
import "@formatjs/intl-locale/polyfill";
import "@formatjs/intl-pluralrules/polyfill";
import "@formatjs/intl-numberformat/polyfill";
import "@formatjs/intl-numberformat/locale-data/en";
import "@formatjs/intl-datetimeformat/polyfill";
import "@formatjs/intl-datetimeformat/locale-data/en";
import "@formatjs/intl-datetimeformat/add-golden-tz"; // or: "@formatjs/intl-datetimeformat/add-all-tz"
```
[The JavaScriptCore engine](https://github.com/apple-opensource/JavaScriptCore) is also supported and tested but does not require any polyfills.
## API
- [`TZDate`](#tzdate)
- [`tz`](#tz)
- [`tzOffset`](#tzoffset)
- [`tzScan`](#tzscan)
### `TZDate`
All the `TZDate` docs are also true for `TZDateMini`.
#### Constructor
When creating `TZDate`, you can pass the time zone as the last argument:
```ts
new TZDate(2022, 2, "Asia/Singapore");
new TZDate(timestamp, "Asia/Singapore");
new TZDate("2024-09-12T00:00:00Z", "Asia/Singapore");
```
The constructor mirrors the original `Date` parameters except for the last time zone parameter.
#### `TZDate.tz`
The static `tz` function allows to construct `TZDate` instance with just a time zone:
```ts
// Create now in Singapore time zone:
TZDate.tz("Asia/Singapore");
// ❌ This will not work, as TZDate expects a date string:
new TZDate("Asia/Singapore");
//=> Invalid Date
```
Just like the constructor, the function accepts all parameters variants:
```ts
TZDate.tz("Asia/Singapore", 2022, 2);
TZDate.tz("Asia/Singapore", timestamp);
TZDate.tz("Asia/Singapore", "2024-09-12T00:00:00Z");
```
#### `timeZone`
The readonly `timeZone` property returns the time zone name assigned to the instance:
```ts
new TZDate(2022, 2, 13, "Asia/Singapore").timeZone;
// "Asia/Singapore"
```
The property might be `undefined` when created without a time zone:
```ts
new TZDate().timeZone;
// undefined
```
#### `withTimeZone`
The `withTimeZone` method allows to create a new `TZDate` instance with a different time zone:
```ts
const sg = new TZDate(2022, 2, 13, "Asia/Singapore");
const ny = sg.withTimeZone("America/New_York");
sg.toString();
//=> 'Sun Mar 13 2022 00:00:00 GMT+0800 (Singapore Standard Time)'
ny.toString();
//=> 'Sat Mar 12 2022 11:00:00 GMT-0500 (Eastern Standard Time)'
```
#### `[Symbol.for("constructDateFrom")]`
The `TZDate` instance also exposes a method to construct a `Date` instance in the same time zone:
```ts
const sg = TZDate.tz("Asia/Singapore");
// Given that the system time zone is America/Los_Angeles
const date = sg[Symbol.for("constructDateFrom")](new Date(2024, 0, 1));
date.toString();
//=> 'Mon Jan 01 2024 16:00:00 GMT+0800 (Singapore Standard Time)'
```
It's created for date-fns but can be used in any context. You can access it via `Symbol.for("constructDateFrom")` or import it from the package:
```ts
import { constructFromSymbol } from "@date-fns/tz";
```
### `tz`
The `tz` function allows to specify the context for the [date-fns] functions (**starting from date-fns@4**):
```ts
import { isSameDay } from "date-fns";
import { tz } from "@date-fns/tz";
isSameDay("2024-09-09T23:00:00-04:00", "2024-09-10T10:00:00+08:00", {
in: tz("Europe/Prague"),
});
//=> true
```
### `tzOffset`
The `tzOffset` function allows to get the time zone UTC offset in minutes from the given time zone and a date:
```ts
import { tzOffset } from "@date-fns/tz";
const date = new Date("2020-01-15T00:00:00Z");
tzOffset("Asia/Singapore", date);
//=> 480
tzOffset("America/New_York", date);
//=> -300
// Summer time:
tzOffset("America/New_York", "2020-01-15T00:00:00Z");
//=> -240
```
Unlike `Date.prototype.getTimezoneOffset`, this function returns the value mirrored to the sign of the offset in the time zone. For Asia/Singapore (UTC+8), `tzOffset` returns 480, while `getTimezoneOffset` returns -480.
### `tzScan`
The function scans the time zone for changes in the given interval. It returns an array of objects with the date of the change, the offset change, and the new offset:
```ts
import { tzScan } from "@date-fns/tz";
tzScan("America/New_York", {
start: new Date("2020-01-01T00:00:00Z"),
end: new Date("2024-01-01T00:00:00Z"),
});
//=> [
//=> { date: 2020-03-08T07:00:00.000Z, change: 60, offset: -240 },
//=> { date: 2020-11-01T06:00:00.000Z, change: -60, offset: -300 },
//=> { date: 2021-03-14T07:00:00.000Z, change: 60, offset: -240 },
//=> { date: 2021-11-07T06:00:00.000Z, change: -60, offset: -300 },
//=> { date: 2022-03-13T07:00:00.000Z, change: 60, offset: -240 },
//=> { date: 2022-11-06T06:00:00.000Z, change: -60, offset: -300 },
//=> { date: 2023-03-12T07:00:00.000Z, change: 60, offset: -240 },
//=> { date: 2023-11-05T06:00:00.000Z, change: -60, offset: -300 }
//=> ]
```
### `tzName`
The function returns time zone name in human-readable format, e.g. `"Singapore Standard Time"` in the give date and time.
```ts
import { tzName } from "@date-fns/tz";
tzName("Asia/Singapore", new Date("2020-01-01T00:00:00Z"));
//=> "Singapore Standard Time"
```
It is possible to specify the format as the third argument using one of the following options:
- `"short"`e.g., `"EDT"` or "GMT+8"`.
- `"long"`: e.g., `"Eastern Daylight Time"` or `"Singapore Standard Time"`.
- `"shortGeneric"`: e.g., `"ET"` or `"Singapore Time"`.
- `"longGeneric"`: e.g., `"Eastern Time"` or `"Singapore Standard Time"`.
These options correspond to [TR35 tokens](https://www.unicode.org/reports/tr35/tr35-dates.html#dfst-zone) `z..zzz`, `zzzz`, `v`, and `vvvv` respectively.
```ts
import { tzName } from "@date-fns/tz";
const date = new Date("2020-01-01T00:00:00.000Z");
tzName("America/New_York", date, "short");
//=> "EST"
tzName("America/New_York", date, "shortGeneric");
//=> "ET"
```
## Changelog
See [the changelog](./CHANGELOG.md).
## License
[MIT © Sasha Koss](https://kossnocorp.mit-license.org/)
+8
View File
@@ -0,0 +1,8 @@
"use strict";
exports.constructFromSymbol = void 0;
/**
* The symbol to access the `TZDate`'s function to construct a new instance from
* the provided value. It helps date-fns to inherit the time zone.
*/
const constructFromSymbol = exports.constructFromSymbol = Symbol.for("constructDateFrom");
+6
View File
@@ -0,0 +1,6 @@
/**
* The symbol to access the `TZDate`'s function to construct a new instance from
* the provided value. It helps date-fns to inherit the time zone.
*/
export declare const constructFromSymbol: unique symbol;
//# sourceMappingURL=index.d.ts.map
+6
View File
@@ -0,0 +1,6 @@
/**
* The symbol to access the `TZDate`'s function to construct a new instance from
* the provided value. It helps date-fns to inherit the time zone.
*/
export declare const constructFromSymbol: unique symbol;
//# sourceMappingURL=index.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,mBAAmB,eAAkC,CAAC"}
+5
View File
@@ -0,0 +1,5 @@
/**
* The symbol to access the `TZDate`'s function to construct a new instance from
* the provided value. It helps date-fns to inherit the time zone.
*/
export const constructFromSymbol = Symbol.for("constructDateFrom");
+84
View File
@@ -0,0 +1,84 @@
"use strict";
exports.TZDate = void 0;
var _index = require("../tzName/index.cjs");
var _mini = require("./mini.cjs");
class TZDate extends _mini.TZDateMini {
//#region static
static tz(tz, ...args) {
return args.length ? new TZDate(...args, tz) : new TZDate(Date.now(), tz);
}
//#endregion
//#region representation
toISOString() {
const [sign, hours, minutes] = this.tzComponents();
const tz = `${sign}${hours}:${minutes}`;
return this.internal.toISOString().slice(0, -1) + tz;
}
toString() {
// "Tue Aug 13 2024 07:50:19 GMT+0800 (Singapore Standard Time)";
return `${this.toDateString()} ${this.toTimeString()}`;
}
toDateString() {
// toUTCString returns RFC 7231 ("Mon, 12 Aug 2024 23:36:08 GMT")
const [day, date, month, year] = this.internal.toUTCString().split(" ");
// "Tue Aug 13 2024"
return `${day?.slice(0, -1) /* Remove "," */} ${month} ${date} ${year}`;
}
toTimeString() {
// toUTCString returns RFC 7231 ("Mon, 12 Aug 2024 23:36:08 GMT")
const time = this.internal.toUTCString().split(" ")[4];
const [sign, hours, minutes] = this.tzComponents();
// "07:42:23 GMT+0800 (Singapore Standard Time)"
return `${time} GMT${sign}${hours}${minutes} (${(0, _index.tzName)(this.timeZone, this)})`;
}
toLocaleString(locales, options) {
return Date.prototype.toLocaleString.call(this, locales, {
...options,
timeZone: options?.timeZone || this.timeZone
});
}
toLocaleDateString(locales, options) {
return Date.prototype.toLocaleDateString.call(this, locales, {
...options,
timeZone: options?.timeZone || this.timeZone
});
}
toLocaleTimeString(locales, options) {
return Date.prototype.toLocaleTimeString.call(this, locales, {
...options,
timeZone: options?.timeZone || this.timeZone
});
}
//#endregion
//#region private
tzComponents() {
const offset = this.getTimezoneOffset();
const sign = offset > 0 ? "-" : "+";
const hours = String(Math.floor(Math.abs(offset) / 60)).padStart(2, "0");
const minutes = String(Math.abs(offset) % 60).padStart(2, "0");
return [sign, hours, minutes];
}
//#endregion
withTimeZone(timeZone) {
return new TZDate(+this, timeZone);
}
//#region date-fns integration
[Symbol.for("constructDateFrom")](date) {
return new TZDate(+new Date(date), this.timeZone);
}
//#endregion
}
exports.TZDate = TZDate;
+308
View File
@@ -0,0 +1,308 @@
import { constructFromSymbol } from "../constants/index.cts";
/**
* Time zone date class. It overrides original Date functions making them
* to perform all the calculations in the given time zone.
*
* It also provides new functions useful when working with time zones.
*
* Combined with date-fns, it allows using the class the same way as
* the original date class.
*
* This complete version provides formatter functions, mirroring all original
* methods of the `Date` class. It's build-size-heavier than `TZDateMini` and
* should be used when you need to format a string or in an environment you
* don't fully control (a library).
*
* For the minimal version, see `TZDateMini`.
*/
export class TZDate extends Date {
/**
* Constructs a new `TZDate` instance in the system time zone.
*/
constructor();
/**
* Constructs a new `TZDate` instance from the date time string and time zone.
*
* @param dateStr - Date time string to create a new instance from
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(dateStr: string, timeZone?: string);
/**
* Constructs a new `TZDate` instance from the date object and time zone.
*
* @param date - Date object to create a new instance from
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(date: Date, timeZone?: string);
/**
* Constructs a new `TZDate` instance from the Unix timestamp in milliseconds
* and time zone.
*
* @param timestamp - Unix timestamp in milliseconds to create a new instance from
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(timestamp: number, timeZone?: string);
/**
* Constructs a new `TZDate` instance from the year, month, and time zone.
*
* @param year - Year
* @param month - Month (0-11)
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(year: number, month: number, timeZone?: string);
/**
* Constructs a new `TZDate` instance from the year, month, date and time zone.
*
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(year: number, month: number, date: number, timeZone?: string);
/**
* Constructs a new `TZDate` instance from the year, month, date, hours
* and time zone.
*
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(
year: number,
month: number,
date: number,
hours: number,
timeZone?: string,
);
/**
* Constructs a new `TZDate` instance from the year, month, date, hours,
* minutes and time zone.
*
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param minutes - Minutes
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(
year: number,
month: number,
date: number,
hours: number,
minutes: number,
timeZone?: string,
);
/**
* Constructs a new `TZDate` instance from the year, month, date, hours,
* minutes, seconds and time zone.
*
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param minutes - Minutes
* @param seconds - Seconds
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(
year: number,
month: number,
date: number,
hours: number,
minutes: number,
seconds: number,
timeZone?: string,
);
/**
* Constructs a new `TZDate` instance from the year, month, date, hours,
* minutes, seconds, milliseconds and time zone.
*
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param minutes - Minutes
* @param seconds - Seconds
* @param milliseconds - Milliseconds
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(
year: number,
month: number,
date: number,
hours: number,
minutes: number,
seconds: number,
milliseconds: number,
timeZone?: string,
);
/**
* Creates a new `TZDate` instance in the given time zone.
*
* @param tz - Time zone name (IANA or UTC offset)
*/
static tz(tz: string): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the Unix
* timestamp in milliseconds.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param timestamp - Unix timestamp in milliseconds
*/
static tz(tz: string, timestamp: number): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the date time
* string.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param dateStr - Date time string
*/
static tz(tz: string, dateStr: string): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the date object.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param date - Date object
*/
static tz(tz: string, date: Date): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the year
* and month.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param year - Year
* @param month - Month (0-11)
*/
static tz(tz: string, year: number, month: number): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the year,
* month and date.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
*/
static tz(tz: string, year: number, month: number, date: number): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the year,
* month, date and hours.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
*/
static tz(
tz: string,
year: number,
month: number,
date: number,
hours: number,
): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the year,
* month, date, hours and minutes.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param minutes - Minutes
*/
static tz(
tz: string,
year: number,
month: number,
date: number,
hours: number,
minutes: number,
): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the year,
* month, date, hours, minutes and seconds.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param minutes - Minutes
* @param seconds - Seconds
*/
static tz(
tz: string,
year: number,
month: number,
date: number,
hours: number,
minutes: number,
seconds: number,
): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the year,
* month, date, hours, minutes, seconds and milliseconds.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param minutes - Minutes
* @param seconds - Seconds
* @param milliseconds - Milliseconds
*/
static tz(
tz: string,
year: number,
month: number,
date: number,
hours: number,
minutes: number,
seconds: number,
milliseconds: number,
): TZDate;
/**
* The current time zone of the date.
*/
readonly timeZone: string | undefined;
/**
* Creates a new `TZDate` instance in the given time zone.
*/
withTimeZone(timeZone: string): TZDate;
/**
* Creates a new `TZDate` instance in the current instance time zone and
* the specified date time value.
*
* @param date - Date value to create a new instance from
*/
[constructFromSymbol](date: Date | number | string): TZDate;
}
+308
View File
@@ -0,0 +1,308 @@
import { constructFromSymbol } from "../constants/index.ts";
/**
* Time zone date class. It overrides original Date functions making them
* to perform all the calculations in the given time zone.
*
* It also provides new functions useful when working with time zones.
*
* Combined with date-fns, it allows using the class the same way as
* the original date class.
*
* This complete version provides formatter functions, mirroring all original
* methods of the `Date` class. It's build-size-heavier than `TZDateMini` and
* should be used when you need to format a string or in an environment you
* don't fully control (a library).
*
* For the minimal version, see `TZDateMini`.
*/
export class TZDate extends Date {
/**
* Constructs a new `TZDate` instance in the system time zone.
*/
constructor();
/**
* Constructs a new `TZDate` instance from the date time string and time zone.
*
* @param dateStr - Date time string to create a new instance from
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(dateStr: string, timeZone?: string);
/**
* Constructs a new `TZDate` instance from the date object and time zone.
*
* @param date - Date object to create a new instance from
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(date: Date, timeZone?: string);
/**
* Constructs a new `TZDate` instance from the Unix timestamp in milliseconds
* and time zone.
*
* @param timestamp - Unix timestamp in milliseconds to create a new instance from
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(timestamp: number, timeZone?: string);
/**
* Constructs a new `TZDate` instance from the year, month, and time zone.
*
* @param year - Year
* @param month - Month (0-11)
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(year: number, month: number, timeZone?: string);
/**
* Constructs a new `TZDate` instance from the year, month, date and time zone.
*
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(year: number, month: number, date: number, timeZone?: string);
/**
* Constructs a new `TZDate` instance from the year, month, date, hours
* and time zone.
*
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(
year: number,
month: number,
date: number,
hours: number,
timeZone?: string,
);
/**
* Constructs a new `TZDate` instance from the year, month, date, hours,
* minutes and time zone.
*
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param minutes - Minutes
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(
year: number,
month: number,
date: number,
hours: number,
minutes: number,
timeZone?: string,
);
/**
* Constructs a new `TZDate` instance from the year, month, date, hours,
* minutes, seconds and time zone.
*
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param minutes - Minutes
* @param seconds - Seconds
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(
year: number,
month: number,
date: number,
hours: number,
minutes: number,
seconds: number,
timeZone?: string,
);
/**
* Constructs a new `TZDate` instance from the year, month, date, hours,
* minutes, seconds, milliseconds and time zone.
*
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param minutes - Minutes
* @param seconds - Seconds
* @param milliseconds - Milliseconds
* @param timeZone - Time zone name (IANA or UTC offset)
*/
constructor(
year: number,
month: number,
date: number,
hours: number,
minutes: number,
seconds: number,
milliseconds: number,
timeZone?: string,
);
/**
* Creates a new `TZDate` instance in the given time zone.
*
* @param tz - Time zone name (IANA or UTC offset)
*/
static tz(tz: string): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the Unix
* timestamp in milliseconds.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param timestamp - Unix timestamp in milliseconds
*/
static tz(tz: string, timestamp: number): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the date time
* string.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param dateStr - Date time string
*/
static tz(tz: string, dateStr: string): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the date object.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param date - Date object
*/
static tz(tz: string, date: Date): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the year
* and month.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param year - Year
* @param month - Month (0-11)
*/
static tz(tz: string, year: number, month: number): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the year,
* month and date.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
*/
static tz(tz: string, year: number, month: number, date: number): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the year,
* month, date and hours.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
*/
static tz(
tz: string,
year: number,
month: number,
date: number,
hours: number,
): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the year,
* month, date, hours and minutes.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param minutes - Minutes
*/
static tz(
tz: string,
year: number,
month: number,
date: number,
hours: number,
minutes: number,
): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the year,
* month, date, hours, minutes and seconds.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param minutes - Minutes
* @param seconds - Seconds
*/
static tz(
tz: string,
year: number,
month: number,
date: number,
hours: number,
minutes: number,
seconds: number,
): TZDate;
/**
* Creates a new `TZDate` instance in the given time zone from the year,
* month, date, hours, minutes, seconds and milliseconds.
*
* @param tz - Time zone name (IANA or UTC offset)
* @param year - Year
* @param month - Month (0-11)
* @param date - Date
* @param hours - Hours
* @param minutes - Minutes
* @param seconds - Seconds
* @param milliseconds - Milliseconds
*/
static tz(
tz: string,
year: number,
month: number,
date: number,
hours: number,
minutes: number,
seconds: number,
milliseconds: number,
): TZDate;
/**
* The current time zone of the date.
*/
readonly timeZone: string | undefined;
/**
* Creates a new `TZDate` instance in the given time zone.
*/
withTimeZone(timeZone: string): TZDate;
/**
* Creates a new `TZDate` instance in the current instance time zone and
* the specified date time value.
*
* @param date - Date value to create a new instance from
*/
[constructFromSymbol](date: Date | number | string): TZDate;
}
+80
View File
@@ -0,0 +1,80 @@
import { tzName } from "../tzName/index.js";
import { TZDateMini } from "./mini.js";
export class TZDate extends TZDateMini {
//#region static
static tz(tz, ...args) {
return args.length ? new TZDate(...args, tz) : new TZDate(Date.now(), tz);
}
//#endregion
//#region representation
toISOString() {
const [sign, hours, minutes] = this.tzComponents();
const tz = `${sign}${hours}:${minutes}`;
return this.internal.toISOString().slice(0, -1) + tz;
}
toString() {
// "Tue Aug 13 2024 07:50:19 GMT+0800 (Singapore Standard Time)";
return `${this.toDateString()} ${this.toTimeString()}`;
}
toDateString() {
// toUTCString returns RFC 7231 ("Mon, 12 Aug 2024 23:36:08 GMT")
const [day, date, month, year] = this.internal.toUTCString().split(" ");
// "Tue Aug 13 2024"
return `${day?.slice(0, -1) /* Remove "," */} ${month} ${date} ${year}`;
}
toTimeString() {
// toUTCString returns RFC 7231 ("Mon, 12 Aug 2024 23:36:08 GMT")
const time = this.internal.toUTCString().split(" ")[4];
const [sign, hours, minutes] = this.tzComponents();
// "07:42:23 GMT+0800 (Singapore Standard Time)"
return `${time} GMT${sign}${hours}${minutes} (${tzName(this.timeZone, this)})`;
}
toLocaleString(locales, options) {
return Date.prototype.toLocaleString.call(this, locales, {
...options,
timeZone: options?.timeZone || this.timeZone
});
}
toLocaleDateString(locales, options) {
return Date.prototype.toLocaleDateString.call(this, locales, {
...options,
timeZone: options?.timeZone || this.timeZone
});
}
toLocaleTimeString(locales, options) {
return Date.prototype.toLocaleTimeString.call(this, locales, {
...options,
timeZone: options?.timeZone || this.timeZone
});
}
//#endregion
//#region private
tzComponents() {
const offset = this.getTimezoneOffset();
const sign = offset > 0 ? "-" : "+";
const hours = String(Math.floor(Math.abs(offset) / 60)).padStart(2, "0");
const minutes = String(Math.abs(offset) % 60).padStart(2, "0");
return [sign, hours, minutes];
}
//#endregion
withTimeZone(timeZone) {
return new TZDate(+this, timeZone);
}
//#region date-fns integration
[Symbol.for("constructDateFrom")](date) {
return new TZDate(+new Date(date), this.timeZone);
}
//#endregion
}
+236
View File
@@ -0,0 +1,236 @@
"use strict";
exports.TZDateMini = void 0;
var _index = require("../tzOffset/index.cjs");
class TZDateMini extends Date {
//#region static
constructor(...args) {
super();
if (args.length > 1 && typeof args[args.length - 1] === "string") {
this.timeZone = args.pop();
}
this.internal = new Date();
if (isNaN((0, _index.tzOffset)(this.timeZone, this))) {
this.setTime(NaN);
} else {
if (!args.length) {
this.setTime(Date.now());
} else if (typeof args[0] === "number" && (args.length === 1 || args.length === 2 && typeof args[1] !== "number")) {
this.setTime(args[0]);
} else if (typeof args[0] === "string") {
this.setTime(+new Date(args[0]));
} else if (args[0] instanceof Date) {
this.setTime(+args[0]);
} else {
this.setTime(+new Date(...args));
adjustToSystemTZ(this, NaN);
syncToInternal(this);
}
}
}
static tz(tz, ...args) {
return args.length ? new TZDateMini(...args, tz) : new TZDateMini(Date.now(), tz);
}
//#endregion
//#region time zone
withTimeZone(timeZone) {
return new TZDateMini(+this, timeZone);
}
getTimezoneOffset() {
const offset = -(0, _index.tzOffset)(this.timeZone, this);
// Remove the seconds offset
// use Math.floor for negative GMT timezones and Math.ceil for positive GMT timezones.
return offset > 0 ? Math.floor(offset) : Math.ceil(offset);
}
//#endregion
//#region time
setTime(time) {
Date.prototype.setTime.apply(this, arguments);
syncToInternal(this);
return +this;
}
//#endregion
//#region date-fns integration
[Symbol.for("constructDateFrom")](date) {
return new TZDateMini(+new Date(date), this.timeZone);
}
//#endregion
}
// Assign getters and setters
exports.TZDateMini = TZDateMini;
const re = /^(get|set)(?!UTC)/;
Object.getOwnPropertyNames(Date.prototype).forEach(method => {
if (!re.test(method)) return;
const utcMethod = method.replace(re, "$1UTC");
// Filter out methods without UTC counterparts
if (!TZDateMini.prototype[utcMethod]) return;
if (method.startsWith("get")) {
// Delegate to internal date's UTC method
TZDateMini.prototype[method] = function () {
return this.internal[utcMethod]();
};
} else {
// Assign regular setter
TZDateMini.prototype[method] = function () {
Date.prototype[utcMethod].apply(this.internal, arguments);
syncFromInternal(this);
return +this;
};
// Assign UTC setter
TZDateMini.prototype[utcMethod] = function () {
Date.prototype[utcMethod].apply(this, arguments);
syncToInternal(this);
return +this;
};
}
});
/**
* Function syncs time to internal date, applying the time zone offset.
*
* @param {Date} date - Date to sync
*/
function syncToInternal(date) {
date.internal.setTime(+date);
date.internal.setUTCSeconds(date.internal.getUTCSeconds() - Math.round(-(0, _index.tzOffset)(date.timeZone, date) * 60));
}
/**
* Function syncs the internal date UTC values to the date. It allows to get
* accurate timestamp value.
*
* @param {Date} date - The date to sync
*/
function syncFromInternal(date) {
// First we transpose the internal values
Date.prototype.setFullYear.call(date, date.internal.getUTCFullYear(), date.internal.getUTCMonth(), date.internal.getUTCDate());
Date.prototype.setHours.call(date, date.internal.getUTCHours(), date.internal.getUTCMinutes(), date.internal.getUTCSeconds(), date.internal.getUTCMilliseconds());
// Now we have to adjust the date to the system time zone
adjustToSystemTZ(date);
}
/**
* Function adjusts the date to the system time zone. It uses the time zone
* differences to calculate the offset and adjust the date.
*
* @param {Date} date - Date to adjust
*/
function adjustToSystemTZ(date) {
// Save the time zone offset before all the adjustments
const baseOffset = (0, _index.tzOffset)(date.timeZone, date);
// Remove the seconds offset
// use Math.floor for negative GMT timezones and Math.ceil for positive GMT timezones.
const offset = baseOffset > 0 ? Math.floor(baseOffset) : Math.ceil(baseOffset);
//#region System DST adjustment
// The biggest problem with using the system time zone is that when we create
// a date from internal values stored in UTC, the system time zone might end
// up on the DST hour:
//
// $ TZ=America/New_York node
// > new Date(2020, 2, 8, 1).toString()
// 'Sun Mar 08 2020 01:00:00 GMT-0500 (Eastern Standard Time)'
// > new Date(2020, 2, 8, 2).toString()
// 'Sun Mar 08 2020 03:00:00 GMT-0400 (Eastern Daylight Time)'
// > new Date(2020, 2, 8, 3).toString()
// 'Sun Mar 08 2020 03:00:00 GMT-0400 (Eastern Daylight Time)'
// > new Date(2020, 2, 8, 4).toString()
// 'Sun Mar 08 2020 04:00:00 GMT-0400 (Eastern Daylight Time)'
//
// Here we get the same hour for both 2 and 3, because the system time zone
// has DST beginning at 8 March 2020, 2 a.m. and jumps to 3 a.m. So we have
// to adjust the internal date to reflect that.
//
// However we want to adjust only if that's the DST hour the change happenes,
// not the hour where DST moves to.
// We calculate the previous hour to see if the time zone offset has changed
// and we have landed on the DST hour.
const prevHour = new Date(+date);
// We use UTC methods here as we don't want to land on the same hour again
// in case of DST.
prevHour.setUTCHours(prevHour.getUTCHours() - 1);
// Calculate if we are on the system DST hour.
const systemOffset = -new Date(+date).getTimezoneOffset();
const prevHourSystemOffset = -new Date(+prevHour).getTimezoneOffset();
const systemDSTChange = systemOffset - prevHourSystemOffset;
// Detect the DST shift. System DST change will occur both on
const dstShift = Date.prototype.getHours.apply(date) !== date.internal.getUTCHours();
// Move the internal date when we are on the system DST hour.
if (systemDSTChange && dstShift) date.internal.setUTCMinutes(date.internal.getUTCMinutes() + systemDSTChange);
//#endregion
//#region System diff adjustment
// Now we need to adjust the date, since we just applied internal values.
// We need to calculate the difference between the system and date time zones
// and apply it to the date.
const offsetDiff = systemOffset - offset;
if (offsetDiff) Date.prototype.setUTCMinutes.call(date, Date.prototype.getUTCMinutes.call(date) + offsetDiff);
//#endregion
//#region Seconds System diff adjustment
const systemDate = new Date(+date);
// Set the UTC seconds to 0 to isolate the timezone offset in seconds.
systemDate.setUTCSeconds(0);
// For negative systemOffset, invert the seconds.
const systemSecondsOffset = systemOffset > 0 ? systemDate.getSeconds() : (systemDate.getSeconds() - 60) % 60;
// Calculate the seconds offset based on the timezone offset.
const secondsOffset = Math.round(-((0, _index.tzOffset)(date.timeZone, date) * 60)) % 60;
if (secondsOffset || systemSecondsOffset) {
date.internal.setUTCSeconds(date.internal.getUTCSeconds() + secondsOffset);
Date.prototype.setUTCSeconds.call(date, Date.prototype.getUTCSeconds.call(date) + secondsOffset + systemSecondsOffset);
}
//#endregion
//#region Post-adjustment DST fix
const postBaseOffset = (0, _index.tzOffset)(date.timeZone, date);
// Remove the seconds offset
// use Math.floor for negative GMT timezones and Math.ceil for positive GMT timezones.
const postOffset = postBaseOffset > 0 ? Math.floor(postBaseOffset) : Math.ceil(postBaseOffset);
const postSystemOffset = -new Date(+date).getTimezoneOffset();
const postOffsetDiff = postSystemOffset - postOffset;
const offsetChanged = postOffset !== offset;
const postDiff = postOffsetDiff - offsetDiff;
if (offsetChanged && postDiff) {
Date.prototype.setUTCMinutes.call(date, Date.prototype.getUTCMinutes.call(date) + postDiff);
// Now we need to check if got offset change during the post-adjustment.
// If so, we also need both dates to reflect that.
const newBaseOffset = (0, _index.tzOffset)(date.timeZone, date);
// Remove the seconds offset
// use Math.floor for negative GMT timezones and Math.ceil for positive GMT timezones.
const newOffset = newBaseOffset > 0 ? Math.floor(newBaseOffset) : Math.ceil(newBaseOffset);
const offsetChange = postOffset - newOffset;
if (offsetChange) {
date.internal.setUTCMinutes(date.internal.getUTCMinutes() + offsetChange);
Date.prototype.setUTCMinutes.call(date, Date.prototype.getUTCMinutes.call(date) + offsetChange);
}
}
//#endregion
}
+17
View File
@@ -0,0 +1,17 @@
import type { TZDate } from "./index.cjs";
/**
* Time zone date class. It overrides original Date functions making them
* to perform all the calculations in the given time zone.
*
* It also provides new functions useful when working with time zones.
*
* Combined with date-fns, it allows using the class the same way as
* the original date class.
*
* This minimal version provides complete functionality required for date-fns
* and excludes build-size-heavy formatter functions.
*
* For the complete version, see `TZDate`.
*/
export const TZDateMini: typeof TZDate;
+17
View File
@@ -0,0 +1,17 @@
import type { TZDate } from "./index.js";
/**
* Time zone date class. It overrides original Date functions making them
* to perform all the calculations in the given time zone.
*
* It also provides new functions useful when working with time zones.
*
* Combined with date-fns, it allows using the class the same way as
* the original date class.
*
* This minimal version provides complete functionality required for date-fns
* and excludes build-size-heavy formatter functions.
*
* For the complete version, see `TZDate`.
*/
export const TZDateMini: typeof TZDate;
+232
View File
@@ -0,0 +1,232 @@
import { tzOffset } from "../tzOffset/index.js";
export class TZDateMini extends Date {
//#region static
constructor(...args) {
super();
if (args.length > 1 && typeof args[args.length - 1] === "string") {
this.timeZone = args.pop();
}
this.internal = new Date();
if (isNaN(tzOffset(this.timeZone, this))) {
this.setTime(NaN);
} else {
if (!args.length) {
this.setTime(Date.now());
} else if (typeof args[0] === "number" && (args.length === 1 || args.length === 2 && typeof args[1] !== "number")) {
this.setTime(args[0]);
} else if (typeof args[0] === "string") {
this.setTime(+new Date(args[0]));
} else if (args[0] instanceof Date) {
this.setTime(+args[0]);
} else {
this.setTime(+new Date(...args));
adjustToSystemTZ(this, NaN);
syncToInternal(this);
}
}
}
static tz(tz, ...args) {
return args.length ? new TZDateMini(...args, tz) : new TZDateMini(Date.now(), tz);
}
//#endregion
//#region time zone
withTimeZone(timeZone) {
return new TZDateMini(+this, timeZone);
}
getTimezoneOffset() {
const offset = -tzOffset(this.timeZone, this);
// Remove the seconds offset
// use Math.floor for negative GMT timezones and Math.ceil for positive GMT timezones.
return offset > 0 ? Math.floor(offset) : Math.ceil(offset);
}
//#endregion
//#region time
setTime(time) {
Date.prototype.setTime.apply(this, arguments);
syncToInternal(this);
return +this;
}
//#endregion
//#region date-fns integration
[Symbol.for("constructDateFrom")](date) {
return new TZDateMini(+new Date(date), this.timeZone);
}
//#endregion
}
// Assign getters and setters
const re = /^(get|set)(?!UTC)/;
Object.getOwnPropertyNames(Date.prototype).forEach(method => {
if (!re.test(method)) return;
const utcMethod = method.replace(re, "$1UTC");
// Filter out methods without UTC counterparts
if (!TZDateMini.prototype[utcMethod]) return;
if (method.startsWith("get")) {
// Delegate to internal date's UTC method
TZDateMini.prototype[method] = function () {
return this.internal[utcMethod]();
};
} else {
// Assign regular setter
TZDateMini.prototype[method] = function () {
Date.prototype[utcMethod].apply(this.internal, arguments);
syncFromInternal(this);
return +this;
};
// Assign UTC setter
TZDateMini.prototype[utcMethod] = function () {
Date.prototype[utcMethod].apply(this, arguments);
syncToInternal(this);
return +this;
};
}
});
/**
* Function syncs time to internal date, applying the time zone offset.
*
* @param {Date} date - Date to sync
*/
function syncToInternal(date) {
date.internal.setTime(+date);
date.internal.setUTCSeconds(date.internal.getUTCSeconds() - Math.round(-tzOffset(date.timeZone, date) * 60));
}
/**
* Function syncs the internal date UTC values to the date. It allows to get
* accurate timestamp value.
*
* @param {Date} date - The date to sync
*/
function syncFromInternal(date) {
// First we transpose the internal values
Date.prototype.setFullYear.call(date, date.internal.getUTCFullYear(), date.internal.getUTCMonth(), date.internal.getUTCDate());
Date.prototype.setHours.call(date, date.internal.getUTCHours(), date.internal.getUTCMinutes(), date.internal.getUTCSeconds(), date.internal.getUTCMilliseconds());
// Now we have to adjust the date to the system time zone
adjustToSystemTZ(date);
}
/**
* Function adjusts the date to the system time zone. It uses the time zone
* differences to calculate the offset and adjust the date.
*
* @param {Date} date - Date to adjust
*/
function adjustToSystemTZ(date) {
// Save the time zone offset before all the adjustments
const baseOffset = tzOffset(date.timeZone, date);
// Remove the seconds offset
// use Math.floor for negative GMT timezones and Math.ceil for positive GMT timezones.
const offset = baseOffset > 0 ? Math.floor(baseOffset) : Math.ceil(baseOffset);
//#region System DST adjustment
// The biggest problem with using the system time zone is that when we create
// a date from internal values stored in UTC, the system time zone might end
// up on the DST hour:
//
// $ TZ=America/New_York node
// > new Date(2020, 2, 8, 1).toString()
// 'Sun Mar 08 2020 01:00:00 GMT-0500 (Eastern Standard Time)'
// > new Date(2020, 2, 8, 2).toString()
// 'Sun Mar 08 2020 03:00:00 GMT-0400 (Eastern Daylight Time)'
// > new Date(2020, 2, 8, 3).toString()
// 'Sun Mar 08 2020 03:00:00 GMT-0400 (Eastern Daylight Time)'
// > new Date(2020, 2, 8, 4).toString()
// 'Sun Mar 08 2020 04:00:00 GMT-0400 (Eastern Daylight Time)'
//
// Here we get the same hour for both 2 and 3, because the system time zone
// has DST beginning at 8 March 2020, 2 a.m. and jumps to 3 a.m. So we have
// to adjust the internal date to reflect that.
//
// However we want to adjust only if that's the DST hour the change happenes,
// not the hour where DST moves to.
// We calculate the previous hour to see if the time zone offset has changed
// and we have landed on the DST hour.
const prevHour = new Date(+date);
// We use UTC methods here as we don't want to land on the same hour again
// in case of DST.
prevHour.setUTCHours(prevHour.getUTCHours() - 1);
// Calculate if we are on the system DST hour.
const systemOffset = -new Date(+date).getTimezoneOffset();
const prevHourSystemOffset = -new Date(+prevHour).getTimezoneOffset();
const systemDSTChange = systemOffset - prevHourSystemOffset;
// Detect the DST shift. System DST change will occur both on
const dstShift = Date.prototype.getHours.apply(date) !== date.internal.getUTCHours();
// Move the internal date when we are on the system DST hour.
if (systemDSTChange && dstShift) date.internal.setUTCMinutes(date.internal.getUTCMinutes() + systemDSTChange);
//#endregion
//#region System diff adjustment
// Now we need to adjust the date, since we just applied internal values.
// We need to calculate the difference between the system and date time zones
// and apply it to the date.
const offsetDiff = systemOffset - offset;
if (offsetDiff) Date.prototype.setUTCMinutes.call(date, Date.prototype.getUTCMinutes.call(date) + offsetDiff);
//#endregion
//#region Seconds System diff adjustment
const systemDate = new Date(+date);
// Set the UTC seconds to 0 to isolate the timezone offset in seconds.
systemDate.setUTCSeconds(0);
// For negative systemOffset, invert the seconds.
const systemSecondsOffset = systemOffset > 0 ? systemDate.getSeconds() : (systemDate.getSeconds() - 60) % 60;
// Calculate the seconds offset based on the timezone offset.
const secondsOffset = Math.round(-(tzOffset(date.timeZone, date) * 60)) % 60;
if (secondsOffset || systemSecondsOffset) {
date.internal.setUTCSeconds(date.internal.getUTCSeconds() + secondsOffset);
Date.prototype.setUTCSeconds.call(date, Date.prototype.getUTCSeconds.call(date) + secondsOffset + systemSecondsOffset);
}
//#endregion
//#region Post-adjustment DST fix
const postBaseOffset = tzOffset(date.timeZone, date);
// Remove the seconds offset
// use Math.floor for negative GMT timezones and Math.ceil for positive GMT timezones.
const postOffset = postBaseOffset > 0 ? Math.floor(postBaseOffset) : Math.ceil(postBaseOffset);
const postSystemOffset = -new Date(+date).getTimezoneOffset();
const postOffsetDiff = postSystemOffset - postOffset;
const offsetChanged = postOffset !== offset;
const postDiff = postOffsetDiff - offsetDiff;
if (offsetChanged && postDiff) {
Date.prototype.setUTCMinutes.call(date, Date.prototype.getUTCMinutes.call(date) + postDiff);
// Now we need to check if got offset change during the post-adjustment.
// If so, we also need both dates to reflect that.
const newBaseOffset = tzOffset(date.timeZone, date);
// Remove the seconds offset
// use Math.floor for negative GMT timezones and Math.ceil for positive GMT timezones.
const newOffset = newBaseOffset > 0 ? Math.floor(newBaseOffset) : Math.ceil(newBaseOffset);
const offsetChange = postOffset - newOffset;
if (offsetChange) {
date.internal.setUTCMinutes(date.internal.getUTCMinutes() + offsetChange);
Date.prototype.setUTCMinutes.call(date, Date.prototype.getUTCMinutes.call(date) + offsetChange);
}
}
//#endregion
}
+79
View File
@@ -0,0 +1,79 @@
"use strict";
var _index = require("./constants/index.cjs");
Object.keys(_index).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _index[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _index[key];
}
});
});
var _index2 = require("./date/index.cjs");
Object.keys(_index2).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _index2[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _index2[key];
}
});
});
var _mini = require("./date/mini.cjs");
Object.keys(_mini).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _mini[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _mini[key];
}
});
});
var _index3 = require("./tz/index.cjs");
Object.keys(_index3).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _index3[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _index3[key];
}
});
});
var _index4 = require("./tzOffset/index.cjs");
Object.keys(_index4).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _index4[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _index4[key];
}
});
});
var _index5 = require("./tzScan/index.cjs");
Object.keys(_index5).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _index5[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _index5[key];
}
});
});
var _index6 = require("./tzName/index.cjs");
Object.keys(_index6).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _index6[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _index6[key];
}
});
});
+8
View File
@@ -0,0 +1,8 @@
export * from "./constants/index.cts";
export * from "./date/index.cjs";
export * from "./date/mini.cjs";
export * from "./tz/index.cts";
export * from "./tzOffset/index.cts";
export * from "./tzScan/index.cts";
export * from "./tzName/index.cts";
//# sourceMappingURL=index.d.ts.map
+8
View File
@@ -0,0 +1,8 @@
export * from "./constants/index.ts";
export * from "./date/index.js";
export * from "./date/mini.js";
export * from "./tz/index.ts";
export * from "./tzOffset/index.ts";
export * from "./tzScan/index.ts";
export * from "./tzName/index.ts";
//# sourceMappingURL=index.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC"}
+7
View File
@@ -0,0 +1,7 @@
export * from "./constants/index.js";
export * from "./date/index.js";
export * from "./date/mini.js";
export * from "./tz/index.js";
export * from "./tzOffset/index.js";
export * from "./tzScan/index.js";
export * from "./tzName/index.js";
+134
View File
@@ -0,0 +1,134 @@
{
"name": "@date-fns/tz",
"version": "1.4.1",
"description": "date-fns timezone utils",
"type": "module",
"main": "index.cjs",
"module": "index.js",
"exports": {
"./package.json": "./package.json",
".": {
"require": {
"types": "./index.d.cts",
"default": "./index.cjs"
},
"import": {
"types": "./index.d.ts",
"default": "./index.js"
}
},
"./tzOffset": {
"require": {
"types": "./tzOffset/index.d.cts",
"default": "./tzOffset/index.cjs"
},
"import": {
"types": "./tzOffset/index.d.ts",
"default": "./tzOffset/index.js"
}
},
"./tzScan": {
"require": {
"types": "./tzScan/index.d.cts",
"default": "./tzScan/index.cjs"
},
"import": {
"types": "./tzScan/index.d.ts",
"default": "./tzScan/index.js"
}
},
"./tzName": {
"require": {
"types": "./tzName/index.d.cts",
"default": "./tzName/index.cjs"
},
"import": {
"types": "./tzName/index.d.ts",
"default": "./tzName/index.js"
}
},
"./date": {
"require": {
"types": "./date/index.d.cts",
"default": "./date/index.cjs"
},
"import": {
"types": "./date/index.d.ts",
"default": "./date/index.js"
}
},
"./date/mini": {
"require": {
"types": "./date/mini.d.cts",
"default": "./date/mini.cjs"
},
"import": {
"types": "./date/mini.d.ts",
"default": "./date/mini.js"
}
},
"./tz": {
"require": {
"types": "./tz/index.d.cts",
"default": "./tz/index.cjs"
},
"import": {
"types": "./tz/index.d.ts",
"default": "./tz/index.js"
}
},
"./constants": {
"require": {
"types": "./constants/index.d.cts",
"default": "./constants/index.cjs"
},
"import": {
"types": "./constants/index.d.ts",
"default": "./constants/index.js"
}
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/date-fns/tz.git"
},
"keywords": [
"date-fns",
"tz",
"timezones",
"date",
"time",
"datetime"
],
"author": "Sasha Koss <koss@nocorp.me>",
"license": "MIT",
"bugs": {
"url": "https://github.com/date-fns/tz/issues"
},
"homepage": "https://github.com/date-fns/tz#readme",
"devDependencies": {
"@arethetypeswrong/cli": "^0.18.2",
"@babel/cli": "^7.28.0",
"@babel/core": "^7.28.0",
"@babel/plugin-transform-modules-commonjs": "^7.27.1",
"@babel/preset-env": "^7.28.0",
"@babel/preset-typescript": "^7.27.1",
"@parcel/watcher": "^2.4.1",
"@sinonjs/fake-timers": "^11.2.2",
"@swc/core": "^1.4.13",
"@types/sinonjs__fake-timers": "^8.1.5",
"babel-plugin-replace-import-extension": "^1.1.5",
"bytes-iec": "^3.1.1",
"date-fns": "4.0.0-alpha.1",
"glob": "^10.3.12",
"minimatch": "^10.0.1",
"picocolors": "^1.0.0",
"prettier": "^3.6.2",
"tinybench": "^2.7.0",
"typescript": "5.9.2",
"vitest": "^3.2.4"
},
"scripts": {
"test": "vitest run"
}
}
+15
View File
@@ -0,0 +1,15 @@
"use strict";
exports.tz = void 0;
var _index = require("../date/index.cjs");
/**
* The function creates accepts a time zone and returns a function that creates
* a new `TZDate` instance in the time zone from the provided value. Use it to
* provide the context for the date-fns functions, via the `in` option.
*
* @param timeZone - Time zone name (IANA or UTC offset)
*
* @returns Function that creates a new `TZDate` instance in the time zone
*/
const tz = timeZone => value => _index.TZDate.tz(timeZone, +new Date(value));
exports.tz = tz;
+12
View File
@@ -0,0 +1,12 @@
import { TZDate } from "../date/index.cjs";
/**
* The function creates accepts a time zone and returns a function that creates
* a new `TZDate` instance in the time zone from the provided value. Use it to
* provide the context for the date-fns functions, via the `in` option.
*
* @param timeZone - Time zone name (IANA or UTC offset)
*
* @returns Function that creates a new `TZDate` instance in the time zone
*/
export declare const tz: (timeZone: string) => (value: Date | number | string) => TZDate;
//# sourceMappingURL=index.d.ts.map
+12
View File
@@ -0,0 +1,12 @@
import { TZDate } from "../date/index.js";
/**
* The function creates accepts a time zone and returns a function that creates
* a new `TZDate` instance in the time zone from the provided value. Use it to
* provide the context for the date-fns functions, via the `in` option.
*
* @param timeZone - Time zone name (IANA or UTC offset)
*
* @returns Function that creates a new `TZDate` instance in the time zone
*/
export declare const tz: (timeZone: string) => (value: Date | number | string) => TZDate;
//# sourceMappingURL=index.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tz/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C;;;;;;;;GAQG;AACH,eAAO,MAAM,EAAE,GAAI,UAAU,MAAM,MAAM,OAAO,IAAI,GAAG,MAAM,GAAG,MAAM,WAC/B,CAAC"}
+12
View File
@@ -0,0 +1,12 @@
import { TZDate } from "../date/index.js";
/**
* The function creates accepts a time zone and returns a function that creates
* a new `TZDate` instance in the time zone from the provided value. Use it to
* provide the context for the date-fns functions, via the `in` option.
*
* @param timeZone - Time zone name (IANA or UTC offset)
*
* @returns Function that creates a new `TZDate` instance in the time zone
*/
export const tz = timeZone => value => TZDate.tz(timeZone, +new Date(value));
+40
View File
@@ -0,0 +1,40 @@
"use strict";
exports.tzName = tzName;
/**
* Time zone name format.
*/
/**
* The function returns the time zone name for the given date in the specified
* time zone.
*
* It uses the `Intl.DateTimeFormat` API and by default outputs the time zone
* name in a long format, e.g. "Pacific Standard Time" or
* "Singapore Standard Time".
*
* It is possible to specify the format as the third argument using one of the following options
*
* - "short": e.g. "EDT" or "GMT+8".
* - "long": e.g. "Eastern Daylight Time".
* - "shortGeneric": e.g. "ET" or "Singapore Time".
* - "longGeneric": e.g. "Eastern Time" or "Singapore Standard Time".
*
* These options correspond to TR35 tokens `z..zzz`, `zzzz`, `v`, and `vvvv` respectively: https://www.unicode.org/reports/tr35/tr35-dates.html#dfst-zone
*
* @param timeZone - Time zone name (IANA or UTC offset)
* @param date - Date object to get the time zone name for
* @param format - Optional format of the time zone name. Defaults to "long". Can be "short", "long", "shortGeneric", or "longGeneric".
*
* @returns Time zone name (e.g. "Singapore Standard Time")
*/
function tzName(timeZone, date, format = "long") {
return new Intl.DateTimeFormat("en-US", {
// Enforces engine to render the time. Without the option JavaScriptCore omits it.
hour: "numeric",
timeZone: timeZone,
timeZoneName: format
}).format(date).split(/\s/g) // Format.JS uses non-breaking spaces
.slice(2) // Skip the hour and AM/PM parts
.join(" ");
}
+29
View File
@@ -0,0 +1,29 @@
/**
* Time zone name format.
*/
export type TZNameFormat = "short" | "long" | "shortGeneric" | "longGeneric";
/**
* The function returns the time zone name for the given date in the specified
* time zone.
*
* It uses the `Intl.DateTimeFormat` API and by default outputs the time zone
* name in a long format, e.g. "Pacific Standard Time" or
* "Singapore Standard Time".
*
* It is possible to specify the format as the third argument using one of the following options
*
* - "short": e.g. "EDT" or "GMT+8".
* - "long": e.g. "Eastern Daylight Time".
* - "shortGeneric": e.g. "ET" or "Singapore Time".
* - "longGeneric": e.g. "Eastern Time" or "Singapore Standard Time".
*
* These options correspond to TR35 tokens `z..zzz`, `zzzz`, `v`, and `vvvv` respectively: https://www.unicode.org/reports/tr35/tr35-dates.html#dfst-zone
*
* @param timeZone - Time zone name (IANA or UTC offset)
* @param date - Date object to get the time zone name for
* @param format - Optional format of the time zone name. Defaults to "long". Can be "short", "long", "shortGeneric", or "longGeneric".
*
* @returns Time zone name (e.g. "Singapore Standard Time")
*/
export declare function tzName(timeZone: string, date: Date, format?: TZNameFormat): string;
//# sourceMappingURL=index.d.ts.map
+29
View File
@@ -0,0 +1,29 @@
/**
* Time zone name format.
*/
export type TZNameFormat = "short" | "long" | "shortGeneric" | "longGeneric";
/**
* The function returns the time zone name for the given date in the specified
* time zone.
*
* It uses the `Intl.DateTimeFormat` API and by default outputs the time zone
* name in a long format, e.g. "Pacific Standard Time" or
* "Singapore Standard Time".
*
* It is possible to specify the format as the third argument using one of the following options
*
* - "short": e.g. "EDT" or "GMT+8".
* - "long": e.g. "Eastern Daylight Time".
* - "shortGeneric": e.g. "ET" or "Singapore Time".
* - "longGeneric": e.g. "Eastern Time" or "Singapore Standard Time".
*
* These options correspond to TR35 tokens `z..zzz`, `zzzz`, `v`, and `vvvv` respectively: https://www.unicode.org/reports/tr35/tr35-dates.html#dfst-zone
*
* @param timeZone - Time zone name (IANA or UTC offset)
* @param date - Date object to get the time zone name for
* @param format - Optional format of the time zone name. Defaults to "long". Can be "short", "long", "shortGeneric", or "longGeneric".
*
* @returns Time zone name (e.g. "Singapore Standard Time")
*/
export declare function tzName(timeZone: string, date: Date, format?: TZNameFormat): string;
//# sourceMappingURL=index.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tzName/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,cAAc,GAAG,aAAa,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,MAAM,CACpB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,IAAI,EACV,MAAM,GAAE,YAAqB,GAC5B,MAAM,CAWR"}
+37
View File
@@ -0,0 +1,37 @@
/**
* Time zone name format.
*/
/**
* The function returns the time zone name for the given date in the specified
* time zone.
*
* It uses the `Intl.DateTimeFormat` API and by default outputs the time zone
* name in a long format, e.g. "Pacific Standard Time" or
* "Singapore Standard Time".
*
* It is possible to specify the format as the third argument using one of the following options
*
* - "short": e.g. "EDT" or "GMT+8".
* - "long": e.g. "Eastern Daylight Time".
* - "shortGeneric": e.g. "ET" or "Singapore Time".
* - "longGeneric": e.g. "Eastern Time" or "Singapore Standard Time".
*
* These options correspond to TR35 tokens `z..zzz`, `zzzz`, `v`, and `vvvv` respectively: https://www.unicode.org/reports/tr35/tr35-dates.html#dfst-zone
*
* @param timeZone - Time zone name (IANA or UTC offset)
* @param date - Date object to get the time zone name for
* @param format - Optional format of the time zone name. Defaults to "long". Can be "short", "long", "shortGeneric", or "longGeneric".
*
* @returns Time zone name (e.g. "Singapore Standard Time")
*/
export function tzName(timeZone, date, format = "long") {
return new Intl.DateTimeFormat("en-US", {
// Enforces engine to render the time. Without the option JavaScriptCore omits it.
hour: "numeric",
timeZone: timeZone,
timeZoneName: format
}).format(date).split(/\s/g) // Format.JS uses non-breaking spaces
.slice(2) // Skip the hour and AM/PM parts
.join(" ");
}
+45
View File
@@ -0,0 +1,45 @@
"use strict";
exports.tzOffset = tzOffset;
const offsetFormatCache = {};
const offsetCache = {};
/**
* The function extracts UTC offset in minutes from the given date in specified
* time zone.
*
* Unlike `Date.prototype.getTimezoneOffset`, this function returns the value
* mirrored to the sign of the offset in the time zone. For Asia/Singapore
* (UTC+8), `tzOffset` returns 480, while `getTimezoneOffset` returns -480.
*
* @param timeZone - Time zone name (IANA or UTC offset)
* @param date - Date to check the offset for
*
* @returns UTC offset in minutes
*/
function tzOffset(timeZone, date) {
try {
const format = offsetFormatCache[timeZone] ||= new Intl.DateTimeFormat("en-US", {
timeZone,
timeZoneName: "longOffset"
}).format;
const offsetStr = format(date).split("GMT")[1];
if (offsetStr in offsetCache) return offsetCache[offsetStr];
return calcOffset(offsetStr, offsetStr.split(":"));
} catch {
// Fallback to manual parsing if the runtime doesn't support ±HH:MM/±HHMM/±HH
// See: https://github.com/nodejs/node/issues/53419
if (timeZone in offsetCache) return offsetCache[timeZone];
const captures = timeZone?.match(offsetRe);
if (captures) return calcOffset(timeZone, captures.slice(1));
return NaN;
}
}
const offsetRe = /([+-]\d\d):?(\d\d)?/;
function calcOffset(cacheStr, values) {
const hours = +(values[0] || 0);
const minutes = +(values[1] || 0);
// Convert seconds to minutes by dividing by 60 to keep the function return in minutes.
const seconds = +(values[2] || 0) / 60;
return offsetCache[cacheStr] = hours * 60 + minutes > 0 ? hours * 60 + minutes + seconds : hours * 60 - minutes - seconds;
}
+15
View File
@@ -0,0 +1,15 @@
/**
* The function extracts UTC offset in minutes from the given date in specified
* time zone.
*
* Unlike `Date.prototype.getTimezoneOffset`, this function returns the value
* mirrored to the sign of the offset in the time zone. For Asia/Singapore
* (UTC+8), `tzOffset` returns 480, while `getTimezoneOffset` returns -480.
*
* @param timeZone - Time zone name (IANA or UTC offset)
* @param date - Date to check the offset for
*
* @returns UTC offset in minutes
*/
export declare function tzOffset(timeZone: string | undefined, date: Date): number;
//# sourceMappingURL=index.d.ts.map
+15
View File
@@ -0,0 +1,15 @@
/**
* The function extracts UTC offset in minutes from the given date in specified
* time zone.
*
* Unlike `Date.prototype.getTimezoneOffset`, this function returns the value
* mirrored to the sign of the offset in the time zone. For Asia/Singapore
* (UTC+8), `tzOffset` returns 480, while `getTimezoneOffset` returns -480.
*
* @param timeZone - Time zone name (IANA or UTC offset)
* @param date - Date to check the offset for
*
* @returns UTC offset in minutes
*/
export declare function tzOffset(timeZone: string | undefined, date: Date): number;
//# sourceMappingURL=index.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tzOffset/index.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAoBzE"}
+42
View File
@@ -0,0 +1,42 @@
const offsetFormatCache = {};
const offsetCache = {};
/**
* The function extracts UTC offset in minutes from the given date in specified
* time zone.
*
* Unlike `Date.prototype.getTimezoneOffset`, this function returns the value
* mirrored to the sign of the offset in the time zone. For Asia/Singapore
* (UTC+8), `tzOffset` returns 480, while `getTimezoneOffset` returns -480.
*
* @param timeZone - Time zone name (IANA or UTC offset)
* @param date - Date to check the offset for
*
* @returns UTC offset in minutes
*/
export function tzOffset(timeZone, date) {
try {
const format = offsetFormatCache[timeZone] ||= new Intl.DateTimeFormat("en-US", {
timeZone,
timeZoneName: "longOffset"
}).format;
const offsetStr = format(date).split("GMT")[1];
if (offsetStr in offsetCache) return offsetCache[offsetStr];
return calcOffset(offsetStr, offsetStr.split(":"));
} catch {
// Fallback to manual parsing if the runtime doesn't support ±HH:MM/±HHMM/±HH
// See: https://github.com/nodejs/node/issues/53419
if (timeZone in offsetCache) return offsetCache[timeZone];
const captures = timeZone?.match(offsetRe);
if (captures) return calcOffset(timeZone, captures.slice(1));
return NaN;
}
}
const offsetRe = /([+-]\d\d):?(\d\d)?/;
function calcOffset(cacheStr, values) {
const hours = +(values[0] || 0);
const minutes = +(values[1] || 0);
// Convert seconds to minutes by dividing by 60 to keep the function return in minutes.
const seconds = +(values[2] || 0) / 60;
return offsetCache[cacheStr] = hours * 60 + minutes > 0 ? hours * 60 + minutes + seconds : hours * 60 - minutes - seconds;
}
+75
View File
@@ -0,0 +1,75 @@
"use strict";
exports.tzScan = tzScan;
var _index = require("../tzOffset/index.cjs");
/**
* Time interval.
*/
/**
* Time zone change record.
*/
/**
* The function scans the time zone for changes in the given interval.
*
* @param timeZone - Time zone name (IANA or UTC offset)
* @param interval - Time interval to scan for changes
*
* @returns Array of time zone changes
*/
function tzScan(timeZone, interval) {
const changes = [];
const monthDate = new Date(interval.start);
monthDate.setUTCSeconds(0, 0);
const endDate = new Date(interval.end);
endDate.setUTCSeconds(0, 0);
const endMonthTime = +endDate;
let lastOffset = (0, _index.tzOffset)(timeZone, monthDate);
while (+monthDate < endMonthTime) {
// Month forward
monthDate.setUTCMonth(monthDate.getUTCMonth() + 1);
// Find the month where the offset changes
const offset = (0, _index.tzOffset)(timeZone, monthDate);
if (offset != lastOffset) {
// Rewind a month back to find the day where the offset changes
const dayDate = new Date(monthDate);
dayDate.setUTCMonth(dayDate.getUTCMonth() - 1);
const endDayTime = +monthDate;
lastOffset = (0, _index.tzOffset)(timeZone, dayDate);
while (+dayDate < endDayTime) {
// Day forward
dayDate.setUTCDate(dayDate.getUTCDate() + 1);
// Find the day where the offset changes
const offset = (0, _index.tzOffset)(timeZone, dayDate);
if (offset != lastOffset) {
// Rewind a day back to find the time where the offset changes
const hourDate = new Date(dayDate);
hourDate.setUTCDate(hourDate.getUTCDate() - 1);
const endHourTime = +dayDate;
lastOffset = (0, _index.tzOffset)(timeZone, hourDate);
while (+hourDate < endHourTime) {
// Hour forward
hourDate.setUTCHours(hourDate.getUTCHours() + 1);
// Find the hour where the offset changes
const hourOffset = (0, _index.tzOffset)(timeZone, hourDate);
if (hourOffset !== lastOffset) {
changes.push({
date: new Date(hourDate),
change: hourOffset - lastOffset,
offset: hourOffset
});
}
lastOffset = hourOffset;
}
}
lastOffset = offset;
}
}
lastOffset = offset;
}
return changes;
}
+30
View File
@@ -0,0 +1,30 @@
/**
* Time interval.
*/
export interface TZChangeInterval {
/** Start date. */
start: Date;
/** End date. */
end: Date;
}
/**
* Time zone change record.
*/
export interface TZChange {
/** Date time the change occurs */
date: Date;
/** Offset change in minutes */
change: number;
/** New UTC offset in minutes */
offset: number;
}
/**
* The function scans the time zone for changes in the given interval.
*
* @param timeZone - Time zone name (IANA or UTC offset)
* @param interval - Time interval to scan for changes
*
* @returns Array of time zone changes
*/
export declare function tzScan(timeZone: string, interval: TZChangeInterval): TZChange[];
//# sourceMappingURL=index.d.ts.map
+30
View File
@@ -0,0 +1,30 @@
/**
* Time interval.
*/
export interface TZChangeInterval {
/** Start date. */
start: Date;
/** End date. */
end: Date;
}
/**
* Time zone change record.
*/
export interface TZChange {
/** Date time the change occurs */
date: Date;
/** Offset change in minutes */
change: number;
/** New UTC offset in minutes */
offset: number;
}
/**
* The function scans the time zone for changes in the given interval.
*
* @param timeZone - Time zone name (IANA or UTC offset)
* @param interval - Time interval to scan for changes
*
* @returns Array of time zone changes
*/
export declare function tzScan(timeZone: string, interval: TZChangeInterval): TZChange[];
//# sourceMappingURL=index.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tzScan/index.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB;IAClB,KAAK,EAAE,IAAI,CAAC;IACZ,gBAAgB;IAChB,GAAG,EAAE,IAAI,CAAC;CACX;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,kCAAkC;IAClC,IAAI,EAAE,IAAI,CAAC;IACX,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,MAAM,CACpB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,gBAAgB,GACzB,QAAQ,EAAE,CA+DZ"}
+73
View File
@@ -0,0 +1,73 @@
import { tzOffset } from "../tzOffset/index.js";
/**
* Time interval.
*/
/**
* Time zone change record.
*/
/**
* The function scans the time zone for changes in the given interval.
*
* @param timeZone - Time zone name (IANA or UTC offset)
* @param interval - Time interval to scan for changes
*
* @returns Array of time zone changes
*/
export function tzScan(timeZone, interval) {
const changes = [];
const monthDate = new Date(interval.start);
monthDate.setUTCSeconds(0, 0);
const endDate = new Date(interval.end);
endDate.setUTCSeconds(0, 0);
const endMonthTime = +endDate;
let lastOffset = tzOffset(timeZone, monthDate);
while (+monthDate < endMonthTime) {
// Month forward
monthDate.setUTCMonth(monthDate.getUTCMonth() + 1);
// Find the month where the offset changes
const offset = tzOffset(timeZone, monthDate);
if (offset != lastOffset) {
// Rewind a month back to find the day where the offset changes
const dayDate = new Date(monthDate);
dayDate.setUTCMonth(dayDate.getUTCMonth() - 1);
const endDayTime = +monthDate;
lastOffset = tzOffset(timeZone, dayDate);
while (+dayDate < endDayTime) {
// Day forward
dayDate.setUTCDate(dayDate.getUTCDate() + 1);
// Find the day where the offset changes
const offset = tzOffset(timeZone, dayDate);
if (offset != lastOffset) {
// Rewind a day back to find the time where the offset changes
const hourDate = new Date(dayDate);
hourDate.setUTCDate(hourDate.getUTCDate() - 1);
const endHourTime = +dayDate;
lastOffset = tzOffset(timeZone, hourDate);
while (+hourDate < endHourTime) {
// Hour forward
hourDate.setUTCHours(hourDate.getUTCHours() + 1);
// Find the hour where the offset changes
const hourOffset = tzOffset(timeZone, hourDate);
if (hourOffset !== lastOffset) {
changes.push({
date: new Date(hourDate),
change: hourOffset - lastOffset,
offset: hourOffset
});
}
lastOffset = hourOffset;
}
}
lastOffset = offset;
}
}
lastOffset = offset;
}
return changes;
}