OS X 10.6“Snow Leopard”之前的所有版本都有2038年的问题。大多数安装的10.6和所有安装的10.7“Lion”修复了问题的主要原因。它几乎消失了,但是2038年的bug可能会在一些应用程序中存活下来。
我的旧PowerPC Mac运行OS X 10.4.11“Tiger”。我在系统偏好设置中输入了日期和时间,并尝试在2038年之后输入日期,但它将日期重置为2037年12月31日。它知道2038年出现了问题。
OS X是通过BSD从Unix派生的。OS X应用程序使用BSD系统调用来打开文件和连接到互联网。BSD历史悠久,其中一些系统调用来自20世纪80年代。其中一个系统调用是gettimeofday()
首次出现在4.1cBSD中。加州大学伯克利分校于1982年发布了4.1cBSD,比2038年前发布了半个多世纪。时间gettimeofday()
是一个整数类型time_t
。它计算秒数,其中零是1970-01-01 00:00:00 UTC的Unix纪元。
在我的旧PowerPC Mac中,time_t
是一个带符号的32位整数。这导致了2038年的问题。带符号的32位time_t
范围为-2147483648到2147483647.这只能保持从1901-12-13 20:45:52 UTC到2038-01-19 03:14:07 UTC的时间。当这个溢出时,gettimeofday()
将把日期从2038年1月19日星期一翻到1901年12月13日星期五。
修复是从32位转换time_t
到64位time_t
。对于OS X,这种转换伴随着从32位指针到64位指针的另一次转换,但64位指针需要64位处理器。Apple仅提供64位time_t
64位处理器。32位处理器可以处理64位time_t
,但Apple从未提供过该功能。
自OS X 10.0“Cheetah”以来,Apple的编译器支持32位处理器上的64位整数,当时time_t
有32位且off_t
有64位。在Unix和BSD中,off_t
是文件的大小,还是整个磁盘的大小。32位off_t
会将OS X限制为2 GiB以下的磁盘。Apple定义off_t
为64位,因此OS X适用于较大的磁盘。Apple time_t
在10.0中定义为32位,因此time_t
需要稍后转换为64位。
对于我的旧PowerPC Mac,头文件<ppc/_types.h>
定义__darwin_time_t
为long
。对于Intel Mac,标题<i386/_types.h>
也是如此。在OS X中,long
与指针具有相同的大小。因此,当指针变为64位时,long
也变为64位,并且time_t
也变为64位,从而解决了2038年问题的主要原因。
Apple的64位转换指南称,“在OS X v10.6之前,操作系统附带的所有应用程序都是32位应用程序。从v10.6开始,操作系统附带的应用程序通常是64位应用程序“。我从维基百科知道,10.6需要英特尔处理器,10.7需要64位英特尔处理器。在32位英特尔处理器上运行10.6的Mac必须具有32位应用程序。我的结论是,大多数运行10.6的Mac和运行10.7的所有Mac都有64位应用程序,64位指针和64位time_t
。苹果在2011年发布了10.7,远在2038年1月之前。
使用64位time_t
,2038年的bug几乎消失了,但它可能会在一些应用程序中存活下来。旧的32位应用程序可能仍在较新的系统上运行。此外,64位应用程序可能包含编码错误或过时的设计,导致它们将64位转换time_t
为32位。这对所有系统都是一个问题,而不仅仅是macOS。
还有马赫时间。OS X的内核将BSD与Mach混合在一起。大多数应用程序从BSD使用时间gettimeofday()
,但有一种方法可以绕过BSD并从Mach获得时间。这更难:程序会调用mach_host_self()
获取主机端口,然后host_get_clock_service()
获取CALENDAR_CLOCK
,最后clock_get_time()
。
在我的旧Mac上运行10.4“Tiger”,<mach/clock_types.h>
将时间声明为unsigned int
(内部struct mach_timespec
)。这是一个无符号的32位整数,范围从0到4294967295,这是从1970-01-01 00:00:00 UTC到2106-02-07 06:28:15 UTC。这将交换2038年问题2106年的问题。它不能达到29,940年。
我怀疑host_get_clock_service()
自10.0“Cheetah”以来已经过时了,因为Apple提供了更快的方式来获得时间。这些是gettimeofday()
日历时间的BSD ,而Apple则是mach_absolute_time()
单调时间。倾向于gettimeofday()
将问题放在2038年,而不是2106。