计算机的几种时间格式

 
 
注意:
本文大部分翻译自 Matt Pietrek 1997 2 MSJ 上的 Under The Hood 专栏。
链接: http://www.microsoft.com/msj/0297/hood/hood0297.aspx
 
一.FILETIME和SYSTEMTIME格式
 
我遇到的第一种时间格式是在使用函数GetFileTime时返回的FILETIME,这是一个64位(8字节)结构。在SDK文档中,关于这个结构是这样描述的“FILETIME结构的64位值,表示从1601年1月1日开始的以100纳秒(一纳秒为十亿分之一秒)为间隔的值”。我不知道你——反正我的朋友和亲戚——在听到“100纳秒”时头都大了。
 
不过还好,Win32的另一种时间格式消除了这个问题,这个格式就是SYSTEMTIME。它是一个包含有年、月、日、小时、分、秒、微秒这些成员的结构,而且还有一个API函数FileTimeToSystemTime专门用来将FILETIEM格式转化成SYSTEMTIME格式。当然,假如你要知道是否为闰年、闰纪等这样的问题就只好自己手工转换了。
 
每次运行使用GetFileTime和FileTimeToSystemTime函数的代码,我总是发现得出的时间比正确的时间少几个小时。为什么呢?思来想去,我终于明白了:在安装WINDOWS NT和95时,我曾经告诉系统我住在什么地区。而在win32下,FILETIME总是为格林尼治时间(UTC)。使用UTC,你就会发现实际时间是 美国新罕布什尔州的南雪(Nashua)只有2PM,而得到的时间却是格林尼治7PM。
 
如果让程序员对每个FILETIME都负责检查并修正,这太可怕了。这就是WIN32提供FileTimeToLocalTime函数的原因。在调用FileTimeToSystemTime前先调用FileTimeToLocalFileTime,可以非常方便地对FILETIME进行时区修正。
 
二.MS-DOS格式

第三种描绘时间的格式是一种老式的MS-DOS格式。在这种格式下,日期和时间被独立存储在两个双字中。因为只有16位,所以年度值是相对于1980年的差值。而且,这种格式时间精度是2秒。如果你选择使用这种格式,那么函数FileTimeToDosDateTime是不能缺少的。
 
我怎么会想到这种时间格式呢?真不好意思,当我在开发DEPENDS程序时,开始我并没有想到要使用SYSTEMTIME格式。所以,一直到我意识到这个问题之前,所有版本的DEPENDS都是将FILETIME转换成MS-DOS格式的。
 
三.PE文件中的时间戳
 
第四种时间格式在我们平常的API文档中是不会见到的。在WIN32可执行文件中,PE文件头部(IMAGE_FILE_HEADER)中有个DWORD字段TimeDateStamp。它是从格林尼治时间1970年1月1日夜里12:00开始的秒数。TimeDateStamp由连接器(linker)设置,并且在PE文件的其它部分也有使用。
 
在这里,我要承认我以前犯的一个愚蠢的错误。在我的文章《Peering Inside the PE: A Tour of the Win32 Portable Executable File Format》 (MSJ March 1994)和书《Windows 95 System Programming Secrets》中,我将TimeDateStamp字段描述成从1969年12月31日4PM开始的秒数。我得到这个结果是因为我将TimeDateStamp设置为0,然后运行DUMPBIN来看转换成什么时间。在这里我没有考虑到DUMPBIN已经帮我把时间转换成计算机当前时区的时间(我的时区当然不会是格林尼治时区)了。所以,在这里我再次纠正这个错误。
 
TimeDateStamp这个字段在PE文件中相当有用。比如,当你在文件系统中改变了文件的日期和时间后,TimeDateStamp却会保持不变。这样,当你想知道文件到底什么时候创建时,TimeDateStamp是比较准确(当然前提是连接器正确设置了它)。TimeDateStamp的唯一需要点技术的地方是:怎样将它转变成我们比较熟悉的时间格式。
 
经过考虑,我是这样来解决这个问题的。FILETIME和TimeDateStamp分别相对于某个时间点的值。如果我能用FILETIME来描述TimeDateStamp,我就可以使用上面提到的Win32时间函数来做我想做的任何事情。所以我需要先将1970年1月1日表示成FILETIME格式,然后再将TimeDateStamp(以秒数为计数单位)转换成以100纳秒为计数单位,最后将上面得到的两个值相加就可以得到我想要的FILETIME格式了。
 
为了将1970年1月1日转换成FILETIME,我首先定义了一个SYSTEIMTIME结构,然后将1970年1月1日填空进去,接着我只要调用SystemTimeToFileTime便可以得到FILETIME格式了。转换的结果我在DEPENDS代码用到:0x019DB1DED53E8000。将秒数转换成100纳秒比较简单:只要乘上10000000。当然,结果肯定会超过32位,所以一定要将其中的被乘数强制成64位整数(VC中的_INT64)。当然,如果你想省点事,你完全可以使用C运行库中的ctime函数。
 
四.MAC操作系统中的longdt时间
 
和FILETIME一样,这种时间也是个8字节数据格式,而且也是相对于一个时间点的秒数的计数。但不幸的是:这个时间点和FILETIME不同,它是1904年1月1日午夜12:00。
 
受上面文章的启发,我写了个将longdt转换到FILETIME格式的函数:
 
function LongDtToFileTime(ldt: INT64): FILETIME;
var
 ft1904: FILETIME;
 st1904: SYSTEMTIME;
begin
 st1904.wYear := 1904;
 st1904.wMonth := 1;
 st1904.wDay := 1;
 st1904.wHour := 0;
 st1904.wMinute := 0;
 st1904.wSecond := 0;
 st1904.wMilliseconds := 0;
 SystemtimeToFileTime(st1904, ft1904);
 
 ldt := ldt * 10000000;
 ldt := ldt + (int64(ft1904));
 
 FileTimeToLocalFileTime(FILETIME(ldt), FILETIME(ldt));
 Result := FILETIME(ldt);
end;
 
 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值