246

When initializing a new Date object in JavaScript using the below call, I found out that the month argument counts starting from zero.

new Date(2010, 3, 1);  // that's the 1st April 2010!

Why does the month argument start from 0? On the other hand, the day of the month argument (last one) is a number from 1 to 31. Are there good reasons for this?

Agnel Kurian
  • 57,975
  • 43
  • 146
  • 217

10 Answers10

224

The real answer to this question, is that it was copied from java.util.Date, which also had this quirk. Proof can be found on Twitter from Brendan Eich - the guy who originally implemented JavaScript:

https://twitter.com/BrendanEich/status/481939099138654209

First Tweet, which says: "In case it helps (it doesn't for most), JS's Date is a copy of Java's JDK1.0 (1995) java.util.Date.  Made it look like Java..."

https://twitter.com/BrendanEich/status/771006397886533632

Second Tweet, which says: "We were under "Make It Look Like Java" mgmt orders, and I had ten days to demo.  No time to invent our own date API or even fix Java's."

Brendan also indicates that it was Ken Smith of Netscape who did the porting from Java.

https://twitter.com/BrendanEich/status/771006208949891072

Third Tweet, which says: "Only Mocha src file I didn't create was mo_date.c: Ken Smith of Netscape helped me translate java.util.Date from Java to C."

This happened in 1995, and JDK 1.0 was in beta. It launched in 1996. In 1997, JDK 1.1 came out which deprecated the vast majority of functions on java.util.Date, moving them over to java.util.Calendar, but even that still had zero-based months. Developers fed-up with this created the Joda-Time library, which ultimately led to java.time package that's baked in to Java 8 (2014).

In short, it took 18 years for Java to get a correctly designed date/time API built-in, but JavaScript is still stuck back in the dark ages. We do indeed have excellent libraries like Luxon Moment.js, date-fns, js-joda, and others. But as of now, there is nothing more than Date built-in to the language. Hopefully this will change in the near future with the TC39 Temporal proposal.

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • 77
    Ah... Good old Demo-Driven Development methodology. – Álvaro González Feb 06 '17 at 10:25
  • 1
    @ÁlvaroGonzález I would blame original JDK 1.0 developer who introduced it in the first place. – barell Nov 02 '18 at 12:16
  • @barell Why would you blame the guy who modeled the very first version of Java, there is no language that got it all figured out since the first version. Java actually corrected their Date api but Javascript are still stuck to the old one, javascript devs should at least give us a new api just like Java did introducing LocalDate. – Yassir Khaldi Dec 25 '20 at 17:53
  • 4
    @Yassir - That work is underway. https://tc39.es/proposal-temporal/docs/ – Matt Johnson-Pint Dec 25 '20 at 19:18
  • Heads up on the last paragraph: not all is rosy even in more modern libraries. `Moment().month()` and date-fn's `getMonth()` are both still 0-based. Luxon and js-joda's month functions appear to be 1-based. – cincodenada Sep 03 '21 at 21:16
  • @YassirKhaldi — Why would you blame a guy who did a thing for doing that thing? I mean, even if it was the right decision, or the right decision at the time, it's still that person's fault that it is was done the way that it was. – M. Justin Sep 14 '21 at 18:27
87

It's an old (probably unfortunate, probably dying) tradition in the programming world, see the old standard (POSIX) localtime C function http://linux.die.net/man/3/localtime

leonbloy
  • 73,180
  • 20
  • 142
  • 190
  • 19
    JS `Date` object was ported from Java 1.0, that's why. Inheriting all its flaws ... http://stackoverflow.com/questions/344380/why-is-january-month-0-in-java-calendar – c69 Nov 10 '11 at 14:29
  • 3
    You are right, traditions are usually totally inconsistent and often times irrational and I would really hope that such "bad" traditions are really dying ... – henon Mar 07 '18 at 11:57
  • 3
    is 2019 and I am fixing an issue related to this behaviour, so as long as frameworks as angular and languages as javascript dont deprecate this it will still happen - feel free to coment in the year 2025 and on ;-) – Mauricio Gracia Gutierrez Oct 08 '19 at 14:39
  • 5
    That's a tradition that always make me spend time on debugging issues with dates... Wondering how much millings of wasted working hours this tradition caused. – Vedmant Jul 03 '20 at 03:30
  • 2
    It's *never* going to change. There's an incomprehensibly vast amount of existing code that assumes this behavior. (I mean, in JavaScript.) – Pointy Oct 01 '20 at 16:51
  • Potentially, we could get new retrieval functions that assume what we want to assume, with useful names, and deprecate the old ones. But changing the old ones would ruin everybody's day at this point. – coppereyecat May 07 '21 at 17:21
35

Everything but the day of the month is 0 based, see here for a full list including ranges :)

It's actually the 1 based days that are the oddballs here...oddly enough. Why was this was done? I don't know...but probably happened the same meeting they got plastered and decided semicolons were optional.

Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • 1
    The "ones-based" days thing is probably because no one in their right mind would ever create an array of string names for days (e.g., `{ "first", "second", "third", ..., "twenty-seventh", ... }`) and try to index it by `tm_mday`. Then again, maybe they just saw the absolute utility in making _off by one_ errors a regular occurrence. – D.Shawley Mar 31 '10 at 12:00
  • 4
    They why years are not 0 based? – Vedmant Jul 03 '20 at 03:31
  • 1
    @Vedmant there are (for practical purposes) an infinite number of years in both the negative and positive directions. The year isn't really "based" at all because it's not a fixed set of values. – Pointy Oct 01 '20 at 16:49
  • Imagine the day of the month being zero-based: index 0 => day 1; indez 1 => day 2; ... What could possibly go wrong? XD – jordisan Jun 14 '22 at 14:56
24

In 2023 the real question is:

If Date was broken from JS day one, why after 28 years (27 if you count from zero) it's still here?

JS has a lot of bad parts/quirks and the worst thing is that some of them haven't been fixed in decades (fun fact: we're talking about Date dates).

But we're lucky, it looks like the end of Date is near.

Spoiler

new Temporal.PlainDate(2020, 11, 26); // => 2020-11-26

Temporal (proposal)

From the proposal introduction:

Date has been a long-standing pain point in ECMAScript. This is a proposal for Temporal, a global Object that acts as a top-level namespace (like Math), that brings a modern date/time API to the ECMAScript language.

It's based, as reported in docs, "on common use cases we examined" and has a multiple types for different kinds of data:

  • Plain types do not have a timezone
  • ZonedDateTime types have a timezone
  • most types have a calendar
  • many useful types: Absolute, DateTime, Date, Time, TimeZone, ...

This is a schema that outline various Temporal types and their relationships JS Temporal proposal Types

You can read more about them in the available documentation and in the nice cookbook. Or explore current issues for open ones.

When Temporal will be available

Since March '21 it's in Stage 3/Draft (see TC39 stages reference). See TC39 March '21 slides.

Now it can be included in TypeScript soon, since their policy is:

When new features have reached stage 3, then they are ready for inclusion in TypeScript.

Probably for Node and major browsers we'll need to wait more.

Start experimenting today

In the meanwhile you can experiment with it using the Temporal polyfill.

npm install --save proposal-temporal

// temporal-test.js
const { Temporal } = require('proposal-temporal');

// or as an ES module
// import { Temporal } from 'proposal-temporal/lib/index.mjs';

// 11 means November now!
const date = new Temporal.PlainDate(2020, 11, 26); // => 2020-11-26

const sameDate = Temporal.PlainDate.from(
                {year: 2020, month: 11, day: 26}); // => 2020-11-26
lifeisfoo
  • 15,478
  • 6
  • 74
  • 115
8

I know it's not really an answer to the original question, but I just wanted to show you my preferred solution to this problem, which I never seem to memorize as it pops up from time to time.

The small function zerofill does the trick filling the zeroes where needed, and the month is just +1 added:

function zerofill(i) {
    return (i < 10 ? '0' : '') + i;
}

function getDateString() {
    const date = new Date();
    const year = date.getFullYear();
    const month = zerofill(date.getMonth()+1);
    const day = zerofill(date.getDate());
    return year + '-' + month + '-' + day;
}

But yes, Date has a pretty unintuitive API, I was laughing when I read Brendan Eich's Twitter.

Christof Kälin
  • 1,384
  • 2
  • 17
  • 26
5

There are always 12 months in a year, so early C implementations might have used a static fixed-width array with indexes 0..11.

Jonathan Julian
  • 12,163
  • 2
  • 42
  • 48
  • 3
    The Java Date/Calendar implementation maintains support for an extra month for some calendars. http://en.wikipedia.org/wiki/Undecimber – Pointy Mar 31 '10 at 11:43
4

Its like this in java too.. Probably to convert int to string (0 - jan,, 1-feb), they coded this way.. because they might have an array of string (indexed from 0) of month names and these month numbers if they start from 0, it'll be lot easier to map to the month strings..

raj
  • 3,769
  • 4
  • 25
  • 43
2

They might've considered months to be an enumeration (first index being 0) and days not since they don't have a name associated with them.

Or rather, they thought the number of the day was the actual representation of the day (the same way months are represented as numbers in a date like 12/31), as if you could make a enumeration with numbers as the variables, but actually 0-based.

So actually, for the months, perhaps they thought the proper enumeration representation would be to use the month's name, instead of numbers, and they would've done the same if days had a name representation. Imagine if we'd say January Five, January Sixth, instead of January 5, January 6, etc., then perhaps they'd have made a 0-based enumeration for days too...

Perhaps subconsciously they thought about an enumeration for months as {January, February, ...} and for days as {One, Two, Three, ...}, except for days you access the day as a number rather than the name, like 1 for One, etc., so impossible to start at 0...

user
  • 675
  • 4
  • 11
  • You should dual-class to Psychologist. It's still a mistake they made, but at least we now understand why they made it. – Zesty Mar 10 '20 at 07:42
0

It might be a flaw, but it's also very handy when you want to represent the months or day of the week as a string you can just create an array like ['jan,'feb' ...etc][new Date().getMonth()] in stead of ['','jan',feb ...etc][new Date().getMonth()] or ['jan','feb' ...etc][new Date().getMonth()-1]

days of the month are normaly not named so you won't be making arrays with names for those. In this case 1-31 is easier to handle, so you want have to subtract 1 every time...

Rogier
  • 71
  • 6
  • not really. You could easily just subtract one. It creates more problems than it solves because now when you do math with dates, you have to do specific manipulation on the month rather often. – Rey Nov 17 '15 at 23:21
-1

the simple solution new Date(year,month,day) : -

let year = 2022
let month = 4
let day = 25
//use 
new Date(year,month-1,day)
JaNith RathNayaka
  • 101
  • 1
  • 2
  • 10
  • 1
    I think it's generally understood from the question that one has to do this. I think the question is more about *why* you have to, to which the answer is "Because JS Date was based on Java's and the creator didn't have time to think about all the negative repercussions that this would have." – General Grievance Jan 26 '22 at 16:07