Win32 API 有相当多的时间和日期函数可供选择。最常见的是,用户想要用这些函数来获得和设置当前日期与时间。这里只能讨论这些函数的一小部分,不过在 Platform SDK 文档中可以查阅到下表列出的 Win32 函数。
函数 | 说明 |
---|---|
CompareFileTime | 比较两个 64 位的文件时间 |
DosDateTimeToFileTime | 把 MS-DOS 日期和时间值转换为一个 64 位的文件时间 |
FileTimeToDosDateTime | 把 64 位文件时间转换为 MS-DOS 日期和时间值 |
FileTimeToLocalFileTime | 把 UTC(通用协调时间)文件时间转换为本地文件时间 |
FileTimeToSystemTime | 把 64 位文件时间转换为系统时间格式 |
GetFileTime | 检索文件创建、最后访问和最后修改的日期与时间 |
GetLocalTime | 检索当前本地日期和时间 |
GetSystemTime | 以 UTC 格式检索当前系统日期和时间 |
GetSystemTimeAdjustment | 决定系统是否对其日历钟进行周期性时间调整 |
GetSystemTimeAsFileTime | 以 UTC 格式检索当前系统日期和时间 |
GetTickCount | 检索自系统启动后经过的毫秒数 |
GetTimeZoneInformation | 检索当前时区参数 |
LocalFileTimeToFileTime | 把本地文件时间转换为基于 UTC 的文件时间 |
SetFileTime | 设置文件创建、最后访问和最后修改的日期与时间 |
SetLocalTime | 设置当前本地时间与日期 |
SetSystemTime | 设置当前系统时间与日期 |
SetSystemTimeAdjustment | 启用或禁用对系统日历钟进行周期性时间调整 |
SetTimeZoneInformation | 设置当前时区参数 |
SystemTimeToFileTime | 把系统时间转换为文件时间 |
SystemTimeToTzSpecificLocalTime | 把 UTC 时间转换为指定时区对应的本地时间 |
SYSTEMTIME 结构由 Windows API 的日期和时间函数使用:
字段 wDayOfWeek 的值依序为星期天 = 0,星期一 = 1,以此类推。wMilliseconds 中的值不确定,因为系统可以与时钟源同步周期性地刷新时间。
函数 GetLocalTime 根据系统时钟返回日期和当前时间。时间要调整为本地时区。调用该函数时,需向其传递一个指针指向 SYSTEMTIME 结构:
函数 GetLocalTime 调用示例如下:
.data
sysTime SYSTEMTIME <>
.code
INVOKE GetLocalTime, ADDR sysTime
函数 SetLocalTime 设置系统的本地日期和时间。调用时,需向其传递一个指针指向包含了期望日期和时间的 SYSTEMTIME 结构:
如果函数执行成功,则返回非零整数;如果失败,则返回零。
函数 GetTickCount 返回从系统启动起经过的毫秒数:
由于返回值为一个双字,因此当系统连续运行 49.7 天后,时间将会回绕归零。可以使用这个函数监视循环经过的时间,并在达到时间限制时终止循环。
下面的程序 Timer.asm 计算两次调用 GetTickCount 之间的时间间隔。程序尝试确定计时器没有回绕(超过 49.7 天)。相似的代码可以用于各种程序:
;计算经过的时间 (Timer.asm)
;用Win32函数GetTickCount演示一个简单的秒表计时器。
INCLUDE Irvine32.inc
INCLUDE macros.inc
.data
startTime DWORD ?
.code
main PROC
INVOKE GetTickCount ; 获取开始时间计数
mov startTime,eax ; 保存开始时间计数
; Create a useless calculation loop.
mov ecx,10000100h
L1: imul ebx
imul ebx
imul ebx
loop L1
INVOKE GetTickCount ; 获得新的时间计数
cmp eax,startTime ; 比开始时间计数小
jb error ; 时间回绕
sub eax,startTime ; 计算时间间隔
call WriteDec ; 显示时间间隔
mWrite <" milliseconds have elapsed",0dh,0ah>
jmp quit
error:
mWrite "Error: GetTickCount invalid--system has "
mWrite <"been active for more than 49.7 days",0dh,0ah>
quit:
exit
main ENDP
END main
有些时候程序需要暂停或延迟一小段时间。虽然可以通过构造一个计算循环或忙循环来保持处理器工作,但是不同的处理器会使得执行时间不同。另外,忙循环还不必要地占用了处理器,这会降低在同一时间执行程序的速度。
Win32 函数 Sleep 按照指定毫秒数暂停当前执行的线程:
由于本教程中汇编语言程序是单线程的,因此假设一个线程就等同于一个程序。当线程休眠时,它不会消耗处理器时间。
Irvine32 链接库中的过程 GetDateTime 以 100 纳秒为间隔,返回从 1601 年 1 月 1 日起经过的时间间隔数。这看起来有点奇怪,因为那个时候计算机还是未知的。对任何事件,Microsoft 都用这个值来跟踪文件日期和时间。
如果想要为日期计算准备系统日期/时间值,Win32 SDK 建议采用如下步骤:
FILETIME 结构把 64 位四字分割为两个双字:
下面的 GetDateTime 过程接收一个指针,指向 64 位四字变量。它用 Win32 FILETIME 格式将当前日期和时间保存到变量中:
;--------------------------------------------------
GetDateTime PROC,
pDateTime:PTR QWORD
LOCAL sysTime:SYSTEMTIME, flTime:FILETIME
;
; 以64位整数形式 ( 按 Win32 FILETIME 格式 ) 获得并保存当前本地时间/日期
;--------------------------------------------------
; 获得系统本地时间
INVOKE GetLocalTime,
ADDR sysTime
; SYSTEMTIME 转换为 FILETIME.
INVOKE SystemTimeToFileTime,
ADDR sysTime,
ADDR flTime
; 把 FILETIME 复制到一个64位整数
mov esi,pDateTime
mov eax,flTime.loDateTime
mov DWORD PTR [esi],eax
mov eax,flTime.hiDateTime
mov DWORD PTR [esi+4],eax
ret
GetDateTime ENDP