When you pass a string in this format to the builder of Date
, he uses the same method rule Date.parse()
.
In this case, the string contains only day, month and year in format ISO 8601, and this information is completed with the time of midnight, at UTC.
The problem is that toLocaleDateString
uses the browser Timezone (which will not necessarily be the same as UTC) to get the values of the day, month and year. My browser, for example, is using the Brazilian time zone (Official Time of Brasilia).
And as 15 January 2019, at midnight in UTC, corresponds to 14 January 2019, at 22h in Brasilia time, this difference occurs (normally the Brasilia time is 3 hours behind the UTC, but in January 2019 it was in daylight time, so it was only 2 hours less, and depending on the region you are in, the difference with the UTC may have another value - anyway, your browser’s Timezone is some that is a few hours before UTC, hence the difference).
Some solutions (besides setting Timezone to UTC, as already suggested in the other answers):
Add time (ugly, but suggested by the documentation itself and it works, because then it starts to consider midnight in the browser Timezone):
let d = new Date("2019-01-15T00:00");
console.log(d.toLocaleDateString('pt-BR')); // 15/01/2019
Remembering to put the lyrics T
before the time, in the format defined by ISO 8601 standard.
Do the Parsing manually:
let [ano, mes, dia] = '2019-01-15'.split('-').map(v => parseInt(v));
let d = new Date(ano, mes - 1, dia);
console.log(d.toLocaleDateString('pt-BR'));
// Ou, caso o seu browser não seja compatível com ES6:
let partes = '2019-01-15'.split('-');
ano = parseInt(partes[0]);
mes = parseInt(partes[1]);
dia = parseInt(partes[2]);
d = new Date(ano, mes - 1, dia);
console.log(d.toLocaleDateString('pt-BR'));
Remembering that in this API January is zero, February is 1, etc, so you have to subtract 1 of the month when passing to the constructor of Date
.
Using a library like Moment js.:
let d = moment("2019-01-15");
console.log(d.format("DD/MM/YYYY"));
<script src="https://momentjs.com/downloads/moment.min.js"></script>
Or, to use the specific format according to the locale, use the moment-with-locales
:
moment.locale('pt-BR'); // setar o locale para Português
let d = moment("2019-01-15");
console.log(d.format("L"));
<script src="https://momentjs.com/downloads/moment-with-locales.min.js"></script>
Being a bit pedantic: actually the locale only controls the format (if it is d/m/y, y-m-d, etc). But the values date and time come from the browser Timezone, so much so that it is done
new Date("2019-01-15").toLocaleDateString('ja-JP')
(locale of Japan), the value of the day continues 14, even if in Japan the equivalent date is 15 (because they are in UTC+9) - will only change the format, the values will not. And depending on the region of Brazil, will not necessarily be UTC-3: if it is regions with daylight saving time, in January is -2 (southeast) or -3 (center west), if it is in the northeast is -3, but in the Amazon is -4, etc :-)– hkotsubo
Yes, true friend. I got confused
locale
withtimeZone
. Thanks for the warning!– Rafael Laurindo