Преобразование 64-битной временной метки Unix

Существует ли какая-либо реализация на С++ 64-битных преобразований временных меток Unix для 32-битных систем? Мне нужно преобразовать struct tm в 64-битное целое число и наоборот, включая високосные годы, часовые пояса, UTC. Также нужна переносимость, по крайней мере, для GNU/Linux и Windows.


person Adam Trhon    schedule 27.10.2011    source источник
comment
Что должна представлять эта отметка времени? Если это всего лишь секунды с начала эпохи, вы можете просто использовать 32-битную функцию преобразования и скопировать результат в 64-битное целое число (до 2038 года)   -  person PlasmaHH    schedule 27.10.2011
comment
Разве time_t уже не 64-битный на большинстве систем? Windows имеет большинство функций и в 64-битном варианте. Просто погуглите.   -  person RedX    schedule 27.10.2011
comment
Целое число не может представлять часовые пояса, так как это относительное смещение от произвольной эпохи (в UNIX это 01 января 1970 года), но часовой пояс не определен. Если вы хотите представить эти элементы, вам все равно придется разбить их на struct. Также никто не «представляет» високосные годы; как бы они? Держите бессмысленный счет или что-то в этом роде?   -  person trojanfoe    schedule 27.10.2011
comment
PlasmaHH: Точно, только не раньше 2038 года.   -  person Adam Trhon    schedule 27.10.2011
comment
RedX: Я полагаю, что только на 64-битных системах. Пожалуйста, поправьте меня, если я ошибаюсь.   -  person Adam Trhon    schedule 27.10.2011
comment
trojanfoe: Вы правы, целое число не может представлять ни одно из них. Но вы должны учитывать их при конвертации в struct tm   -  person Adam Trhon    schedule 27.10.2011


Ответы (5)


Тебе нужно:

typedef long long time64_t; 
time64_t mktime64(struct tm *t); 
struct tm* localtime64_r(const time64_t* t, struct tm* p);

Первоначально (в 2011 году) этот ответ содержал ссылки на 2038bug.com, где можно было скачать небольшую pivotal_gmtime_r библиотеку, содержащую упомянутые функции. Библиотека тогда была удалена с 2038bug.com, ссылки стали битыми и были удалены из ответа модератором. Похоже, этот код pivotal_gmtime_r теперь можно найти здесь:

https://github.com/franklin373/mortage/tree/master/time_pivotal

Кроме того, я нашел другую, более новую библиотеку под названием y2038, которая также реализует mktime64 и localtime64_r:

https://github.com/evalEmpire/y2038

person Alexei Khlebnikov    schedule 07.11.2011
comment
Это выглядит как идеальное решение для меня. Мне просто кажется, что mktime64 ожидает UTC в своем параметре. Преобразование time_t в struct tm с помощью localtime64_r и обратно с помощью mktime64 не дает исходного времени, в то время как преобразование time_t в struct tm с помощью gmtime64_r и обратно с помощью mktime64 дает. Не могли бы вы подтвердить это? - person Adam Trhon; 08.11.2011
comment
Да, подтверждаю! localtime так много упоминалось в этой ветке, что я перепутал. :) Конечно нужен gmtime64_r. - person Alexei Khlebnikov; 16.11.2011
comment
Но я так понимаю, что mktime должно рассчитывать на местное время, не так ли? - person Adam Trhon; 16.11.2011
comment
Да, похоже на несоответствие. Стандартный mktime ожидает местное время и предположительно получит часовой пояс из ваших локальных настроек и преобразует его в UTC. Но этот mktime64 не зависит от часового пояса. т.е. он даст вам вывод time64_t в UTC, если вы подадите ввод struct tm в UTC, вывод в UTC+10, если вы подадите ввод в UTC+10 и т. д. - person Alexei Khlebnikov; 22.11.2011
comment
Где эти функции? ack mktime64 /usr/include/ возвращается пустым в последних версиях Linux - person dargaud; 18.12.2019
comment
@dargaud, я обновил ответ ссылками и некоторыми пояснениями. - person Alexei Khlebnikov; 08.01.2020

Функция, преобразующая struct tm* в time_t, называется mktime. Вы можете найти множество его реализаций, например. в Glibc и в файле mktime.c libvxc. Вы можете взять код (при условии, что он является законным для вас, поэтому, пожалуйста, уважайте лицензии) и изменить time_t на какое-то 64-битное целое число, например int64_t.

Функции, выполняющие другие преобразования из time_t в struct tm*, — это localtime или gmtime, и вы можете сделать то же самое.

Однако у вас может быть более фундаментальная проблема: ваша 32-битная машина, работающая в 2040 году, должна каким-то образом сообщать вам текущее время (как это делает системный вызов time) соответствующим образом в 64-битном варианте time_t, а это намного больше. сложнее (это зависит от ядра и железа).

person Basile Starynkevitch    schedule 04.11.2011
comment
Есть ли реализация, которая обрабатывает localtime переносимым способом? - person Adam Trhon; 05.11.2011
comment
Я не понимаю вопроса. Что вы называете портативным? time_t может быть 32-битным или 64-битным целым числом (поэтому машинный код должен быть другим). - person Basile Starynkevitch; 05.11.2011
comment
Я думал об использовании источников. Но когда я просматривал некоторые из них, они использовали нестандартные встроенные функции для определения часового пояса и перехода на летнее время. - person Adam Trhon; 05.11.2011
comment
это совершенно переносимо, но им нет дела до разницы между UTC и местным временем - person Adam Trhon; 05.11.2011
comment
Также обратите внимание, что в mktime они не корректируют диапазоны в struct tm. - person Adam Trhon; 05.11.2011
comment
Версия mktime(), которую вы связали, очень наивна. Сравните его, например, с mktime() от minix. - person jfs; 06.11.2011
comment
+1, для моих целей libvxc неплохо. И, кстати, для исправления ситуации с преобразованием локального UTC достаточно одной строки кода, так что на самом деле это не проблема. - person Agnius Vasiliauskas; 21.11.2012

Кажется, вы делаете предположение, что time_t является 32-битным в 32-битных системах, и это может быть правдой, а может и не быть.

В Windows, начиная с Visual Studio 2005, размер time_t составляет 64 бита, даже при компиляции для 32-битной Windows.

К сожалению, glibc определяет его как long int, что в 32-битных системах является 32-битным целым числом. Это означает, что 32-битный Linux и другие 32-битные платформы, основанные на gcc/glibc (например, Cygwin), не смогут работать с 64-битными метками времени.

Если ваше приложение должно работать на 32-битной glibc, вы должны использовать свои собственные функции преобразования, которые могут быть теми же функциями в библиотеке C, перекомпилированные для использования 64-битных временных меток.

Если вам нужен исходный код с разрешающей лицензией (BSD), то вы можете посмотреть эти функции в minix3. Здесь указано местное время. Источник имеет гиперссылку, так что вы можете легко найти остальные.

person Miguel    schedule 06.11.2011

Поддержка 64-битного времени в 32-битной версии Linux была впервые представлена ​​в ядре 5.1< /a> с добавлением новых *time64 системных вызовов (поскольку изменение возвращаемого типа старых системных вызовов ломает старые приложения). Проверьте эту таблицу, и вы увидите, что эти системные вызовы доступны только на 32-разрядных платформы.

Но это только поддержка со стороны ядра. Вы можете вызвать clock_gettime64 напрямую (из встроенного ассемблера или из C с помощью syscall()< /a>), чтобы получить текущее время, но вам понадобится код, специфичный для Linux, потому что пока нет поддержки glibc. Для полной поддержки userspace у вас должна быть Linux 5.6 или выше, а также musl 1.2+ или glibc 2.32+. Просто перестройте свой код, и time_t станет 64-битным. Теперь код, использующий time_t, станет полностью переносимым.

  • Все пользовательское пространство должно быть скомпилировано с 64-битной time_t, которая будет поддерживаться в следующих выпусках musl-1.2 и glibc-2.32 вместе с установленными заголовками ядра от linux-5.6 или выше.

  • Приложения, которые напрямую используют интерфейсы системных вызовов, необходимо портировать для использования системных вызовов time64, добавленных в linux-5.1, вместо существующих системных вызовов. Это влияет на большинство пользователей futex() и seccomp(), а также на языки программирования, которые имеют собственную среду выполнения, не основанную на libc.

https://lkml.org/lkml/2020/1/29/355?anz=web

Для получения дополнительной информации прочитайте

person phuclv    schedule 18.11.2020

Да, используйте stuct tm *_localtime64 ( const __time64_t *timer);

Это если у вас вентилятор на окнах.

person Alex Force    schedule 07.11.2011
comment
Идеальное решение для Windows, но, как я уже упоминал в вопросе, мне нужны и Windows, и Linux. - person Adam Trhon; 07.11.2011
comment
Есть что-то, что называется ifndef. Используйте это. - person Alex Force; 08.11.2011
comment
Правда правда. Мое практическое правило — забыть об условной компиляции, если в этом нет крайней необходимости. - person Adam Trhon; 08.11.2011
comment
_localtime64_s безопаснее кстати - person Guy L; 10.01.2014