Why does tm_mday start at 1 and all other struct tm elements start at 0?

While answering another question , I told OP that it should correctly initialize its struct tm variable, but should be careful because it could not just use

 struct tm mytime; memset(&mytime, 0, sizeof(mytime)); 

because not all struct tm fields are valid from 0 . A closer look at struct tm showed me that this is exactly one struct tm field that does not have 0 as a real value, namely tm_mday :

 int tm_sec seconds [0,61] int tm_min minutes [0,59] int tm_hour hour [0,23] int tm_mday day of month [1,31] int tm_mon month of year [0,11] int tm_year years since 1900 int tm_wday day of week [0,6] (Sunday = 0) int tm_yday day of year [0,365] int tm_isdst daylight savings flag 

Why? What were the thoughts behind the decision that for this element itself 0 would not be a valid value ???

+6
source share
2 answers

This makes sense if you accept the following two rules:

  • Save the value starting with 1 if this allows you to get the simplest display without having to add or subtract one of the common date formats.
  • In all other cases (or when the first rule can go anyway depending on the format), save the value starting from 0

Rule Application:

  • tm_sec , tm_min , tm_hour displayed starting at 0, so save it starting at 0. In a 12-hour format, the first hour is 12, and the rest can be displayed โ€œas isโ€, starting from 0.
  • tm_mday displayed starting at 1, so saving starts at 1
  • tm_mon displayed starting from 1 in dates, such as 24/02/1964, but it also makes sense to store starting from 0 for the convenience of indexing rows in an array for dates such as February 24, 1964, so you can go anyway โ†’ start with 0
  • 20th century tm_year can be displayed as is in a two-year format, for example. 24/02/64, or add 1900, there is no case when starting with 1 makes sense
  • tm_wday Usually displayed by indexing a string array starting at 0
  • tm_yday There is no clear reason to start working with 1 for ease of display, starting at 0

So, tm_mday is the only case when there is a clear advantage for storing it starting from 1 for ease of display in all common cases.

The reference implementation of asctime from C-89 standard is consistent with this, the only setting for any of the values โ€‹โ€‹related to add 1900 to tm_year :

  char *asctime(const struct tm *timeptr) { static const char wday_name[7][3] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static const char mon_name[12][3] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static char result[26]; sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", wday_name[timeptr->tm_wday], mon_name[timeptr->tm_mon], timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec, 1900 + timeptr->tm_year); return result; } 
+3
source

I think that babylonians decided to use number 1 on the first day of the month (for obvious reasons), because they have not yet invented number 0 .

(for the same reason that year 1 is the AC of the first year)

Since then, no one has changed the number of months.

0
source

All Articles