Skip to content

Commit 71359df

Browse files
Merge pull request #6068 from Hacker0x01/timezone-support
Timezone support
2 parents 45ed908 + 94457ed commit 71359df

File tree

10 files changed

+1874
-1746
lines changed

10 files changed

+1874
-1746
lines changed

.stylelintrc.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"at-rule-no-unknown": null,
88
"at-rule-disallowed-list": ["import"],
99
"scss/at-rule-no-unknown": true,
10+
"scss/dollar-variable-colon-space-after": null,
1011
"scss/dollar-variable-pattern": null,
1112
"scss/at-import-partial-extension": null,
1213
"scss/no-global-function-names": null,

docs-site/src/components/Examples/config.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ import YearItemNumber from "../../examples/ts/yearItemNumber?raw";
112112
import WeekPicker from "../../examples/ts/weekPicker?raw";
113113
import ExcludeWeeks from "../../examples/ts/excludeWeeks?raw";
114114
import ExternalForm from "../../examples/ts/externalForm?raw";
115+
import Timezone from "../../examples/ts/timezone?raw";
115116

116117
export const EXAMPLE_CONFIG: IExampleConfig[] = [
117118
{
@@ -581,4 +582,10 @@ export const EXAMPLE_CONFIG: IExampleConfig[] = [
581582
title: "External Form",
582583
component: ExternalForm,
583584
},
585+
{
586+
title: "Timezone",
587+
description:
588+
"Display and handle dates in a specific timezone using the timeZone prop. Requires date-fns-tz as a peer dependency.",
589+
component: Timezone,
590+
},
584591
];
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const Timezone = () => {
2+
const [selectedDate, setSelectedDate] = useState<Date | null>(new Date());
3+
4+
return (
5+
<DatePicker
6+
selected={selectedDate}
7+
onChange={setSelectedDate}
8+
showTimeSelect
9+
timeFormat="HH:mm"
10+
timeIntervals={15}
11+
dateFormat="MMMM d, yyyy h:mm aa (zzz)"
12+
timeZone="America/New_York"
13+
/>
14+
);
15+
};
16+
17+
render(Timezone);

docs-site/yarn.lock

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4694,8 +4694,12 @@ __metadata:
46944694
clsx: "npm:^2.1.1"
46954695
date-fns: "npm:^4.1.0"
46964696
peerDependencies:
4697+
date-fns-tz: ^3.0.0
46974698
react: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc
46984699
react-dom: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc
4700+
peerDependenciesMeta:
4701+
date-fns-tz:
4702+
optional: true
46994703
languageName: node
47004704
linkType: soft
47014705

docs/timezone.md

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,112 @@
22

33
This guide explains how react-datepicker handles timezones and provides solutions for common timezone-related scenarios.
44

5-
## The "Date is One Day Off" Problem (Issue #1018)
5+
## Using the `timeZone` Prop
6+
7+
React-datepicker now supports a `timeZone` prop that allows you to display and handle dates in a specific timezone, regardless of the user's local timezone. This feature requires the optional `date-fns-tz` peer dependency.
8+
9+
### Installation
10+
11+
To use the `timeZone` prop, you need to install `date-fns-tz`:
12+
13+
```bash
14+
npm install date-fns-tz
15+
# or
16+
yarn add date-fns-tz
17+
```
18+
19+
### Basic Usage
20+
21+
```jsx
22+
import DatePicker from "react-datepicker";
23+
24+
function MyComponent() {
25+
const [startDate, setStartDate] = useState(new Date());
26+
27+
return <DatePicker selected={startDate} onChange={(date) => setStartDate(date)} timeZone="America/New_York" />;
28+
}
29+
```
30+
31+
### How It Works
32+
33+
When you provide a `timeZone` prop:
34+
35+
1. **Display**: Dates are displayed in the specified timezone. For example, if you select January 15th at noon UTC and the timezone is "America/New_York", the datepicker will display the date as it appears in New York time.
36+
37+
2. **Selection**: When a user selects a date, the `onChange` callback receives a Date object that represents the selected moment in UTC. The internal conversion ensures that the date selected visually in the specified timezone is correctly converted.
38+
39+
3. **Current Time**: The "today" indicator and default selections use the current time in the specified timezone.
40+
41+
### Supported Timezone Formats
42+
43+
The `timeZone` prop accepts IANA timezone identifiers:
44+
45+
- `"UTC"` - Coordinated Universal Time
46+
- `"America/New_York"` - Eastern Time (US)
47+
- `"America/Los_Angeles"` - Pacific Time (US)
48+
- `"Europe/London"` - British Time
49+
- `"Europe/Paris"` - Central European Time
50+
- `"Asia/Tokyo"` - Japan Standard Time
51+
- `"Australia/Sydney"` - Australian Eastern Time
52+
53+
For a complete list, see the [IANA Time Zone Database](https://www.iana.org/time-zones).
54+
55+
### Examples
56+
57+
#### Date and Time Picker in a Specific Timezone
58+
59+
```jsx
60+
import DatePicker from "react-datepicker";
61+
62+
function TimezoneDateTimePicker() {
63+
const [date, setDate] = useState(new Date());
64+
65+
return <DatePicker selected={date} onChange={setDate} showTimeSelect timeZone="Europe/London" dateFormat="MMMM d, yyyy h:mm aa" />;
66+
}
67+
```
68+
69+
#### Date Range in UTC
70+
71+
```jsx
72+
import DatePicker from "react-datepicker";
73+
74+
function UTCDateRange() {
75+
const [startDate, setStartDate] = useState(null);
76+
const [endDate, setEndDate] = useState(null);
77+
78+
const onChange = (dates) => {
79+
const [start, end] = dates;
80+
setStartDate(start);
81+
setEndDate(end);
82+
};
83+
84+
return <DatePicker selected={startDate} onChange={onChange} startDate={startDate} endDate={endDate} selectsRange timeZone="UTC" />;
85+
}
86+
```
87+
88+
#### Inline Calendar with Timezone
89+
90+
```jsx
91+
import DatePicker from "react-datepicker";
92+
93+
function TokyoCalendar() {
94+
const [date, setDate] = useState(new Date());
95+
96+
return <DatePicker selected={date} onChange={setDate} inline timeZone="Asia/Tokyo" />;
97+
}
98+
```
99+
100+
### Important Notes
101+
102+
- **Optional Dependency**: The `timeZone` prop requires `date-fns-tz` to be installed. If it's not installed and you use the `timeZone` prop, a warning will be logged in development mode and the datepicker will fall back to local timezone behavior.
103+
104+
- **UTC Storage**: Even when using a timezone, the Date objects passed to `onChange` represent moments in time (internally stored as UTC). The timezone only affects how dates are displayed and interpreted during selection.
105+
106+
- **Consistency**: When using the `timeZone` prop, ensure all date-related props (like `minDate`, `maxDate`, `excludeDates`, etc.) are provided in a consistent manner.
107+
108+
---
109+
110+
## The "Date is One Day Off" Problem
6111

7112
One of the most commonly reported issues is that the selected date appears to be "one day off" when converted to a string or sent to a server. This is **not a bug** in react-datepicker—it's the expected behavior of JavaScript Date objects.
8113

package.json

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,23 @@
2424
"./dist/": "./dist/",
2525
"./src/stylesheets/": "./src/stylesheets/"
2626
},
27-
"files": ["*.md", "dist", "lib", "es", "src"],
28-
"sideEffects": ["**/*.css"],
29-
"keywords": ["react", "datepicker", "calendar", "date", "react-component"],
27+
"files": [
28+
"*.md",
29+
"dist",
30+
"lib",
31+
"es",
32+
"src"
33+
],
34+
"sideEffects": [
35+
"**/*.css"
36+
],
37+
"keywords": [
38+
"react",
39+
"datepicker",
40+
"calendar",
41+
"date",
42+
"react-component"
43+
],
3044
"repository": {
3145
"type": "git",
3246
"url": "git://github.com/Hacker0x01/react-datepicker.git"
@@ -65,6 +79,7 @@
6579
"babel-jest": "^30.0.2",
6680
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
6781
"core-js": "^3.46.0",
82+
"date-fns-tz": "^3.2.0",
6883
"eslint": "^9.19.0",
6984
"eslint-config-prettier": "^10.0.1",
7085
"eslint-plugin-import": "^2.31.0",
@@ -96,9 +111,15 @@
96111
"typescript-eslint": "^8.22.0"
97112
},
98113
"peerDependencies": {
114+
"date-fns-tz": "^3.0.0",
99115
"react": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc",
100116
"react-dom": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc"
101117
},
118+
"peerDependenciesMeta": {
119+
"date-fns-tz": {
120+
"optional": true
121+
}
122+
},
102123
"dependencies": {
103124
"@floating-ui/react": "^0.27.15",
104125
"clsx": "^2.1.1",
@@ -128,7 +149,10 @@
128149
"prepare": "husky"
129150
},
130151
"lint-staged": {
131-
"*.{js,jsx,ts,tsx,json,css,scss,md}": ["prettier --write", "git add"]
152+
"*.{js,jsx,ts,tsx,json,css,scss,md}": [
153+
"prettier --write",
154+
"git add"
155+
]
132156
},
133157
"packageManager": "[email protected]"
134158
}

0 commit comments

Comments
 (0)