admin管理员组

文章数量:1129002

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?

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?

Share Improve this question asked Mar 31, 2010 at 11:34 Agnel KurianAgnel Kurian 59.4k47 gold badges154 silver badges226 bronze badges 10
  • 249 It is just to keep you on your toes. – SeanJA Commented Mar 31, 2010 at 11:36
  • 9 One that is also zero indexed is the Day of the week (integer) 0-6 – SeanJA Commented Mar 31, 2010 at 11:37
  • 1 Because it was coded for machines and not for humans. But it is still a huge source of bugs because a lot of code is (still) written by humans :) – Christophe Roussy Commented Jun 6, 2016 at 14:15
  • 11 @Christophe the same argument should apply to day and year also. – Agnel Kurian Commented Jun 6, 2016 at 14:28
  • 7 @ChristopheRoussy yeah, if it were coded for machines, why index days from 1 then? – user151496 Commented Mar 28, 2018 at 8:28
 |  Show 5 more comments

10 Answers 10

Reset to default 248

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

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

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

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

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.

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

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.

In 2024 the real question is:

If Date was broken from JS day one, why after 29 years (28 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

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

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.

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

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..

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...

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...

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

let year = 2022
let month = 4
let day = 25
//use 
new Date(year,month-1,day)

本文标签: datetimeWhy does the month argument range from 0 to 11 in JavaScript39s Date constructorStack Overflow