5

I was trying out the examples in expert C programming while I encountered this problem. My program basically does one thing: use the standard gmtime function and see how many years has past since 1970. Here is my program:

#include <stdio.h>
#include <time.h>

int main(int argc, char** argv) {
    time_t now = time(0);
    struct tm *t = gmtime(&now);
    printf("%d\n", t->tm_year);
    return 0;
}

The output is 117, the number of years past 1900. This is unexpected because I checked time() and man gmtime beforehand and they both said they are relative to the Epoch time (1970-1-1 00:00:00):

time() returns the time as the number of seconds since the Epoch,
1970-01-01 00:00:00 +0000 (UTC).

http://man7.org/linux/man-pages/man2/time.2.html

The ctime(), gmtime() and localtime() functions all take an argument of data type 
time_t, which represents calendar time.  When interpreted as an absolute time 
value, it represents the number of seconds elapsed since the Epoch, 1970-01-01 
00:00:00 +0000 (UTC).

http://man7.org/linux/man-pages/man3/ctime.3.html

According to the above description, my program should have returned 47 instead of 117. What is going on here?

macos sierra 10.12.5
Darwin 16.6.0 Darwin Kernel Version 16.6.0: Fri Apr 14 16:21:16 PDT 2017; root:xnu-3789.60.24~6/RELEASE_X86_64 x86_64
Apple LLVM version 8.1.0 (clang-802.0.42)
Rainbow Fizz
  • 77
  • 1
  • 1
  • 4
  • 4
    Because that's what the [doc says](http://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html) also [online manual](http://www.cplusplus.com/reference/ctime/tm/) – litelite Jul 27 '17 at 15:49
  • 1
    Also the man page: `tm_year The number of years since 1900.` – Mat Jul 27 '17 at 15:50
  • The section of the ctime(3) manpage you cite doesn't say anything about `tm_year`. It describes how to interpret the `time_t` value, which is the *argument* to `gmtime(3)`. – Ssswift Jul 27 '17 at 16:45
  • I don't see a requirement from the C standard for a specific zero-date. Can you provide a reference? Why do you cite Linux man-pages for OSX? – too honest for this site Jul 27 '17 at 16:52
  • Thanks for all the docs and man pages :D – Rainbow Fizz Jul 28 '17 at 04:51
  • ```tm_year``` is need to isolate the year in this century subtract 100. If need 2022 - can convert to string + "20" and back to integer as needed. – Andrew Bannerman Dec 25 '22 at 21:44

2 Answers2

10

The tm_year field is relative to 1900 on all POSIX-compliant platforms, not just on macOS.

The struct tm is designed for parsing, displaying, and manipulating human-readable dates. When it was created, dates were commonly written and even stored without the “19” part of the year number and the Y2K problem was around 25 years away. So the convenience of making tm_year directly printable as two digits, by making it relative to 1900, apparently seemed reasonable at the time.

Unix timestamps are relative to the “Unix epoch”, which is 1970-01-01 00:00:00 UTC. For the reasons why, see this Q&A.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
2

The tm_year member of struct tm is relative to 1900 per the C library specification. All compliant standard libraries use that.

The tm structure shall contain at least the following members, in any order. The semantics of the members and their normal ranges are expressed in the comments §7.27.2.1 4

...
int tm_year; // years since 1900

time() returns a time_t value "which may represent a calendar time based on a particular epoch". This is commonly 1970, Jan 1, 0:00:00 universal time. *nix systems adhere to that. This epoch of Jan 1, is not required by C and is not connected direclty to the epoch to the tm_year member of struct tm.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • I see. So `struct tm` is defined by the C standard and has no relation with the *nix conventions. – Rainbow Fizz Jul 28 '17 at 04:48
  • @RainbowFizz `time_t` is also defined by the C standard library. It is the C standard allows for various implementations details such as what date/time is `(time_t)0`. Many `*nix` compilers have further restricted those details in a common fashion, like having `(time_t)0` as Jan 1, 1970. – chux - Reinstate Monica Jul 28 '17 at 04:54