The "Z" at the end of 2019-10-18T11:23:27.756Z
indicates that this date and time is in UTC.
Already when printing the Date
, notice that he possesses GMT-0300
, indicating 3 hours behind UTC.
That is, both represent at the same moment. This is a somewhat confusing point, but the Date
javascript, despite the name, it does not represent a single date and time value (a single day, month, year, time, minute and second specific).
She actually represents a timestamp: the amount of milliseconds since the Unix Epoch. This value represents a single instant, a specific point in the timeline. Only that the same timestamp can represent a different date and time depending on the time zone (just think that right now, in each part of the world the "day of today" and the "current time" may be different depending on the time zone you are in).
Therefore, when printing a Date
with console.log
, it shows you the value considering the Timezone browser. But when sending Date
in a request, it is converting it to UTC. But the value of the Date
(your timestamp, the instant it corresponds to) has not been changed.
In this case, the backend take this date and convert to the correct Timezone (and each language has its ways to do this).
The locale controls language and location settings, but does not interfere with the time zone used, they are different things. I can use the locale corresponding to the Portuguese language, but showing the date in a time zone of any other country, one thing is not related to another.
When changing the value of timestamp, as suggested another answer (which has been deleted), you will be changing the instant at which the date corresponds. It may "work," but it’s not ideal, depending on what you want to do.
To better understand, an analogy. Now in Brazil it is 10:20 and in London it is 14:20 (the English are in summer time, hence the difference of 4 hours). Imagine that my computer is misconfigured with the London zone, then it shows 14:20.
For him to show the right time, I can do two things:
- change the computer configuration to Brasilia Time
- delay the clock by 4 hours
In both cases, the time will be shown as 10:20, but the second option is worse, because now my watch is indicating an instant in the past. This is what happens when you manipulate the value of timestamp, and this is the error of the other answer. Although the value shown is "correct", you created a Date
corresponding to a different instant, and depending on what you will do with the date, may give incorrect results.
Besides, the difference won’t always be four hours. When London is not in daylight saving time, the difference is 3 hours, except that when Brasilia Daylight Saving Time is in daylight saving time, the difference is 2 hours (but there have been periods when both are in summer time, and the difference is back to 3 hours, since in many years, summer time in Brazil began in early October, and in England ended in late October, then for a few days both were in daylight time).
In the specific case of Brazil, this year we will not have summer time, But since this is something defined by the government, there’s no guarantee that it won’t change in the future. So manipulating the value of timestamp still has this other disadvantage: it won’t be synchronized with real-world changes. You would have to consult Timezone information to know if you use 2 or 3 hours for your calculation.
That is, using fixed values to make this calculation is extremely prone to errors, and the ideal is always to use the correct Timezone.
Unfortunately Javascript does not have a decent way to convert between time zones. The most you can do is get the date and time values in the Timezone browser or in UTC. If you want in the same format above, but using the browser Timezone, you have to do it manually:
function pad(value) {
return value.toString().padStart(2, 0);
}
let d = new Date();
console.log(`${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`);
The difference is you won’t get the Z
at the end because it is no longer in UTC. In that case, you will have to assume that the backend knows which Timezone it is in. You can still use d.getTimezoneOffset()
, which returns the difference in minutes with respect to UTC. In the case of Brasília Time, the return is 180 (or 120 when it is in daylight saving time). If you want, you can send this information separately, so that the backend can do the conversion correctly.
Note also that I had to add 1 in the month, because in Javascript months are indexed to zero (January is zero, February is 1, etc).
Moment js.
You can use the Moment js., together with the Moment Timezone, to manipulate the dates in the correct Timezone:
let d = moment.tz('America/Sao_Paulo');
console.log(d.format()); //2019-10-18T10:32:31-03:00
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data.min.js"></script>
Thus, it sends the date in the correct Timezone (ex: 2019-10-18T10:32:31-03:00
), without relying on the browser’s Timezone, and you can manipulate in the way you think best in the backend.
The names of timezones (such as America/Sao_Paulo
) are defined by IANA and are always suffering constant updates (It keeps track of daylight saving time changes around the world, so you don’t have to worry about it: just use the right Timezone and the API does the rest). With Moment.js you can have a list of available timezones using moment.tz.names()
:
console.log(moment.tz.names());
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data.min.js"></script>
Angular
On the Angular, he seems to use JSON.stringify
to convert the Date
, when sending it on an HTTP request lacks sources, but I’m looking for.
Anyway, I did a quick test, following the idea of this answer:
// aproveitando a função pad() já vista anteriormente
Date.prototype.toJSON = function() {
return `${this.getFullYear()}-${pad(this.getMonth() + 1)}-${pad(this.getDate())}T${pad(this.getHours())}:${pad(this.getMinutes())}:${pad(this.getSeconds())}`;
}
By doing this, all dates sent via HttpClient
are converted using the above function (which you can adapt to whatever you need).
Of course this will change for all instances of Date
of your project (which by the comments below seems to be the case).
Use
LocalDateTime.now()
java 8.– Collura