Skip to content

Commit

Permalink
Merge pull request #273 from marnusw/version3
Browse files Browse the repository at this point in the history
Version 3
  • Loading branch information
marnusw authored Apr 6, 2024
2 parents 867837b + 1cd68ff commit 3bcf1db
Show file tree
Hide file tree
Showing 83 changed files with 479 additions and 1,203 deletions.
4 changes: 0 additions & 4 deletions .flowconfig

This file was deleted.

29 changes: 15 additions & 14 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
### v3.0.0-beta.3 (28 March 2024)

- [BUGFIX] Fix `date-fns` imports for `fp` by copying the `convertToFP` function

### v3.0.0-beta.2 (26 March 2024)

- [BUGFIX] Fix `date-fns` imports by copying the `getTimezoneOffsetInMilliseconds` (#272)

### v3.0.0-beta.1 (22 March 2024)
### v3.0.0 (6 April 2024)

- [UPGRADE] Support `date-fns` v3 (#265) Thank you, @christopherklint97
- [BUGFIX] Correct import of `date-fns@v3` format and use Babel Webpack loader for mjs files (#271)
- [BUGFIX] Correct various other `date-fns@v3` imports

### v3.0.0-beta.0 (9 March 2024)

- [UPGRADE] Support date-fns v3 (#265) Thank you, @christopherklint97
- [BREAKING CHANGE] `date-fns` v2 is no longer supported
- [BREAKING CHANGE] Renamed `utcToZonedTime` to `toZonedTime` to make the name less confusing, just search & replace
- [BREAKING CHANGE] Renamed `zonedTimeToUtc` to `fromZonedTime` to make the name less confusing, just search & replace
- [BREAKING CHANGE] All functions are now exported using named exports, this requires changing direct
imports from `import formatInTimeZone from 'date-fns-tz/formatInTimeZone'` to
`import { formatInTimeZone } from 'date-fns-tz/formatInTimeZone'`
- [BREAKING CHANGE] Functions now don’t check the number of passed arguments, delegating this task to type checkers
(This isn't fully implemented yet, but it should be the assumption moving forward, as it is in `date-fns`)
- [BREAKING CHANGE] Arguments are not explicitly converted to the target types. Instead, they are passed as is,
delegating this task to type checkers (This isn't fully implemented yet, but it should be the assumption
moving forward, as it is in `date-fns`)
- [BREAKING CHANGE] IE is no longer supported since `date-fns` no longer supports it
- [BREAKING CHANGE] Removed `flow` support since `date-fns` also removed it

### v2.0.1 (9 March 2024)

Expand Down
60 changes: 28 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ This is because an ESM project cannot use ESM imports from a library that doesn'
- [`formatInTimeZone`](#formatintimezone) - Formats a date in the provided time zone,
regardless of the system time zone
- [Time zone offset helpers](#time-zone-offset-helpers)
- [`zonedTimeToUtc`](#zonedtimetoutc) - Given a date and any time zone, returns a `Date` with the equivalent UTC time
- [`utcToZonedTime`](#utctozonedtime) - Get a date/time representing local time in a given time zone from the UTC date
- [`fromZonedTime`](#zonedtimetoutc) - Given a date and any time zone, returns a `Date` with the equivalent UTC time
- [`toZonedTime`](#utctozonedtime) - Get a date/time representing local time in a given time zone from the UTC date
- [`getTimezoneOffset`](#gettimezoneoffset) - Gets the offset in milliseconds between the time zone and UTC time
- [Low-level formatting helpers](#low-level-formatting-helpers)
- [`format`](#format) - Extends `date-fns/format` with support for all time zone tokens,
Expand Down Expand Up @@ -111,13 +111,14 @@ To discuss the usage of the time zone helpers let's assume we're writing a syste
administrators set up events which will start at a specific time in the venue's local time, and
this local time should be shown when accessing the site from anywhere in the world.

### `zonedTimeToUtc`
### `fromZonedTime`

Given a date and any time zone, returns a `Date` with the equivalent UTC time.
An invalid date string or time zone will result in an `Invalid Date`.
Given a date and any time zone, returns the equivalent `Date` in the current system time zone
and the equivalent UTC time internally. An invalid date string or time zone will result in
an `Invalid Date`.

```ts
zonedTimeToUtc(date: Date|Number|String, timeZone: String): Date
fromZonedTime(date: Date|Number|String, timeZone: String): Date
```

Say a user is asked to input the date/time and time zone of an event. A date/time picker will
Expand All @@ -127,35 +128,36 @@ select input might provide the actual IANA time zone name.
In order to work with this info effectively it is necessary to find the equivalent UTC time:

```javascript
import { zonedTimeToUtc } from 'date-fns-tz'
import { fromZonedTime } from 'date-fns-tz'

const date = getDatePickerValue() // e.g. 2014-06-25 10:00:00 (picked in any time zone)
const timeZone = getTimeZoneValue() // e.g. America/Los_Angeles

const utcDate = zonedTimeToUtc(date, timeZone) // In June 10am in Los Angeles is 5pm UTC
const utcDate = fromZonedTime(date, timeZone) // In June 10am in Los Angeles is 5pm UTC

postToServer(utcDate.toISOString(), timeZone) // post 2014-06-25T17:00:00.000Z, America/Los_Angeles
```

### `utcToZonedTime`
### `toZonedTime`

Returns a `Date` which will format as the local time of any time zone from a specific UTC time.
An invalid date string or time zone will result in an `Invalid Date`.
Returns a `Date` which will format as the local time of any time zone from a specific UTC time
or date in the current system time zone. An invalid date string or time zone will result in
an `Invalid Date`.

```js
utcToZonedTime(date: Date|Number|String, timeZone: String): Date
toZonedTime(date: Date|Number|String, timeZone: String): Date
```

Say the server provided a UTC date/time and a time zone which should be used as initial values
for the above form. The date/time picker will take a Date input which will be in the user's
local time zone, but the date value must be that of the target time zone.

```javascript
import { utcToZonedTime } from 'date-fns-tz'
import { toZonedTime } from 'date-fns-tz'

const { isoDate, timeZone } = fetchInitialValues() // 2014-06-25T10:00:00.000Z, America/New_York

const date = utcToZonedTime(isoDate, timeZone) // In June 10am UTC is 6am in New York (-04:00)
const date = toZonedTime(isoDate, timeZone) // In June 10am UTC is 6am in New York (-04:00)

renderDatePicker(date) // 2014-06-25 06:00:00 (in the system time zone)
renderTimeZoneSelect(timeZone) // America/New_York
Expand Down Expand Up @@ -216,21 +218,21 @@ time zone is provided _and included in the output_, i.e. with time zone tokens i
string, it will also throw a `RangeError`.

To format a date showing time for a specific time zone other than the system time zone, the
`format` function can be combined with `utcToZonedTime`. This is what `formatInTimeZone` does
`format` function can be combined with `toZonedTime`. This is what `formatInTimeZone` does
internally. _To clarify, the `format` function will never change the underlying date, it must be
changed to a zoned time before passing it to `format`._

In most cases there is no need to use `format` rather than `formatInTimeZone`. The only time
this makes sense is when `utcToZonedTime` has been applied to a date once, and you want to
this makes sense is when `toZonedTime` has been applied to a date once, and you want to
format it multiple times to different outputs.

```javascript
import { format, utcToZonedTime } from 'date-fns-tz'
import { format, toZonedTime } from 'date-fns-tz'

const date = new Date('2014-10-25T10:46:20Z')

const nyDate = utcToZonedTime(date, 'America/New_York')
const parisDate = utcToZonedTime(date, 'Europe/Paris')
const nyDate = toZonedTime(date, 'America/New_York')
const parisDate = toZonedTime(date, 'Europe/Paris')

format(nyDate, 'yyyy-MM-dd HH:mm:ssXXX', { timeZone: 'America/New_York' }) // 2014-10-25 06:46:20-04:00
format(nyDate, 'yyyy-MM-dd HH:mm:ss zzz', { timeZone: 'America/New_York' }) // 2014-10-25 06:46:20 EST
Expand Down Expand Up @@ -263,7 +265,7 @@ import { toDate, format } from 'date-fns-tz'

// Offsets in the date string work as usual and take precedence
const parsedDate = toDate('2014-10-25T13:46:20+04:00')
const parisDate = utcToZonedTime(parsedDate, 'Europe/Paris')
const parisDate = toZonedTime(parsedDate, 'Europe/Paris')
format(parisDate, 'yyyy-MM-dd HH:mm:ssxxx', { timeZone: 'Europe/Paris' }) // 2014-10-25 11:46:20+02:00

// Since toDate simply clones a Date instance, the timeZone option is effectively ignored in this case
Expand All @@ -273,32 +275,26 @@ assert(date.valueOf() === clonedDate.valueOf())

// When there is no offset in the date string the timeZone property is used
const parsedDate = toDate('2014-10-25T13:46:20', { timeZone: 'Asia/Bangkok' })
const bangkokDate = utcToZonedTime(parsedDate, 'Asia/Bangkok')
const bangkokDate = toZonedTime(parsedDate, 'Asia/Bangkok')
format(bangkokDate, 'yyyy-MM-dd HH:mm:ssxxx', { timeZone: 'Asia/Bangkok' }) // 2014-10-25 13:46:20+07:00
```

## Usage with Android

This library works with React Native, however the `Intl` API is not available by default on Android.
This library works with React Native on iOS, and on Android with Hermes which supports
`Intl` by default.

In projects that do not use Hermes, make this change to `android/app/build.gradle`:
In Android projects that do not use Hermes, make this change in `android/app/build.gradle`:

```diff
- def jscFlavor = 'org.webkit:android-jsc:+'
+ def jscFlavor = 'org.webkit:android-jsc-intl:+'
```

React Native does not currently support `Intl` on Android with
Hermes ([facebook/hermes#23](https://github.com/facebook/hermes/issues/23)). The best bet
seems to be using the [polyfills by Format.JS](https://formatjs.io/docs/polyfills/intl-datetimeformat).

## Usage with Node.js

Node.js supports the `Intl` API and ships with full ICU data included in the binary from v13,
i.e. this library will just work.

Node.js v12, which reaches end of life on 30 April 2022, requires running with
[full ICU data provided at runtime](https://nodejs.org/docs/latest-v12.x/api/intl.html#intl_providing_icu_data_at_runtime).
Node.js supports the `Intl` API and ships with full ICU data included in the binary since v13,
so this library works by default.

## Credit

Expand Down
60 changes: 42 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "date-fns-tz",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.6",
"sideEffects": false,
"description": "Time zone support for date-fns v3 with the Intl API",
"author": "Marnus Weststrate <marnusw@gmail.com>",
Expand Down Expand Up @@ -50,15 +50,15 @@
"import": "./esm/toDate/index.js",
"require": "./toDate/index.js"
},
"./utcToZonedTime": {
"types": "./utcToZonedTime/index.d.ts",
"import": "./esm/utcToZonedTime/index.js",
"require": "./utcToZonedTime/index.js"
"./toZonedTime": {
"types": "./toZonedTime/index.d.ts",
"import": "./esm/toZonedTime/index.js",
"require": "./toZonedTime/index.js"
},
"./zonedTimeToUtc": {
"types": "./zonedTimeToUtc/index.d.ts",
"import": "./esm/zonedTimeToUtc/index.js",
"require": "./zonedTimeToUtc/index.js"
"./fromZonedTime": {
"types": "./fromZonedTime/index.d.ts",
"import": "./esm/fromZonedTime/index.js",
"require": "./fromZonedTime/index.js"
},
"./fp": {
"types": "./fp/index.d.ts",
Expand All @@ -75,6 +75,26 @@
"import": "./esm/fp/formatInTimeZone/index.js",
"require": "./fp/formatInTimeZone/index.js"
},
"./fp/formatInTimeZoneWithOptions": {
"types": "./fp/formatInTimeZoneWithOptions/index.d.ts",
"import": "./esm/fp/formatInTimeZoneWithOptions/index.js",
"require": "./fp/formatInTimeZoneWithOptions/index.js"
},
"./fp/formatWithOptions": {
"types": "./fp/formatWithOptions/index.d.ts",
"import": "./esm/fp/formatWithOptions/index.js",
"require": "./fp/formatWithOptions/index.js"
},
"./fp/fromZonedTime": {
"types": "./fp/fromZonedTime/index.d.ts",
"import": "./esm/fp/fromZonedTime/index.js",
"require": "./fp/fromZonedTime/index.js"
},
"./fp/fromZonedTimeWithOptions": {
"types": "./fp/fromZonedTimeWithOptions/index.d.ts",
"import": "./esm/fp/fromZonedTimeWithOptions/index.js",
"require": "./fp/fromZonedTimeWithOptions/index.js"
},
"./fp/getTimezoneOffset": {
"types": "./fp/getTimezoneOffset/index.d.ts",
"import": "./esm/fp/getTimezoneOffset/index.js",
Expand All @@ -85,15 +105,20 @@
"import": "./esm/fp/toDate/index.js",
"require": "./fp/toDate/index.js"
},
"./fp/utcToZonedTime": {
"types": "./fp/utcToZonedTime/index.d.ts",
"import": "./esm/fp/utcToZonedTime/index.js",
"require": "./fp/utcToZonedTime/index.js"
"./fp/toDateWithOptions": {
"types": "./fp/toDateWithOptions/index.d.ts",
"import": "./esm/fp/toDateWithOptions/index.js",
"require": "./fp/toDateWithOptions/index.js"
},
"./fp/toZonedTime": {
"types": "./fp/toZonedTime/index.d.ts",
"import": "./esm/fp/toZonedTime/index.js",
"require": "./fp/toZonedTime/index.js"
},
"./fp/zonedTimeToUtc": {
"types": "./fp/zonedTimeToUtc/index.d.ts",
"import": "./esm/fp/zonedTimeToUtc/index.js",
"require": "./fp/zonedTimeToUtc/index.js"
"./fp/toZonedTimeWithOptions": {
"types": "./fp/toZonedTimeWithOptions/index.d.ts",
"import": "./esm/fp/toZonedTimeWithOptions/index.js",
"require": "./fp/toZonedTimeWithOptions/index.js"
}
},
"scripts": {
Expand Down Expand Up @@ -140,7 +165,6 @@
"date-fns": "^3.0.6",
"eslint": "^7.11.0",
"eslint-config-prettier": "^7.2.0",
"flow-bin": "^0.143.1",
"fs-promise": "^2.0.3",
"husky": "^4.3.0",
"jsdoc-to-markdown": "^7.0.1",
Expand Down
2 changes: 1 addition & 1 deletion scripts/_lib/listFPFns.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const fs = require('fs')

module.exports = listFPFns

const ignoredFiles = ['index.js', 'test.js', 'index.js.flow', 'package.json']
const ignoredFiles = ['index.js', 'test.js', 'package.json']

function listFPFns() {
const files = fs.readdirSync(path.join(process.cwd(), 'src', 'fp'))
Expand Down
2 changes: 1 addition & 1 deletion scripts/_lib/listFns.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const fs = require('fs')

module.exports = listFns

const ignoredFiles = ['locale', 'esm', 'fp', 'index.js', 'test.js', 'index.js.flow', 'package.json']
const ignoredFiles = ['locale', 'esm', 'fp', 'index.js', 'test.js', 'package.json']

function listFns() {
const files = fs.readdirSync(path.join(process.cwd(), 'src'))
Expand Down
Loading

0 comments on commit 3bcf1db

Please sign in to comment.