ZetCode

Windows API 中的日期和时间

最后修改于 2023 年 10 月 18 日

在本 Windows API 教程中,我们将处理日期和时间。ZetCode 有一篇文章讨论了 ANSI C 中的日期和时间。

SYSTEMTIME 结构用于处理 Windows API 中的日期和时间。时间可以是协调世界时 (UTC) 或本地时间。它具有以下成员

WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;

SYSTEMTIME 结构通过 GetSystemTime 函数或 GetLocalTime 函数填充。然后我们可以访问该结构的成员以获取当前日期或时间。

FILETIME 结构包含一个 64 位值,表示自 1601 年 1 月 1 日(UTC)以来经过的 100 纳秒间隔数。有了这个值,我们就可以计算 Windows API 纪元或日期时间差。

DWORD dwLowDateTime;
DWORD dwHighDateTime;

FILETIME 结构有两个成员:dwLowDateTime 是文件时间的低位部分,dwHighDateTime 是文件时间的高位部分。为了从这两个成员中获取一个值,我们使用 LARGE_INTEGER 联合。

FileTimeToSystemTimeSystemTimeToFileTime 函数用于在这两个结构之间进行转换。

本地时间

本地时间定义为用户时区的当前时间。

localtime.c
#include <windows.h>
#include <wchar.h>

int wmain(void) {

    SYSTEMTIME lt = {0};
  
    GetLocalTime(&lt);
  
    wprintf(L"The local time is: %02d:%02d:%02d\n", 
        lt.wHour, lt.wMinute, lt.wSecond);

    return 0;
}

该程序打印本地时间。

SYSTEMTIME lt = {0};

我们声明 SYSTEMTIME 结构。此结构的成员通过调用特定时间函数来填充。

GetLocalTime(&lt);

GetLocalTime 检索当前本地日期和时间。它使用当前日期和时间值填充 SYSTEMTIME 的成员。

wprintf(L"The local time is: %02d:%02d:%02d\n", 
  lt.wHour, lt.wMinute, lt.wSecond);

我们以 hh:mm:ss 格式打印当前本地时间。

C:\Users\Jano\Documents\Pelles C Projects\timedate\LocalTime>LocalTime.exe
The local time is: 20:20:07

这是示例输出。

UTC 时间

我们的星球是一个球体。它围绕其轴旋转。地球向东旋转。因此,太阳在不同的地方在不同的时间升起。地球大约每 24 小时自转一次。因此,世界被划分为 24 个时区。在每个时区,都有一个不同的本地时间。这种本地时间通常会因夏令时而进一步修改。

有一个对一个全球时间的务实需求。一个全球时间有助于避免关于时区和夏令时的混淆。UTC(协调世界时)被选为主要的时间标准。UTC 用于航空、天气预报、飞行计划、空中交通管制许可和地图。与本地时间不同,UTC 不会随着季节的变化而变化。

Windows API 有 GetSystemTime 函数来获取 UTC 时间。

utctime.c
#include <windows.h>
#include <wchar.h>

int wmain(void) {

    SYSTEMTIME st = {0};
  
    GetSystemTime(&st);
  
    wprintf(L"The UTC time is: %02d:%02d:%02d\n", 
        st.wHour, st.wMinute, st.wSecond);

    return 0;
}

在这个例子中,我们计算 UTC 时间。

SYSTEMTIME st = {0};

UTC 时间将存储在 SYSTEMTIME 结构中。

GetSystemTime(&st);

我们使用 GetSystemTime 函数检索 UTC 时间。

wprintf(L"The UTC time is: %02d:%02d:%02d\n", 
  st.wHour, st.wMinute, st.wSecond);

UTC 时间以 hh:mm:ss 格式打印到控制台。

C:\Users\Jano\Documents\Pelles C Projects\timedate\UtcTime>UtcTime.exe
The UTC time is: 19:25:20

这是 UTC 时间的输出。

算术

不建议对 SYSTEMTIME 结构中的值进行算术运算以获得相对时间。相反,我们将 SYSTEMTIME 结构转换为 FILETIME 结构,将生成的 FILETIME 结构复制到 ULARGE_INTEGER 结构,并在 ULARGE_INTEGER 值上使用正常的 64 位算术运算。最后,我们将 FILETIME 结构转换回 SYSTEMTIME 结构。

arithmetic.c
#include <windows.h>
#include <wchar.h>

#define NSECS 60*60*3

int wmain(void) {

    SYSTEMTIME st = {0};
    FILETIME ft = {0};

    GetLocalTime(&st);

    wprintf(L"%02d/%02d/%04d %02d:%02d:%02d\n",
        st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond);

    SystemTimeToFileTime(&st, &ft);

    ULARGE_INTEGER u = {0};
     
    memcpy(&u, &ft, sizeof(u));
    u.QuadPart += NSECS * 10000000LLU;
    memcpy(&ft, &u, sizeof(ft));

    FileTimeToSystemTime(&ft, &st);

    wprintf(L"%02d/%02d/%04d %02d:%02d:%02d\n",
        st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond);

    return 0;
}

在这个例子中,我们在当前本地时间值上加了三个小时。

#define NSECS 60*60*3

这三个小时以秒为单位表示。

GetLocalTime(&st);

使用 GetLocalTime 函数,我们检索当前本地时间。

SystemTimeToFileTime(&st, &ft);

我们调用 SystemTimeToFileTime 函数将 SYSTEMTIME 结构转换为 FILETIME 结构。

ULARGE_INTEGER u = {0};

创建 ULARGE_INTEGER 结构。

memcpy(&u, &ft, sizeof(u));
u.QuadPart += NSECS * 10000000LLU;
memcpy(&ft, &u, sizeof(ft));

我们在 ULARGE_INTEGER 结构的 QuadPart 成员中添加了三个小时。该成员以 100 纳秒的滴答声表示;因此,我们将 NSECS 乘以 10000000LLU

FileTimeToSystemTime(&ft, &st);

我们将 FILETIME 结构转换回 SYSTEMTIME 结构。

C:\Users\Jano\Documents\Pelles C Projects\timedate\Arithmetic>Arithmetic.exe
01/02/2016 13:28:13
01/02/2016 16:28:13

这是 Arithmetic.exe 的示例输出。三个小时已正确添加到当前本地时间。

Date

GetLocalTime 函数也用于确定当前日期。

today.c
#include <windows.h>
#include <wchar.h>

int wmain(void) {

    SYSTEMTIME st = {0};
  
    GetLocalTime(&st);
  
    wprintf(L"Today is: %d-%02d-%02d\n", st.wYear, st.wMonth, st.wDay);

    return 0;
}

上面的程序打印今天的日期。

SYSTEMTIME st = {0};

我们声明一个 SYSTEMTIME 结构。

GetLocalTime(&st);

我们用当前的本地时间和日期值填充 SYSTEMTIME 成员。

wprintf(L"Today is: %d-%02d-%02d\n", st.wYear, st.wMonth, st.wDay);

当前日期打印到控制台。我们选择了格里高利大端日期格式。

C:\Users\Jano\Documents\Pelles C Projects\timedate\Today>Today.exe
Today is: 2016-01-30

这是 Today.exe 程序的输出。

格式化日期

GetDateFormatEx 函数将日期格式化为指定区域设置的日期字符串。

date_format.c
#include <windows.h>
#include <wchar.h>

int wmain(void) {

    PDWORD cChars = NULL;
    HANDLE std = GetStdHandle(STD_OUTPUT_HANDLE);   
    
    if (std == INVALID_HANDLE_VALUE) {
        wprintf(L"Cannot retrieve standard output handle %d\n", 
            GetLastError());
        return 1;
    }
 
    SYSTEMTIME lt = {0};
    GetLocalTime(&lt);
     
    wchar_t buf[128] = {0};
     
    int r = GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, DATE_LONGDATE, 
                &lt, NULL, buf, sizeof(buf)/sizeof(buf[0]), NULL);

    if (r == 0) {
    
        wprintf(L"GetDateFormatEx function failed %d\n", 
            GetLastError());
            
        CloseHandle(std);
        
        return 1;
    }

    WriteConsoleW(std, buf, wcslen(buf), cChars, NULL);
    
    r = CloseHandle(std);

    if (r == 0) {
    
        wprintf(L"Cannot close console handle %d\n", 
            GetLastError());
        return 1;    
    }
    
    CloseHandle(std);

    return 0;
}

该程序以本地化格式打印当前本地时间。

SYSTEMTIME lt = {0};
GetLocalTime(&lt);

检索本地时间。

int r = GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, DATE_LONGDATE, 
			&lt, NULL, buf, sizeof(buf)/sizeof(buf[0]), NULL);

GetDateFormatEx 以区域和语言选项中指定的默认区域设置格式化日期。日期以长日期格式打印。

WriteConsoleW(std, buf, wcslen(buf), cChars, NULL);

日期打印到控制台。

C:\Users\Jano\Documents\Pelles C Projects\timedate\DateFormat>DateFormat.exe
1. februára 2016

该程序以斯洛伐克语打印日期。

确定闰年

一个闰年是包含额外一天的年份。日历中增加一天的原因是天文年和日历年之间的差异。日历年恰好有 365 天,而天文年,地球绕太阳公转一周的时间是 365.25 天。差异是 6 小时,这意味着在四年时间里,我们缺少一天。因为我们希望我们的日历与季节同步,所以我们每四年在二月增加一天。(也有例外。)在格里高利历中,闰年的二月有 29 天而不是通常的 28 天。而且这一年持续 366 天而不是通常的 365 天。

leapyear.c
#include <windows.h>
#include <stdbool.h>
#include <wchar.h>

bool isLeapYear(int);

int wmain(void) {

    // Assume year >= 1582 in the Gregorian calendar.
    int years[] = { 2000, 2002, 2004, 2008, 2012, 2016, 2020,
        1900, 1800, 1600 };
  
    int size = sizeof(years) / sizeof(int);

    for (int i=0; i<size; i++) {

        if (isLeapYear(years[i])) {

            wprintf(L"%ld is a leap year\n", years[i]);
        } else {

            wprintf(L"%ld is not a leap year\n", years[i]);
        }
    }

    return 0;
}

bool isLeapYear(int year) {

    if (year % 4 != 0) {
        
        return false;
    } else if (year % 400 == 0) {
        
        return true;
    } else if (year % 100 == 0) {
        
        return false;
    } else {
        
        return true;
    }
}

我们有一个年份数组。我们检查所有年份是否是闰年。没有内置函数来检查闰年。我们创建了一个自定义的 isLeapYear 函数。

// Assume year >= 1582 in the Gregorian calendar.
int years[] = { 2000, 2002, 2004, 2008, 2012, 2016, 2020,
    1900, 1800, 1600 };

这是一个我们检查的年份数组。年份必须是公历。

for (int i=0; i<size; i++) {

    if (isLeapYear(years[i])) {

        wprintf(L"%ld is a leap year\n", years[i]);
    } else {

        wprintf(L"%ld is not a leap year\n", years[i]);
    }
}

使用 for 循环遍历数组。我们使用 isLeapYear 函数检查某一年是否是闰年。

bool isLeapYear(int year) {

    if (year % 4 != 0) {
        
        return false;
    } else if (year % 400 == 0) {
        
        return true;
    } else if (year % 100 == 0) {
        
        return false;
    } else {
        
        return true;
    }
}

这是用于确定闰年的函数。闰年是 4 的整数倍。是 100 的整数倍的年份不是闰年,除非它也是 400 的整数倍,在这种情况下它也是闰年。

C:\Users\Jano\Documents\Pelles C Projects\timedate\LeapYear>LeapYear.exe
2000 is a leap year
2002 is not a leap year
2004 is a leap year
2008 is a leap year
2012 is a leap year
2016 is a leap year
2020 is a leap year
1900 is not a leap year
1800 is not a leap year
1600 is a leap year

LeapYear.exe 程序的输出。

正常运行时间

GetTickCount 函数可用于获取计算机的正常运行时间。它检索自系统启动以来经过的毫秒数。

DWORD WINAPI GetTickCount(void);

该函数返回一个 DWORD 值,因此返回的最大天数为 49.7 天。为了克服此限制,我们可以使用 GetTickCount64。该函数自 Windows Vista 以来可用。

uptime.c
#include <windows.h>
#include <wchar.h>

int wmain(void) {  

    DWORD tc = GetTickCount();

    short seconds = tc / 1000 % 60; 
    short minutes = tc / 1000 / 60 % 60; 
    short hours = tc / 1000 / 60 / 60 % 24; 
    short days = tc / 1000 / 60 / 60 / 24 % 7;  
    short weeks = tc / 1000 / 60 / 60 / 24 / 7 % 52; 

    wprintf(L"Computer has been running for: ");
                    
    if (weeks > 0 && weeks != 1) {

        wprintf(L"%hi weeks ", weeks);
    } else if (weeks == 1) {

        wprintf(L"1 week ");
    }

    if (days > 0 && days != 1) {

        wprintf(L"%hi days ", days);
    } else if (days == 1) {

        wprintf(L"1 day ");
    }

    if (hours > 0 && hours != 1) {

        wprintf(L"%hi hours ", hours);
    } else if (hours == 1) {

        wprintf(L"1 hour ");
    }

    if (minutes > 0 && minutes != 1) {

        wprintf(L"%hi minutes ", minutes); 
    } else if (minutes == 1) {

        wprintf(L"1 minute ");
    }

    wprintf(L"and %hi seconds\n", seconds);

    return 0;
}

该程序打印计算机的正常运行时间。我们使用 GetTickCount 函数。如果计算机运行时间少于 49.71 天或 4294967296 毫秒,则它正常工作。之后,DWORD 值溢出。

DWORD tc = GetTickCount();

我们得到计算机运行的毫秒数。DWORD 变量可以存储的最大数量是 ULONG_MAX

short seconds = tc / 1000 % 60; 
short minutes = tc / 1000 / 60 % 60; 
short hours = tc / 1000 / 60 / 60 % 24; 
short days = tc / 1000 / 60 / 60 / 24 % 7;  
short weeks = tc / 1000 / 60 / 60 / 24 / 7 % 52; 

我们计算秒、分钟、小时、天和周。

if (weeks > 0 && weeks != 1) {

  wprintf(L"%hi weeks ", weeks);
} else if (weeks == 1) {

  wprintf(L"1 week ");
}

如果计算机运行一周或更长时间,我们会在控制台上打印周变量或 "1 周" 字符串。

C:\winapi\examples2\datetime\Uptime>Uptime.exe
Computer has been running for: 3 hours 31 minutes and 7 seconds

示例输出。

星期几

SYSTEMTIME 结构的 wDayOfWeek 成员存储星期几。这些值为 1..7,其中 1 是星期日,2 是星期一,... 7 是星期六。

dayofweek.c
#include <windows.h>
#include <wchar.h>

int wmain(void) {

    SYSTEMTIME st = {0};

    wchar_t *dn[] = { L"Sunday", L"Monday", L"Tuesday", 
        L"Wednesday", L"Thursday", L"Friday", L"Saturday" };

    GetLocalTime(&st);
    wprintf(L"Today is %ls\n", dn[st.wDayOfWeek]);

    return 0;
}

代码将当前星期几打印到控制台。

wchar_t *dn[] = { L"Sunday", L"Monday", L"Tuesday", 
  L"Wednesday", L"Thursday", L"Friday", L"Saturday" };

我们将星期几的名称存储在一个字符串数组中。

GetLocalTime(&st);
wprintf(L"Today is %ls\n", dn[st.wDayOfWeek]);

这些行检索并打印当前星期几。

C:\Users\Jano\Documents\Pelles C Projects\timedate\DayOfWeek>DayOfWeek.exe
Today is Sunday

这是输出。

纪元

纪元是时间的一个瞬间,被选为特定时代的起点。例如,在西方基督教国家,时间纪元从耶稣诞生的第 0 天开始(据信诞生)。另一个例子是法国共和历,使用了十二年。纪元是共和时代的开始,共和时代于 1792 年 9 月 22 日宣布,即第一共和国成立和君主制被废除之日。计算机也有它们的纪元。最受欢迎的之一是 Unix 时间。Unix 纪元是 1970 年 1 月 1 日格林威治标准时间 (UTC) 00:00:00(或 ISO 8601 的 1970-01-01T00:00:00Z)。计算机中的日期和时间是根据自该计算机或平台的定义纪元以来经过的秒数或时钟滴答数来确定的。

Windows 操作系统有几个纪元。Microsoft Excel、MS SQL Server 或 FAT32 文件系统有不同的时间纪元。Windows API 纪元是 1601 年 1 月 1 日,UTC 时间 00:00:00。选择此日期的原因是庆祝格里高利历被接受 400 周年。周年纪念日恰逢 Windows NT 设计的时候。FILETIME 结构包含一个 64 位值,表示自 1601 年 1 月 1 日(UTC)以来经过的 100 纳秒间隔数。

windows_epoch.c
#include <windows.h>
#include <wchar.h>

int wmain(void) {

    FILETIME ft = {0};
  
    GetSystemTimeAsFileTime(&ft);

    LARGE_INTEGER li = {0};    

    li.LowPart = ft.dwLowDateTime;
    li.HighPart = ft.dwHighDateTime;

    long long int hns = li.QuadPart;
    
    wprintf(L"%lli hundreds of nanoseconds have elapsed " 
        "since Windows API epoch\n", hns);

    return 0;
}

代码示例计算自 Windows API 纪元到这一刻经过的 100 纳秒间隔数。

FILETIME ft = {0};

我们声明 FILETIME 结构。它有两个成员。dwLowDateTime 保存文件时间的低位部分。dwHighDateTime 保存文件时间的高位部分。

LARGE_INTEGER li = {0};

LARGE_INTEGER 是一个联合,它帮助我们将 FILETIME 结构的成员转换为 100 纳秒间隔。

li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;

FILETIME 结构的值复制到大整数联合成员。

long long int hns = li.QuadPart;

QuadPart 成员存储从 LowPartHighPart 成员确定的百纳秒数。它是一个巨大的数字,存储为 64 位整数。

wprintf(L"%lli hundreds of nanoseconds have elapsed " 
  "since Windows API epoch\n", hns);

该值打印到控制台。

C:\Users\Jano\Documents\Pelles C Projects\timedate\WindowsEpoch>WindowsEpoch.exe
130987330019489987 hundreds of nanoseconds have elapsed since Windows API epoch

这是示例输出。

以下示例将 Windows API 时间转换为 Unix 时间。

unix_time.c
#include <windows.h>
#include <wchar.h>

#define WINDOWS_TICKS_PER_SEC 10000000
#define EPOCH_DIFFERENCE 11644473600LL

long long WindowsTicksToUnixSeconds(long long);

int wmain(void) {

    FILETIME ft = {0};
  
    GetSystemTimeAsFileTime(&ft);

    LARGE_INTEGER li = {0};    

    li.LowPart = ft.dwLowDateTime;
    li.HighPart = ft.dwHighDateTime;

    long long int hns = li.QuadPart;
    
    wprintf(L"Windows API time: %lli\n", hns);

    long long int utm = WindowsTicksToUnixSeconds(hns);

    wprintf(L"Unix time: %lli\n", utm);

    return 0;
}

long long int WindowsTicksToUnixSeconds(long long windowsTicks) {

     return (windowsTicks / WINDOWS_TICKS_PER_SEC - EPOCH_DIFFERENCE);
}

该示例将 Windows API 时间和 Unix 时间打印到控制台。

#define EPOCH_DIFFERENCE 11644473600LL

两个纪元之间的差异是 11644473600LL。请注意,闰秒是在 1972 年引入的,因此我们不考虑它们。

long long int WindowsTicksToUnixSeconds(long long windowsTicks) {

     return (windowsTicks / WINDOWS_TICKS_PER_SEC - EPOCH_DIFFERENCE);
}

该函数将 Windows 滴答数转换为 Unix 时间秒。

C:\Users\Jano\Documents\Pelles C Projects\timedate\UnixTime>UnixTime.exe
Windows API time: 130987431026414297
Unix time: 1454269502

这是 UnixTime.exe 示例的输出。

到圣诞节的天数

Windows API 没有任何函数来计算两天之间的差值。我们必须自己做数学运算。

days_to_xmas.c
#include <windows.h>
#include <wchar.h>

int wmain(void) {

    FILETIME ft1 = {0};
    FILETIME ft2 = {0};
    SYSTEMTIME st = {0};  
    LARGE_INTEGER li1 = {0};    
    LARGE_INTEGER li2 = {0}; 

    st.wYear = 2016;
    st.wMonth = 12;
    st.wDay = 25;
 
    int r = SystemTimeToFileTime(&st, &ft1);

    if (r == 0) {

        wprintf(L"Failed to convert system time to file time\n (%d)", 
            GetLastError());
        return 1;
    }
  
    GetSystemTimeAsFileTime(&ft2);
   
    li1.LowPart = ft1.dwLowDateTime;
    li1.HighPart = ft1.dwHighDateTime;
 
    li2.LowPart = ft2.dwLowDateTime;
    li2.HighPart = ft2.dwHighDateTime;

    long long int dif = li1.QuadPart - li2.QuadPart;

    int days2xmas = dif / 10000000L / 60 / 60 / 24;

    if (days2xmas == 1) {

        wprintf(L"There is one day until Christmas\n", days2xmas);
    } else if (days2xmas == 0) {

        wprintf(L"Today is Chritmas\n");
    } else {

        wprintf(L"There are %d days until Christmas\n", days2xmas);
    }
  
    return 0;
}

代码示例计算到圣诞节的天数。

FILETIME ft1 = {0};
FILETIME ft2 = {0};
SYSTEMTIME st = {0};  
LARGE_INTEGER li1 = {0};    
LARGE_INTEGER li2 = {0}; 

我们需要 FILETIMESYSTEMTIME 结构和 LARGE_INTEGER 联合来执行我们的计算。

st.wYear = 2016;
st.wMonth = 12;
st.wDay = 25;

SYSTEMTIME 结构填充了圣诞节的日期值。

int r = SystemTimeToFileTime(&st, &ft1);

圣诞节的系统时间转换为文件时间。

GetSystemTimeAsFileTime(&ft2);

我们使用 GetSystemTimeAsFileTime 函数获取当前日期作为文件时间。

li1.LowPart = ft1.dwLowDateTime;
li1.HighPart = ft1.dwHighDateTime;

li2.LowPart = ft2.dwLowDateTime;
li2.HighPart = ft2.dwHighDateTime;

我们用文件时间的低位和高位部分填充这两个联合。

long long int dif = li1.QuadPart - li2.QuadPart;

计算两个日期之间的差值。

int days2xmas = dif / 10000000L / 60 / 60 / 24;

差值以 100 纳秒表示。该值转换为天。

C:\Users\Jano\Documents\Pelles C Projects\timedate\DaysToXmas>DaysToXmas.exe
There are 328 days until Christmas

在 2016 年 1 月 31 日,我们得到此输出。

比较时间

CompareFileTime 函数可用于比较两个文件时间。当指定的时间较早时,该函数返回 -1。当两个时间相等时,它返回 0。当第一个时间晚于第二个文件时间时,它返回 1。

compare_time.c
#include <windows.h>
#include <wchar.h>

int wmain(void) {

    SYSTEMTIME st1 = {0};
    SYSTEMTIME st2 = {0};
    FILETIME ft1 = {0};
    FILETIME ft2 = {0};

    st1.wYear = 2015;
    st1.wMonth = 4;
    st1.wDay = 12;

    st2.wYear = 2015;
    st2.wMonth = 5;
    st2.wDay = 12;

    int r1 = SystemTimeToFileTime(&st1, &ft1);

    if (r1 == 0) {

        wprintf(L"Failed to convert system time to file time\n (%d)", 
            GetLastError());
        return 1;
    }
  
    int r2 = SystemTimeToFileTime(&st2, &ft2);

    if (r2 == 0) {

        wprintf(L"Failed to convert system time to file time\n (%d)", 
            GetLastError());
        return 1;
    }
    
    short ct = CompareFileTime(&ft1, &ft2);

    if (ct == -1) {

        wprintf(L"4/12/2015 comes before 5/12/2015\n");
    } else if (ct == 0) {

        wprintf(L"4/12/2015 is equal to 5/12/2015\n");
    } else if (ct == 1) {

        wprintf(L"4/12/2015 comes after 5/12/2015\n");
    }

    return 0;
}

我们有两个时间值。我们使用 CompareFileTime 来确定哪个时间较早。

st1.wYear = 2015;
st1.wMonth = 4;
st1.wDay = 12;

st2.wYear = 2015;
st2.wMonth = 5;
st2.wDay = 12;

定义了这两个时间。

int r1 = SystemTimeToFileTime(&st1, &ft1);

if (r1 == 0) {

	wprintf(L"Failed to convert system time to file time\n (%d)", 
		GetLastError());
	return 1;
}

int r2 = SystemTimeToFileTime(&st2, &ft2);

if (r2 == 0) {

	wprintf(L"Failed to convert system time to file time\n (%d)", 
		GetLastError());
	return 1;
}

使用 SystemTimeToFileTime 函数调用将系统时间转换为文件时间。

short ct = CompareFileTime(&ft1, &ft2);

使用 CompareFileTime 函数比较两个文件时间。

if (ct == -1) {

	wprintf(L"4/12/2015 comes before 5/12/2015\n");
} else if (ct == 0) {

	wprintf(L"4/12/2015 is equal to 5/12/2015\n");
} else if (ct == 1) {

	wprintf(L"4/12/2015 comes after 5/12/2015\n");
}

根据返回的值,我们在控制台上打印一条消息。

C:\Users\Jano\Documents\Pelles C Projects\timedate\CompareTime>CompareTime.exe
4/12/2015 comes before 5/12/2015

这是 CompareTime.exe 程序的输出。

时区

时区 是使用相同标准时间的一个区域。世界上有 24 个时区。

UTC = local time + bias

偏差是 UTC 时间和本地时间之间的差值(以分钟为单位)。

检索时区

GetTimeZoneInformation 用于获取时区信息。该信息存储在 TIME_ZONE_INFORMATION 结构中。

get_time_zone.c
#include <windows.h>
#include <wchar.h>

int wmain(void) {

    TIME_ZONE_INFORMATION tzi = {0};
    
    int r = GetTimeZoneInformation(&tzi);

    if (r == TIME_ZONE_ID_INVALID) {

        wprintf(L"Failed to get time zone %d", GetLastError());
        return 1;
    }

    wprintf(L"Time zone: %ls\n", tzi.StandardName);
    wprintf(L"The bias is: %ld minutes\n", tzi.Bias);

    return 0;
}

该示例打印用户的时区。

TIME_ZONE_INFORMATION tzi = {0};

TIME_ZONE_INFORMATION 结构存储时区的设置。

int r = GetTimeZoneInformation(&tzi);

GetTimeZoneInformation 函数检索当前时区设置。

wprintf(L"Time zone: %ls\n", tzi.StandardName);

TIME_ZONE_INFORMATION 结构的 StandardName 成员存储我们时区的名称。

wprintf(L"The bias is: %ld minutes\n", tzi.Bias);

我们打印偏差值。

C:\Users\Jano\Documents\Pelles C Projects\timedate\GetTimeZone>GetTimeZone.exe
Time zone: Central Europe Standard Time
The bias is: -60 minutes

我们的时区是欧洲中部标准时间 (CEST),偏差为 -60 分钟。

将本地时间转换为通用时间

TzSpecificLocalTimeToSystemTime 函数将本地时间转换为 UTC 时间。该函数考虑了夏令时 (DST) 是否对要转换的本地时间有效。

localtime_to_universaltime.c
#include <windows.h>
#include <wchar.h>

int wmain(void) { 

    SYSTEMTIME lt = {0};
    GetLocalTime(&lt);

    TIME_ZONE_INFORMATION tzi = {0};
    GetTimeZoneInformation(&tzi);

    SYSTEMTIME utm = {0};

    int r = TzSpecificLocalTimeToSystemTime(&tzi, &lt, &utm);
    
    if (r == 0) {

        wprintf(L"Failed to convert local time to system time %d\n)", 
            GetLastError());
        return 1;
    }

    wprintf(L"Date: %d/%d/%d\n", lt.wMonth, lt.wDay, lt.wYear);

    wprintf(L"The local time is: %02d:%02d:%02d\n", 
        lt.wHour, lt.wMinute, lt.wSecond);

    wprintf(L"The universal time is: %02d:%02d:%02d\n", 
        utm.wHour, utm.wMinute, utm.wSecond);

    return 0;
}

该示例将本地时间转换为世界协调时 (UTC)。

SYSTEMTIME lt = {0};
GetLocalTime(&lt);

当前本地时间使用 GetLocalTime 函数获取。

TIME_ZONE_INFORMATION tzi = {0};
GetTimeZoneInformation(&tzi);

时区设置使用 GetTimeZoneInformation 函数确定。

int r = TzSpecificLocalTimeToSystemTime(&tzi, &lt, &utm);

TzSpecificLocalTimeToSystemTime 函数将本地时间转换为世界协调时,同时考虑夏令时。

wprintf(L"The local time is: %02d:%02d:%02d\n", 
	lt.wHour, lt.wMinute, lt.wSecond);

本地时间打印到控制台。

wprintf(L"The universal time is: %02d:%02d:%02d\n", 
	utm.wHour, utm.wMinute, utm.wSecond);

世界协调时打印到控制台。

C:\Users\Jano\Documents\Pelles C Projects\timedate\LocalTimeToUniversalTime>LocalTimeToUniversalTime.exe
Date: 2/1/2016
The local time is: 11:39:48
The universal time is: 10:39:48

在欧洲中部夏令时 (CEST) 时区,2016年2月1日,我们得到上述输出。

在本 Windows API 教程中,我们使用了日期和时间。