Typescript - Incorrect code output - Date

Asked

Viewed 191 times

6

Why the output from that code is:

Pessoa {
  Id: 1,
  Name: 'Maicon Gabriel Friedel',
  DateOfBirth: 1997-02-22T03:00:00.000Z
}

Code:

import pessoa from './pessoa'

pessoa.Id = 1;
pessoa.Name = 'Maicon Gabriel Friedel'
pessoa.DateOfBirth = new Date(1997, 1, 22)

console.log(pessoa);
console.log(pessoa.DateOfBirth.getMonth())

Class Pessoa:

class Pessoa {
    Id: Number
    Name: String
    DateOfBirth: Date
}

export default new Pessoa()

I put the month 1, but on output comes out 2, what the hell happens? The script I run is tsc && node dist/index.js

And in the getMonth() he returns 1.

2 answers

8


It’s a little confusing, but according to documentation of Date, the numerical value of the month is indexed to zero. That is, January is zero, February is 1, etc.

Therefore, new Date(1997, 1, 22) creates a date for 22 de February de 1997. The method getMonth() also uses this same rule, so in that case it will return 1 (corresponding to February).

But when the date is printed via console.log, it is converted to some format (in this case, the format was "1997-02-22T03:00:00.000Z"), and then the month assumes the correct value (January is 1, February is 2, etc).

let d = new Date(1997, 1, 22);
console.log(d); // 1997-02-22T03:00:00.000Z
console.log(d.getMonth()); // 1


That is, depending on the situation, you have to try to use the values indexed in zero or 1.

In the builder of Date (when it receives numeric values) and in the return of getMonth() (and also in the past value for the method setMonth), values are indexed to zero.

The methods that format the date use the correct value (indexed in 1):

let d = new Date(1997, 1, 22);
console.log(d.getMonth()); // 1
console.log(d.toISOString()); // 1997-02-22T03:00:00.000Z
console.log(d.toLocaleDateString('pt-BR')); // 22/02/1997

// mudando o mês para dezembro
d.setMonth(11);
console.log(d.toISOString()); // 1997-12-22T02:00:00.000Z
console.log(d.toLocaleDateString('pt-BR')); // 22/12/1997


Another point that might confuse you a little bit more is that when you pass a string in the ISO 8601 format for the manufacturer, then the months must have the correct values:

// passando uma string no formato ISO 8601, fevereiro deve ser mês 2
let d = new Date('1997-02-22');
console.log(d.getMonth()); // 1
console.log(d.toISOString()); // 1997-02-22T00:00:00.000Z
console.log(d.toLocaleDateString('pt-BR')); // 21/02/1997

But note that in that case there was a difference: the time is midnight in UTC (the "Z" at the end indicates that it is in UTC), and toLocaleDateString returned day 21, because this method uses the browser Timezone (which in my case is in Brasilia Time), and as day 22 at midnight in UTC is equal to day 21 at 21h Brasilia Time, occurs this discrepancy.

When you use numeric values (new Date(1997, 1, 22)), the Date created corresponds to midnight in the browser Timezone (in this case, midnight in Brasilia time, which is equivalent to 3 am in UTC - so in the first case the time is printed as "03:00:00.000Z"). This behavior is explained in more detail here.


Just to make "even cooler" the builder of Date does not complain if you spend a month greater than 11:

let d = new Date(1997, 12, 22);
console.log(d); // 1998-01-22T02:00:00.000Z
console.log(d.getMonth()); // 0

That is, if it passes the month 12, it creates a date referring to January of the following year.

  • 1

    My God, what madness hahaahah!! Very good your explanation! Thank you very much!! Now I understand this madness.. Javascript and its crazy points :S

  • @Maikeaerosmith And note that dates aren’t even the craziest thing about Javascript, there are worse things: https://www.destroyallsoftware.com/talks/wat

5

TL;DR: There is nothing wrong and the code works perfectly. In fact, the "problem" is due to the behavior of Javascript when dealing with a date.


If you mess with the Javascript date object a little bit, Date, at some point you’ll work with months and do something like this:

console.log(new Date().getMonth());

Note that, even being, for example, in August (month 08 in our calendar), the output is 7. This happens because in Javascript, the months (and some more information, such as the days of the week) are worked with zero index, which means that:

  • January 0;
  • Feb 1;
  • March 2;
  • And so on and so forth...

That’s why, as I pass 1 in the date constructor, you are telling Javascript that the month is feb, since, as they work with zero index, January would be 0.

For more information, please read the documentation relating to getMonth and to the getDay, who has similar behaviour.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.