The Date
javascript nay stores Timezone information. Despite the name, the Date
is not quite a date (in the sense of representing a single value of day, month, year, hour, minute and second).
How so?
In fact, the Date
represents a timestamp: the quantity of milliseconds since the Unix Epoch (which in turn amounts to 1970-01-01T00:00Z
- January 1, 1970 at midnight, at UTC).
When you pass a string like '2020-06-03T12:05:03-05:00'
, he creates a Date
the timestamp of which is equivalent to this date, time and offset. But to the flaunt this date (with toString()
, for example), it is converted to browser time zone.
So much so that if you create instances of Date
with different strings, but corresponding at the same time, you will see that the timestamp value will be the same:
var d1 = new Date("2020-06-03T12:05:03-05:00");
var d2 = new Date("2020-06-03T13:05:03-04:00");
console.log(d1.getTime(), d2.getTime()); // 1591203903000 1591203903000
console.log(d1);
console.log(d2);
The two above dates have the same timestamp value, and therefore correspond to the same instant. The fact that they were generated with different strings is a detail, since the strings were used to calculate the value of the timestamp, but Timezone information is not stored in the Date
(only the value of timestamp).
When printing them, the timestamp is converted to the browser’s time zone, and the output is the same for both.
Another point is that actually the value -05:00
is a offset (the difference with respect to UTC), and not a Timezone in fact (see here to learn more).
Timezones have identifiers such as America/Sao_Paulo
and Asia/Tokyo
, and they actually have a history of offsets used throughout history, in a particular region. For example, America/Sao_Paulo
corresponds to the Time of Brasilia, and generally uses the offset -03:00
, but during daylight time it changes to -02:00
. This whole history is part of the Timezone (when each offset is used, when transitions occur, etc), and the offset may vary according to the date you have (whether at that time it was in daylight saving or not).
So that the exit has the offset -05:00
, you would need to know which Timezone owns this offset at that particular moment (and there is more than one inclusive, and this varies according to date and time, since these timezones can also have daylight savings time and use another offset depending on the season).
An alternative (still incomplete as almost does what you need) is to use toLocaleString
passing a Timezone:
var data = new Date("2020-06-03T12:05:03-05:00");
console.log(data.toLocaleString('pt-BR', { timeZone: 'America/Rio_Branco' }));
The problem is that the above output does not contain the offset, since the format depends on the locale informed (in this case, I used pt-BR
- português do Brasil). Unfortunately Javascript does not provide much more resources to handle the date the way you need it.
An alternative is to use the Moment js., together with the Moment Timezone. Even so we need to pass some Timezone whose offset be it -05:00
on the date in question.
let data = moment.tz("2020-06-03T12:05:03-05:00", "America/Chicago");
console.log(data.format()); // 2020-06-03T12:05:03-05:00
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data.min.js"></script>
But there is also a way to preserve the past Timezone, using parseZone
:
let data = moment.parseZone("2020-06-03T12:05:03-05:00");
console.log(data.format()); // 2020-06-03T12:05:03-05:00
// outro formato
console.log(data.format('ddd, MMM DD YYYY, HH:mm:ss Z')); // Wed, Jun 03 2020, 12:05:03 -05:00
// converter para Date
let d = data.toDate();
console.log(d); // não preserva mais o -05:00, pois Date não guarda o timezone
<script src="https://momentjs.com/downloads/moment.min.js"></script>
Gambiarra that you will probably see around
Before anyone suggests gambiarra, I’ll show myself and explain why it’s not a good idea:
function converter(data, offset) {
data.setTime(data.getTime() + offset * 3600 * 1000);
let s = offset < 0 ? "-" : "+";
return data.toISOString().slice(0, -1) + s + Math.abs(offset).toString().padStart(2, '0') + ":00";
}
var d1 = new Date("2020-06-03T12:05:03-05:00");
console.log(converter(d1, -5)); // 2020-06-03T12:05:03.000-05:00
Although it seems like a good idea ("worked, showed the correct date and time!"), it’s not, because when using setTime
we are changing the value of timestamp, and the date will represent a different instant.
It’s as if my computer was configured with the London time zone (but I’m in Brazil). Here it is 15h, but in London it is 19h (the English are in daylight time). So the computer clock shows 19h.
I can fix it the right way (changing the time zone settings of the computer), or I can hack and delay my watch by 4 hours: it will show the value "correct" (15h), but actually I changed the value it represents (now it indicates that it is 15h in London, an instant 4 hours in the past).
This is what I do by changing the value of the date: it represents a different moment and depending on what you need to do with it, it will give wrong results (just because it shows the value "correct", it does not mean that everything is right).
See more about dates here and here.
You might want to start storing your dates in Unixtimestamp so you can use libraries like Moment.js or even native Apis. Take a look at this answer might help you understand better: https://answall.com/questions/285238#285388 PS: always save the captured timestamp to the server
– Lauro Moraes
Welcome to the wonderful chaotic world of date handling in Javascript. The js have many good things but certainly the treatment of dates is not one of them. It is a real chaos. As someone who has spent many hours banging his head with Javascript’s Dates and Timezones I advise you: don’t waste your time, use Moment.js soon or you will be forced to use it after hitting it hard.
– Nelson Teixeira