【问题标题】:64-bit Unix timestamp conversion64 位 Unix 时间戳转换
【发布时间】:2011-12-16 09:28:05
【问题描述】:

是否有针对 32 位系统的 64 位 Unix 时间戳转换的 C++ 实现?我需要将struct tm 转换为 64 位整数,反之亦然,包括闰年、时区、UTC。还需要它可移植,至少对于 GNU/Linux 和 Windows。

【问题讨论】:

  • 那个时间戳应该代表什么?如果它距离纪元只有几秒钟,那么您可以使用 32 位转换函数并将结果复制为 64 位整数(只要您在 2038 年之前)
  • time_t 在大多数系统上不是已经是 64 位了吗? Windows 也具有 64 位变体的大多数功能。只需谷歌即可。
  • 整数不能表示时区,因为它是与任意纪元(在 UNIX 中为 1970 年 1 月 1 日)的相对偏移量,但时区未定义。如果你想表示这些元素,无论如何你都必须将它们分解为struct。也没有人“代表”闰年;他们会怎样?对它们进行无意义的计数吗?
  • PlasmaHH:没错,只是在 2038 年之前
  • RedX:我相信只在 64 位系统上。如果我错了,请纠正我。

标签: c++ linux 64-bit 32bit-64bit time-t


【解决方案1】:

你需要:

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,它也实现了 mktime64localtime64_r

https://github.com/evalEmpire/y2038

【讨论】:

  • 这对我来说似乎是一个完美的解决方案。在我看来,mktime64 在其参数中期望 UTC。通过 localtime64_r 将 time_t 转换为 struct tm 并使用 mktime64 返回并不会给出原始时间,而通过 gmtime64_r 将 time_t 转换为 struct tm 并通过 mktime64 返回则可以。你能确认一下吗?
  • 是的,确认! localtime 在这个帖子中被提及太多,以至于我把它搞混了。 :) 当然你需要gmtime64_r
  • 但据我了解,“mktime”应该是当地时间,不是吗?
  • 是的,似乎不一致。标准mktime 需要本地时间,并且应该会从您的本地设置中获取时区并将其转换为UTC。但是这个mktime64 是“时区不可知论者”。 IE。如果您在UTC 中提供输入struct tm,它将在UTC 中为您输出time64_t,如果您在UTC+10 中提供输入,则在UTC+10 中输出,等等。
  • 这些功能在哪里? ack mktime64 /usr/include/ 在最近的 Linux 上返回空白
【解决方案2】:

struct tm* 转换为time_t 的函数是mktime。您可以找到它的许多实现,例如。在 Glibc 和 libvxc's mktime.c file 中。您可以获取代码(假设它对您来说是合法的,所以请尊重许可证)并将 time_t 更改为一些 64 位整数,例如 int64_t

执行从time_tstruct tm* 的其他转换的函数是localtimegmtime,您也可以这样做。

但是,您可能有一个更根本的问题:您在 2040 年运行的 32 位机器应该有某种方式在 @ 的 64 位变体中适当地为您提供当前时间(就像 time 系统调用所做的那样) 987654333@,这要困难得多(取决于内核和硬件)。

【讨论】:

  • 是否有任何实现以可移植的方式处理localtime
  • 我不明白这个问题。什么叫便携? time_t 可以是 32 位或 64 位整数类型(因此机器码必须不同)。
  • 我在考虑使用资源。但是当我浏览其中的一些时,他们使用了非标准的内置函数来确定时区和 DST
  • 它非常便携,但他们不关心 UTC 和本地时间之间的差异
  • 另请注意,在mktime 中,它们不会调整struct tm 中的范围
【解决方案3】:

您似乎假设time_t 在 32 位系统上是 32 位,这可能是真的,也可能不是。

在 Windows 上,从 Visual Studio 2005 开始,time_t 的大小为 64 位,即使您为 32 位 Windows 编译也是如此。

不幸的是,glibc 将其定义为long int,在 32 位系统上是一个 32 位整数。这意味着 32 位 Linux 和其他基于 gcc/glibc(如 Cygwin)的 32 位平台将无法使用 64 位时间戳。

如果您的应用程序必须在 32 位 glibc 上运行,那么您应该使用自己的转换函数,这些函数可以是重新编译为使用 64 位时间戳的 C 库中的相同函数。

如果您需要具有许可许可证 (BSD) 的源代码,那么您可以在 minix3 中查看这些功能。 Here 是当地时间。来源是超链接的,因此您可以轻松找到其他来源。

【讨论】:

    【解决方案4】:

    32 位 Linux 上的 64 位时间支持是 first introduced in the 5.1 kernel,并添加了新的 *time64 syscalls(因为更改旧系统调用的返回类型会破坏旧应用程序)。检查this table,您会发现这些系统调用仅在 32 位平台上可用。

    但这只是内核方面的支持。您可以直接调用clock_gettime64(从内联汇编,或从带有syscall() 函数的C 调用)来获取当前时间,但您需要特定于Linux 的代码,因为还没有glibc 支持。要获得完整的用户空间支持,您必须使用 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 或更高版本的内核头文件都将支持它。

    • 直接使用系统调用接口的应用程序需要移植到使用 linux-5.1 中添加的time64 系统调用来代替现有的系统调用。这会影响futex()seccomp() 的大多数用户以及拥有自己的运行时环境而不基于libc 的编程语言。

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

    更多信息请阅读

    【讨论】:

      【解决方案5】:

      是的,使用stuct tm *_localtime64 ( const __time64_t *timer);

      那就是你的 Windows 风扇。

      【讨论】:

      • 完美的windows解决方案,但正如我在问题中提到的,我需要windows和linux
      • 有一个叫做 ifndef.. 的东西。
      • 真的,真的。除非绝对必要,否则我的经验法则是忘记条件编译。
      • _localtime64_s 顺便说一句更安全
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-07
      • 1970-01-01
      • 1970-01-01
      • 2023-03-18
      相关资源
      最近更新 更多