Time_t Статья Википедии статья проливает некоторый свет на это. Суть в том, что тип time_tне гарантируется в спецификации C.
Тип time_tданных - это тип данных в библиотеке ISO C, определенный для хранения значений системного времени. Такие значения возвращаются из стандартной time()
библиотечной функции. Этот тип является typedef, определенным в стандартном заголовке. ISO C определяет time_t как арифметический тип, но не определяет какой-либо конкретный тип , диапазон, разрешение или кодировку для него. Также не определены значения арифметических операций, применяемых к значениям времени.
Unix и POSIX-совместимые системы реализуют time_tтип какsigned
integer (обычно 32 или 64 бита), который представляет количество секунд с начала эпохи Unix : полночь UTC 1 января 1970 года (не считая високосных секунд). Некоторые системы правильно обрабатывают отрицательные значения времени, а другие нет. Системы, использующие 32-битный time_tтип, подвержены проблеме 2038 года .
Обратите внимание, что значения time_t обычно хранятся только в памяти, а не на диске. Вместо этого time_t преобразуется в текстовый или какой-либо другой переносимый формат для постоянного хранения. Это делает проблему Y2038 на самом деле не проблемой.
11
@Heath: в конкретной системе, где одни и те же люди создают операционную систему и библиотеку C, возможно использование time_tв структуре данных на диске. Однако, поскольку файловые системы часто читаются другими операционными системами, было бы глупо определять файловую систему на основе таких зависящих от реализации типов. Например, одна и та же файловая система может использоваться как в 32-разрядных, так и в 64-разрядных системах, и time_tможет изменить размер. Таким образом, файловые системы должны быть определены более точно («32-разрядное целое число со знаком, указывающее количество секунд с начала 1970 года в UTC»), чем просто time_t.
1
Как примечание: связанная статья в Википедии была удалена, и теперь она перенаправляет к списку time.hсодержимого. Эта статья ссылается на cppreference.com, но цитируемый контент нигде нет…
Михал Гурни
3
@ MichałGórny: исправлено, поскольку статьи не удаляются, вы всегда можете посмотреть историю, чтобы найти правильную версию.
Зета
4
-1; цитата из Википедии о том, что POSIX гарантирует time_tподпись, неверна. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… диктует, что различные вещи должны быть «целочисленным типом со знаком » или «целочисленным типом без знака», но time_tэто просто говорит о том, что он «должен быть целочисленным типом» . Реализация может сделать time_tunsigned и по-прежнему быть POSIX-совместимым.
Я вижу , как typedef __int32_t __time_t;и typedef __time_t time_t;в FreeBSD freebsd-test 8.2-RELEASE-p2 FreeBSD 8.2-RELEASE-p2 #8: Sun Aug 7 18:23:48 UTC 2011 root@freebsd-test:/usr/obj/usr/src/sys/MYXEN i386. Ваши результаты явно установлены так в Linux (по крайней мере на 2.6.32-5-xen-amd64 из Debian).
Почему бы grep для __time_tи не time_tнайти основной тип time_t? Пропустить шаг?
chux - Восстановить Монику
@ chux-ReinstateMonica - ОП сказал, что он нашел typedef от time_t до __time_t. Этот ответ просто отвечает на заданный вопрос о том, как определяется __time_t. Но я согласен, что для общего случая (где time_t не может быть определено как typedeff до __time_t), вам нужно сначала выполнить grep для time_t, а затем, возможно, снова выполнить grep для того, что это возвращает
Майкл Ферт
@MichaelFirth Достаточно справедливо. Я вспоминаю свою обеспокоенность тем, что, несмотря на то, что OP обнаружил typedef __time_t time_t;, проверка окружающего кода также необходима, чтобы убедиться, что typedef действительно использовался, а не только как часть условной компиляции. typedef long time_t;возможно, тоже был найден.
chux - Восстановить Монику
31
стандарты
Уильям Брендель цитировал Википедию, но я предпочитаю ее изо рта лошади.
Нет необходимости в трубе от эха:gcc -E -xc -include time.h /dev/null | grep time_t
rvighne
12
Ответ определенно зависит от реализации. Чтобы выяснить это окончательно для вашей платформы / компилятора, просто добавьте этот вывод где-нибудь в вашем коде:
printf ("sizeof time_t is: %d\n",sizeof(time_t));
Если ответ 4 (32 бита) и ваши данные выходят за пределы 2038 года , то у вас есть 25 лет для переноса кода.
Ваши данные будут в порядке, если вы сохраните свои данные в виде строки, даже если это будет что-то простое, например:
FILE*stream =[stream file pointer that you've opened correctly];
fprintf (stream,"%d\n",(int)time_t);
Затем просто прочитайте его обратно тем же способом (fread, fscanf и т. Д. В int), и у вас будет время смещения вашей эпохи. Подобный обходной путь существует в .Net. Я без проблем передаю 64-битные числа эпох между системами Win и Linux (по каналу связи). Это поднимает проблемы с порядком байтов, но это уже другая тема.
Чтобы ответить на запрос Паксдиабло, я бы сказал, что он напечатал «19100», потому что программа была написана таким образом (и я признаю, что я сделал это сам в 80-х):
time_t now;struct tm local_date_time;
now = time(NULL);// convert, then copy internal object to our object
memcpy (&local_date_time, localtime(&now),sizeof(local_date_time));
printf ("Year is: 19%02d\n", local_date_time.tm_year);
printfОператор печатает фиксированную строку «Год является: 19» , за которым следует нулями строку с «лет начиная с 1900 года » (определение tm->tm_year). В 2000 году это значение, очевидно, равно 100. "%02d"колодки с двумя нулями, но не усекаются, если они длиннее двух цифр.
Правильный путь (изменить только на последнюю строку):
printf ("Year is: %d\n", local_date_time.tm_year +1900);
Возможно, вам следует использовать %zuспецификатор формата для форматирования size_tзначений (в том виде sizeof, в каком они получены ), поскольку они являются unsigned ( u) и имеют длину size_t ( z) ·
Адриан Гюнтер
... или использовать printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));и избежать zпроблемы.
chux - Восстановить Монику
6
В Visual Studio 2008 по умолчанию используется значение, __int64если вы не определите _USE_32BIT_TIME_T. Вам лучше просто притворяться, что вы не знаете, как он определяется, поскольку он может (и будет) меняться от платформы к платформе.
Обычно это работает, но если ваша программа предназначена для отслеживания событий, которые произойдут через 30 лет, очень важно, чтобы у вас не было подписанного 32-битного time_t.
Роб Кеннеди
4
@ Роб, ба, оставь это! Мы просто начнем бегать, как куры без головы, в 2036 году, так же, как и в 2000 году. Некоторые из нас заработают кучу денег, будучи консультантами Y2k38, Леонард Нимой выпустит еще одну веселую книгу о том, как мы все должны идти и прятаться в лесу ...
paxdiablo
1
... и все это перевернется, публика задается вопросом, о чем шла речь. Я могу даже выйти на пенсию, чтобы заработать немного денег на наследство детей :-).
paxdiablo
2
Кстати, мы нашли только одну ошибку Y2K, и это была веб-страница, на которой указана дата 1 января 19100 года. Упражнение для читателя о том, почему ...
paxdiablo
9
Если событие, которое произойдет через 30 лет, - «истекает срок действия этой резервной копии», то у вас могут быть проблемы СЕЙЧАС, а не в 2038 году. Добавьте 30 лет к сегодняшнему 32-разрядному time_t, и вы получите дату в прошлом. Ваша программа ищет события для обработки, находит одно просроченное (на 100 лет!) И выполняет его. К сожалению, больше нет резервной копии.
Роб Кеннеди
5
time_tимеет тип long intна 64-битных машинах, иначе это так long long int.
Вы можете проверить это в следующих заголовочных файлах:
Это 32-разрядное целое число со знаком на большинстве устаревших платформ. Однако это приводит к тому, что ваш код страдает от ошибки 2038 года . Поэтому современные библиотеки C должны определять его как 64-битное целое число со знаком, что безопасно в течение нескольких миллиардов лет.
Обычно вы найдете эти базовые специфичные для реализации typedefs для gcc в каталоге заголовка bitsили asm. Для меня это/usr/include/x86_64-linux-gnu/bits/types.h .
С видов, time_tчтобы быть реальным типом, как double, long long, int64_t, intи т. Д.
Это даже может быть unsignedкак возвращаемые значения из многих функций времени, указывающих на ошибку -1, но(time_t)(-1) - этот вариант реализации является редкостью.
Дело в том, что «необходимость знать» тип встречается редко. Код должен быть написан, чтобы избежать необходимости.
Тем не менее, общая «необходимость знать» возникает, когда код хочет распечатать сырье time_t. Приведение к самому широкому целочисленному типу будет соответствовать большинству современных случаев.
time_t now =0;
time(&now);
printf("%jd",(intmax_t) now);// or
printf("%lld",(longlong) now);
Приведение к doubleили long doubleбудет работать, но может дать неточный десятичный вывод
Мне нужно знать ситуацию, потому что мне нужно перенести время из системы ARM в систему AMD64. time_t - 32 бита на руке и 64 бита на сервере. если я переведу время в формат и отправлю строку, это неэффективно и медленно. Поэтому гораздо лучше просто отправить весь time_t и отсортировать его на стороне сервера. Тем не менее, мне нужно понять тип немного больше, потому что я не хочу, чтобы число искажалось из-за разницы в порядковости байтов между системами, поэтому мне нужно использовать htonl ... но сначала, при необходимости знать основы, я хочу выяснить базовый тип;)
Сова
Другой случай «необходимости знать», по крайней мере, для подписанных и неподписанных, заключается в том, нужно ли вам соблюдать осторожность при вычитании времен. Если вы просто «вычтете и напечатаете результат», то вы, возможно, получите то, что ожидаете, в системе с подписанным time_t, но не с неподписанным time_t.
Майкл Ферт
@MichaelFirth Случаи существуют как для целочисленного time_t, так и для unsigned time_t, где необработанное вычитание приведет к неожиданным результатам. С обеспечивает double difftime(time_t time1, time_t time0)единый подход к вычитанию.
chux - Восстановить Монику
-3
time_tтолько typedefдля 8 байт ( long long/__int64), которые понимают все компиляторы и ОС. Раньше это было только для long int(4 байта), но не сейчас. Если вы посмотрите на time_tвнутри, crtdefs.hвы найдете обе реализации, но ОС будет использовать long long.
все компиляторы и операционные системы? Нет. В моей системе Linux компилятор принимает 4-байтовую подписанную реализацию.
Винсент
В системах Zynq 7010 time_t составляет 4 байта.
Сова
1
На встроенных системах я работаю с time_t почти всегда 32-битным или 4 байтами. В стандарте конкретно указывается, что это конкретная реализация, что делает этот ответ просто неправильным.
long int
.Ответы:
Time_t Статья Википедии статья проливает некоторый свет на это. Суть в том, что тип
time_t
не гарантируется в спецификации C.источник
time_t
в структуре данных на диске. Однако, поскольку файловые системы часто читаются другими операционными системами, было бы глупо определять файловую систему на основе таких зависящих от реализации типов. Например, одна и та же файловая система может использоваться как в 32-разрядных, так и в 64-разрядных системах, иtime_t
может изменить размер. Таким образом, файловые системы должны быть определены более точно («32-разрядное целое число со знаком, указывающее количество секунд с начала 1970 года в UTC»), чем простоtime_t
.time.h
содержимого. Эта статья ссылается на cppreference.com, но цитируемый контент нигде нет…time_t
подпись, неверна. pubs.opengroup.org/onlinepubs/9699919799/basedefs/… диктует, что различные вещи должны быть «целочисленным типом со знаком » или «целочисленным типом без знака», ноtime_t
это просто говорит о том, что он «должен быть целочисленным типом» . Реализация может сделатьtime_t
unsigned и по-прежнему быть POSIX-совместимым.[root]# cat time.c
[root]# gcc -E time.c | grep __time_t
typedef long int __time_t;
Это определяется
$INCDIR/bits/types.h
через:источник
typedef __int32_t __time_t;
иtypedef __time_t time_t;
вFreeBSD freebsd-test 8.2-RELEASE-p2 FreeBSD 8.2-RELEASE-p2 #8: Sun Aug 7 18:23:48 UTC 2011 root@freebsd-test:/usr/obj/usr/src/sys/MYXEN i386
. Ваши результаты явно установлены так в Linux (по крайней мере на 2.6.32-5-xen-amd64 из Debian).__time_t
и неtime_t
найти основной типtime_t
? Пропустить шаг?typedef __time_t time_t;
, проверка окружающего кода также необходима, чтобы убедиться, что typedef действительно использовался, а не только как часть условной компиляции.typedef long time_t;
возможно, тоже был найден.стандарты
Уильям Брендель цитировал Википедию, но я предпочитаю ее изо рта лошади.
Проект стандарта C99 N1256 7.23.1 / 3 «Составляющие времени» гласит:
и 6.2.5 / 18 «Типы» говорит:
POSIX 7 sys_types.h говорит:
где
[CX]
будет определен как :Это расширение, потому что оно дает более сильную гарантию: плавающие точки отсутствуют.
gcc однострочник
Нет необходимости создавать файл, как упомянуто Quassnoi :
В Ubuntu 15.10 GCC 5.2 две верхние строки:
Разбивка команд с некоторыми цитатами из
man gcc
:-E
: "Остановитесь после этапа предварительной обработки; не запускайте должным образом компилятор."-xc
: Укажите язык C, поскольку входные данные поступают из стандартного ввода, которое не имеет расширения файла.-include file
: "Обрабатывать файл так, как если бы" #include "file" "появилось как первая строка первичного исходного файла."-
: вход от стандартного вводаисточник
gcc -E -xc -include time.h /dev/null | grep time_t
Ответ определенно зависит от реализации. Чтобы выяснить это окончательно для вашей платформы / компилятора, просто добавьте этот вывод где-нибудь в вашем коде:
Если ответ 4 (32 бита) и ваши данные выходят за пределы 2038 года , то у вас есть 25 лет для переноса кода.
Ваши данные будут в порядке, если вы сохраните свои данные в виде строки, даже если это будет что-то простое, например:
Затем просто прочитайте его обратно тем же способом (fread, fscanf и т. Д. В int), и у вас будет время смещения вашей эпохи. Подобный обходной путь существует в .Net. Я без проблем передаю 64-битные числа эпох между системами Win и Linux (по каналу связи). Это поднимает проблемы с порядком байтов, но это уже другая тема.
Чтобы ответить на запрос Паксдиабло, я бы сказал, что он напечатал «19100», потому что программа была написана таким образом (и я признаю, что я сделал это сам в 80-х):
printf
Оператор печатает фиксированную строку «Год является: 19» , за которым следует нулями строку с «лет начиная с 1900 года » (определениеtm->tm_year
). В 2000 году это значение, очевидно, равно 100."%02d"
колодки с двумя нулями, но не усекаются, если они длиннее двух цифр.Правильный путь (изменить только на последнюю строку):
Новый вопрос: в чем причина такого мышления?
источник
%zu
спецификатор формата для форматированияsize_t
значений (в том видеsizeof
, в каком они получены ), поскольку они являются unsigned (u
) и имеют длину size_t (z
) ·printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));
и избежатьz
проблемы.В Visual Studio 2008 по умолчанию используется значение,
__int64
если вы не определите_USE_32BIT_TIME_T
. Вам лучше просто притворяться, что вы не знаете, как он определяется, поскольку он может (и будет) меняться от платформы к платформе.источник
time_t
имеет типlong int
на 64-битных машинах, иначе это такlong long int
.Вы можете проверить это в следующих заголовочных файлах:
time.h
:/usr/include
types.h
Иtypesizes.h
:/usr/include/x86_64-linux-gnu/bits
(Приведенные ниже операторы не являются друг за другом. Их можно найти в заголовочном файле соответственно с помощью Ctrl + f search.)
1) В
time.h
2) В
types.h
3) В
typesizes.h
4) Опять в
types.h
источник
long int
везде. См. Stackoverflow.com/questions/384502/…Это 32-разрядное целое число со знаком на большинстве устаревших платформ. Однако это приводит к тому, что ваш код страдает от ошибки 2038 года . Поэтому современные библиотеки C должны определять его как 64-битное целое число со знаком, что безопасно в течение нескольких миллиардов лет.
источник
Обычно вы найдете эти базовые специфичные для реализации typedefs для gcc в каталоге заголовка
bits
илиasm
. Для меня это/usr/include/x86_64-linux-gnu/bits/types.h
.Вы можете просто выполнить grep или использовать вызов препроцессора, подобный предложенному Quassnoi, чтобы увидеть, какой именно заголовок.
источник
Надежный код не заботится о типе.
С видов,
time_t
чтобы быть реальным типом, какdouble, long long, int64_t, int
и т. Д.Это даже может быть
unsigned
как возвращаемые значения из многих функций времени, указывающих на ошибку-1
, но(time_t)(-1)
- этот вариант реализации является редкостью.Дело в том, что «необходимость знать» тип встречается редко. Код должен быть написан, чтобы избежать необходимости.
Тем не менее, общая «необходимость знать» возникает, когда код хочет распечатать сырье
time_t
. Приведение к самому широкому целочисленному типу будет соответствовать большинству современных случаев.Приведение к
double
илиlong double
будет работать, но может дать неточный десятичный выводисточник
double difftime(time_t time1, time_t time0)
единый подход к вычитанию.time_t
толькоtypedef
для 8 байт (long long/__int64
), которые понимают все компиляторы и ОС. Раньше это было только дляlong int
(4 байта), но не сейчас. Если вы посмотрите наtime_t
внутри,crtdefs.h
вы найдете обе реализации, но ОС будет использоватьlong long
.источник