Почему член tm_year в struct tm относительно 1900, а не 1970 в C в macosx?

Я пробовал примеры в экспертном программировании на C, когда столкнулся с этой проблемой. Моя программа в основном делает одно: используйте стандартную функцию gmtime и посмотрите, сколько лет прошло с 1970 года. Вот моя программа:

#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;
}

Результатом будет 117, количество прошедших 1900 лет. Это неожиданно, потому что я проверил time() и man gmtime заранее, и они оба сказали, что они относятся к времени Эпохи (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

Согласно приведенному выше описанию, моя программа должна была вернуть 47 вместо 117. Что здесь происходит?

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)

person Rainbow Fizz    schedule 27.07.2017    source источник
comment
Потому что об этом говорится в документе также интерактивное руководство   -  person litelite    schedule 27.07.2017
comment
Также страница руководства: tm_year The number of years since 1900.   -  person Mat    schedule 27.07.2017
comment
Раздел man-страницы ctime (3), который вы цитируете, ничего не говорит о tm_year. Он описывает, как интерпретировать значение time_t, которое является аргументом для gmtime(3).   -  person Ssswift    schedule 27.07.2017
comment
Я не вижу требований стандарта C для конкретной нулевой даты. Можете дать ссылку? Почему вы цитируете справочные страницы Linux для OSX?   -  person too honest for this site    schedule 27.07.2017
comment
Спасибо за все документы и справочные страницы: D   -  person Rainbow Fizz    schedule 28.07.2017


Ответы (2)


Поле tm_year относится к 1900 на всех POSIX-совместимых платформах, а не только на macOS.

struct tm разработан для синтаксического анализа, отображения и управления удобочитаемыми датами. Когда он был создан, даты обычно записывались и даже сохранялись без «19» части номера года, а проблема 2000 года была решена примерно через 25 лет. Так что удобство вывода tm_year на печать в виде двух цифр, сделав его относительным к 1900 году, в то время казалось разумным.

Временные метки Unix относятся к «эпохе Unix», то есть 1970-01-01 00:00:00 UTC. Чтобы узнать, почему, см. Эти вопросы и ответы.

person rob mayoff    schedule 27.07.2017
comment
Спасибо за ответ! Страница /usr/include/time.h на моем Mac говорит, что это действительно относительно 1900 года. - person Rainbow Fizz; 28.07.2017
comment
@RainbowFizz Если этот ответ вам помог, примите его. - person S.S. Anne; 08.11.2019

Член tm_year в struct tm относится к 1900 согласно спецификации библиотеки C. Все совместимые стандартные библиотеки используют это.

Структура tm должна содержать как минимум следующие элементы в любом порядке. Семантика членов и их нормальные диапазоны выражены в комментариях §7.27.2.1 4

...
int tm_year; // years since 1900

time() возвращает значение time_t, «которое может представлять календарное время на основе конкретной эпохи». Обычно это 1 января 1970 года, 0:00:00 по всемирному времени. Системы * nix придерживаются этого. Эта эпоха 1 января не требуется для C и не связана напрямую с эпохой с tm_year членом struct tm.

person chux - Reinstate Monica    schedule 27.07.2017
comment
Я понимаю. Итак, struct tm определяется стандартом C и не имеет отношения к соглашениям * nix. - person Rainbow Fizz; 28.07.2017
comment
@RainbowFizz time_t также определяется стандартной библиотекой C. Это стандарт C, допускающий различные детали реализации, такие как дата / время (time_t)0. Многие компиляторы *nix дополнительно ограничили эти детали обычным образом, например, (time_t)0 на 1 января 1970 года. - person chux - Reinstate Monica; 28.07.2017