I have a problem showing the same date in all timezones.
Users input is for example 01-01-2002 and I store it like a date with Eureope/Berlin
timezone
parseFromTimeZone(String(birthDate), { timeZone: 'Europe/Berlin' })
and the result of parseFromTimeZone
is this string '2001-12-31T23:00:00.000Z'
. String date counts with timezone in Berlin that is why it is shifted for one hour.
And I need to get from '2001-12-31T23:00:00.000Z'
this 01-01-2002
in all timezones.
I using formatISO(new Date(date), { representation: 'date' }))
this returns 01-01-2002
when my timezone is Europe/Prague
or Europe/Berlin
but when I change the timezone to America/Tijuana
then formatISO
returns 2001-12-31
and that is wrong I need to have the same date as is in Europe/Berlin
always! Bud for Asia/Tokyo
this function returns 01-01-2002
that is right ...
Some ideas? I have tried a lot of solutions but none works for all timezones...
I am using "date-fns": "^2.15.0"
, "date-fns-timezone": "^0.1.4"
The Date
object, despite its name, is does not represent a "date". It represents a timestamp. All that it stores internally is the number of milliseconds since the Unix epoch (which is UTC based). It outputs values based on either UTC or the local time zone of the machine where its running, depending on the function being called.
Thus, if you construct a Date
object from a date-only value, you're really taking "the time at midnight" from that time zone and adjusting it to UTC. This is demonstrated by your example of 2002-01-01
in Europe/Berlin
. Your treating that as 2002-01-01T00:00:00.000+01:00
, which indeed has a UTC equivalent of 2001-12-31T23:00:00.000Z
, and thus doesn't carry the same year, month, and day elements as the intended time zone.
You really only have two options to deal with date-only values if you want to prevent them from shifting:
Your first option is to use the Date
object, but treat the input as UTC and only use the UTC-based functions. For example:
var dt = new Date(Date.UTC(2002, 0, 1)); // "2002-01-01T00:00:00.000Z"
var y = dt.getUTCFullYear(); // 2002
var m = dt.getUTCMonth() + 1; // 1
var d = dt.getUTCDate(); // 1
var dtString = d.toISOString().substring(0, 10) // "2002-01-01"
If you need to parse a date string, be aware that current ECMAScript spec treats date-only values as UTC (which is what you want), but in the past such behavior was undefined. Thus some browsers might create a local-time result from new Date('2002-01-01')
. You may want to explicitly add the time and Z
, as in new Date('2002-01-01' + 'T00:00:00.000Z')
to be on the safe side.
If you intend to use date-fns, be careful - the parseISO
and formatISO
functions use local time, not UTC.
The second option is to not use the Date
object. Keep the dates in their string form (in ISO 8601 yyyy-mm-dd format), or keep them in a different object of either your own construction or from a library.
The ECMAScript TC39 Temporal proposal is intended to fix such deficiencies in JavaScript. In particular, the Temporal.Date
object (preliminary name) will be able to be used for date-only values without having the shifting problem you and so many others have encountered. The proposal is currently in Stage 2 of the ECMAScript process, so it's not available to use today, but this problem will be solved eventually!