从零开始的月份编号

一些流行的编程语言使用的月份编号误差为1——我想到了 JavaScript,Java 也是如此,如果内存足够的话,C 是另一种编号方式。我有几个问题:

  • 如果你打算忽略非专业人士使用的月份编号,那么为什么不为了一致性也忽略非专业人士使用的 白天编号,并从0开始计算每个月的天数呢?
  • 为什么这么常见?
  • 这一开始是谁的主意?
25225 次浏览

It is what it is, and the huge weight of software built to that assumption means it's going to be around for a while.

My opinion is that it was the fault of C, and all those other Johnie-come-lately languages just conformed with it.

You get some funny situations from people who don't know better. One of the few Y2K bugs our team found was a web site proudly proclaiming the year was 19100 simply because they prefixed the struct tm year with the literal "19".

Yes, the Romans had problems with zero as well.

This is just a [non-intuitive] consequence of mathematics (being a strong component of programming, especially early programming) defining zero as the first (problematic term that one) real, positive* natural number, and since an array is indexed with real, natural numbers the "first" element is at index 0.

Months are really named values in an array, where days and years are numbered values - it would perhaps be more useful to think of days/years as being in arrays which look like { "1", "2", "3", ... } themselves.

As to why this is so common (apart from being mathematically correct) well all the languages you listed descend from a common origin for one thing...

Edit:

Looking further into it, this wikipedia link details several good and interesting reasons for zero indexing (which does not directly speak to why months are zero-indexed but I think that's covered already), and this SO link has answered the question before.

Looks like the prevailing opinion is either "historical accident" or "because months are not numbers so cannot be compared to day/year storage" depending on who you ask.

* Sorry, sorry, physics!=maths coming back to bite me there. Off to iron my hands now.

The use of zero to start counting is actually an optimization trick from Assembly programmers. Instead of assigning 1 to the count register, they XOR'ed the register with itself, which was slightly faster in CPU cycles. This meant that counting would start with 0 and would always be up to the length of elements, excluding the last one.

Also, the use of zero is also popular with pointer arithmetics where you would use one base pointer pointing at some allocated memory, plus a second pointer which would be at an offset from this base pointer. Here, using the value zero makes a lot of sense to point the offset to the base of the memory block. (General array logic tends to be the base address plus the offset x record size.)

And zero-based month numbers? Often, many programming environments calculate the data as a number of days since some default data. December 31, 1899 is a popular date, although there have been plenty of other dates used as base date. All other dates are offset from this base, and will just be stored as one single number. Fractions would be used to indicate hours, minutes and seconds, where 0.25 would be 24/4 = 6 hours. Thus, to transform a date into a real date, all the environment has to do is transform this number into a real date.

However, the combination of zero-based arrays and 1-based month values does bring a problem. To get the month name of month 9, you would have to get item 8 from the month array. Some developers would be happy with decreasing the month number before getting it's name. Others preferred to change the month into something zero-based since people just want to know the name, not the number. It's a personal view.