Windows中的时间(SYSTEMTIME和FILETIME)&CRT中的时间(time_t和tm)

http://blog.csdn.net/bokee/article/details/5330791

http://blog.csdn.net/bokee/article/details/5330682

 

时间处理时实际项目中经常碰到的问题,这里介绍最常用的时间处理函数。

首先介绍基本的时间概念。时间一般分为两种,一种是本地时间(Local Time),一种是协调世界时间(Coordinated Universal Time ,UTC),也就是传说中的格林威治时间。本地时间与UTC时间之间的差即为时差,比如,北京时间(东八区)比UTC时间晚8个小时。

C运行库中处理时间的函数主要是这四个:

  1. time_t time(
  2. time_t *timer);

time_t类型为32位或64位整型,具体类型由编译系统决定。此函数用来获得从1970年1月1日子夜(这个时刻在不同的CRT实现中可能会不一样)到当前时刻以来所流逝的时间,以秒为单位。这个时间差叫做日历时间(Calendar Time )。

这是当然让我困惑的地方:这个特殊的时刻——1970年1月1日零时零分零秒——是指本地时间呢,还是UTC时间呢?我认为是本地时间,也就是各个时区自己的1970年1月1日零时零分零秒。可以设想这样一种情况,如果全球24时区各有一台电脑,都依次在自己所在时区的本地时间1970年1月1日零时1分零秒调用time函数,那么返回值都是60。注意,这里是依次调用(事实上是每隔1小时),而不是想象中的同时调用,这是因为相邻时区的同一本地时间,总是相差1小时。

当然,time_t型的时间方便计算机处理,但普通用户无法理解这种数字。所以我们通常需要将time_t型时间转换成我们平常所见的年月日形式。CRT中为此定义了tm结构。

  1. struct tm {
  2. int tm_sec; /* seconds after the minute - [0,59] */
  3. int tm_min; /* minutes after the hour - [0,59] */
  4. int tm_hour; /* hours since midnight - [0,23] */
  5. int tm_mday; /* day of the month - [1,31] */
  6. int tm_mon; /* months since January - [0,11] */
  7. int tm_year; /* years since 1900 */
  8. int tm_wday; /* days since Sunday - [0,6] */
  9. int tm_yday; /* days since January 1 - [0,365] */
  10. int tm_isdst; /* daylight savings time flag */
  11. };

注释中已详细解释了各个字段的用法。显然这个结构中的字段对用户更有意义。我们通常用localtime_s函数将time_t时间转换为tm时间。

  1. errno_t localtime_s(
  2. struct tm* _tm,
  3. const time_t *time);

其中第二个参数为传入的time_t时间,第一个参数为返回的tm时间。由函数名可看出,返回的tm时间表示的是本地时间。当然,我们有时候也需要获得对应的UTC时间,这时我们需要gmtime函数。

  1. errno_t gmtime_s(
  2. struct tm* _tm,
  3. const time_t* time);

后面我们会看到两者的区别。

我们知道了如何将time_t时间转换为tm时间。同样,我们会需要将tm表示的时间转换为time_t时间。这时我们需要mktime函数。

  1. time_t mktime(
  2. struct tm *timeptr);

此函数返回从"特殊时刻"到参数表示的时刻之间流逝的日历时间。另外还有个很好用的特性,就是它能修正传进来的tm结构中各字段的取值范围。比如,如果你将tm.tm_mon设为1,tm.tm_day设为33,然后以其为参数调用mktime函数,此函数会将tm.tm_mon修正为2,tm.tm_day修正为2。具体用法参照MSDN。

我们来分析下面示例代码:

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <time.h>
  4. int main()
  5. {
  6. struct tm tmLocal, tmUTC;
  7. time_t tNow;
  8. //Get current calendar time
  9. time(&tNow);
  10. printf("Time Now from time(): %llu/n", tNow);
  11. //Get current local time
  12. localtime_s(&tmLocal, &tNow);
  13. printf("Local Time(YYYY-MM-DD HH:MM:SS): %d-%d-%d %d:%d:%d/n", tmLocal.tm_year + 1900, tmLocal.tm_mon,
  14. tmLocal.tm_mday, tmLocal.tm_hour, tmLocal.tm_min, tmLocal.tm_sec);
  15. //Get UTC time corresponding to current local time, and tmLocal.tm_hour - tmUTC.tm_hour = 8
  16. gmtime_s(&tmUTC, &tNow);
  17. printf("UTC Time (YYYY-MM-DD HH:MM:SS): %d-%d-%d %d:%d:%d/n", tmUTC.tm_year + 1900, tmUTC.tm_mon,
  18. tmUTC.tm_mday, tmUTC.tm_hour, tmUTC.tm_min, tmUTC.tm_sec);
  19. //convert tmLocal to calendar time
  20. tNow = mktime(&tmLocal);
  21. printf("Time Now from mktime(): %llu/n", tNow);
  22. return EXIT_SUCCESS;
  23. }

输出结果如下:

输出结果

上面代码中,11行time函数获得从"特殊时刻"到当前时刻的日历时间,如输出结果中的第一行显示的1267192581秒。

14行localtime_s函数将日历时间转换为本地tm时间,如输出结果第二行。

18行gmtime_s函数将将日历时间转换为对应的UTC的tm时间,如输出结果第三行显示。很容易看出,第二,三行输出的时间相差8小时,因为我在东八区。如果你修改自己电脑的时区(在控制面板的Date and Time中修改),再运行此程序,比较两次的运行结果,你就可以更好的理解了。

22行mktime函数将tm时间转换为日历时间,输出结果中第四行显示的结果与第一行一样,这是必须的。。。

//-----------------------------------------------------------------------------------------------------------------------------------------

上文中介绍了C运行库中的时间处理函数。这一篇介绍Windows SDk中提供的时间函数。两种时间系统之间没有本质区别(事实上CRT时间是用Windows时间实现的,当然这是说的VC实现),同样提供本地时间和UTC时间之间的转换。不过CRT中的tm时间在SDK中对应为系统时间(SYSTEMTIME),CRT中的time_t时间在SDK中对应的为文件时间(FILETIME),那个"特殊时刻"也变成1601年1月1日的子夜。

当然,首先要弄清楚FILETIME与SYSTEMTIME定义。

  1. typedef struct _FILETIME {
  2. DWORD dwLowDateTime;
  3. DWORD dwHighDateTime;
  4. } FILETIME, *PFILETIME;
  5. typedef struct _SYSTEMTIME {
  6. WORD wYear;
  7. WORD wMonth;
  8. WORD wDayOfWeek;
  9. WORD wDay;
  10. WORD wHour;
  11. WORD wMinute;
  12. WORD wSecond;
  13. WORD wMilliseconds;
  14. } SYSTEMTIME, *PSYSTEMTIME;

比较一下,很明显,FILETIME与time_t类似,是64位整型,不过FILETIME是以100纳秒(ns)为单位。SYSTEMTIME与tm类似,不过多了一项wMilliseconds。可以看出,SDK时间比CRT的时间提供了更高的精度。同时SDK提供了更丰富的函数来处理时间。

[c-sharp] view plain copy print ?
  1. void GetSystemTime(
  2. LPSYSTEMTIME lpSystemTime);
  3. void GetLocalTime(
  4. LPSYSTEMTIME lpSystemTime);

这两个函数获得SYSTEMTIME形式的当前时间,不过GetSystemTime函数获得当前的UTC时间,GetLocalTime获得当前的本地时间,可以想象,获得的两个时间存在着时差。类似于CRT中提供tm与time_t之间的转换,SDK也提供了两个函数来转换SYSTEMTIME时间与FILETIME时间。

  1. BOOL SystemTimeToFileTime(
  2. const SYSTEMTIME* lpSystemTime,
  3. LPFILETIME lpFileTime);
  4. BOOL FileTimeToSystemTime(
  5. const FILETIME* lpFileTime,
  6. LPSYSTEMTIME lpSystemTime);

函数命名很self-explanatory,就不用多说了吧。

SDK还提供了两个很有趣的函数。

  1. BOOL LocalFileTimeToFileTime(
  2. const FILETIME* lpLocalFileTime,
  3. LPFILETIME lpFileTime);
  4. BOOL FileTimeToLocalFileTime(
  5. const FILETIME* lpFileTime,
  6. LPFILETIME lpLocalFileTime);

LocalFileTimeToFileTime函数将本地的FILETIME时间转换为对应的UTC的FILETIME时间。我觉得,这个函数只是通过将本地时间减去与UTC时间的时间差来实现转换,比如在东八区的本地时间转换为对应的UTC时间,只需要将本地时间减去8*60*60*1000*1000*10(单位100ns)。类似,FileTimeToLocalFileTime函数是将UTC时间转换为本地时间,它只是将减去时间差换成加上时间差。

了解了这些功能,让我们用代码说话吧。

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <time.h>
  4. #include <windows.h>
  5. int main()
  6. {
  7. SYSTEMTIME stLocal, stUTC, stUTC2;
  8. FILETIME ftLocal, ftUTC, ft;
  9. ULARGE_INTEGER uli;
  10. GetLocalTime(&stLocal);
  11. GetSystemTime(&stUTC);
  12. printf("Local System Time(YYYY-MM-DD HH:MM:SS): %d-%d-%d %d:%d:%d/n", stLocal.wYear, stLocal.wMonth,
  13. stLocal.wDay, stLocal.wHour, stLocal.wMinute, stLocal.wSecond);
  14. printf("UTC System Time (YYYY-MM-DD HH:MM:SS): %d-%d-%d %d:%d:%d/n", stUTC.wYear, stUTC.wMonth,
  15. stUTC.wDay, stUTC.wHour, stUTC.wMinute, stUTC.wSecond);
  16. SystemTimeToFileTime(&stLocal, &ftLocal);
  17. uli.LowPart = ftLocal.dwLowDateTime;
  18. uli.HighPart = ftLocal.dwHighDateTime;
  19. printf("Local File Time: %llu/n", uli.QuadPart);
  20. LocalFileTimeToFileTime(&ftLocal, &ftUTC);
  21. uli.LowPart = ftUTC.dwLowDateTime;
  22. uli.HighPart = ftUTC.dwHighDateTime;
  23. printf("UTC File Time: %llu/n", uli.QuadPart);
  24. FileTimeToSystemTime(&ftUTC, &stUTC2);
  25. printf("UTC System Time2 (YYYY-MM-DD HH:MM:SS): %d-%d-%d %d:%d:%d/n", stUTC2.wYear, stUTC2.wMonth,
  26. stUTC2.wDay, stUTC2.wHour, stUTC2.wMinute, stUTC2.wSecond);
  27. return EXIT_SUCCESS;
  28. }

程序输出结果如下:

程序输出结果

代码13行GetLocalTime函数获得当前的本地SYSTEMTIME时间,14行获得对应的UTC的SYSTEMTIME时间,如输出结果前两行所显示,两者相差8小时(凌晨还在写博客,表扬下自己。。。)。

20行SystemTimeToFileTime函数将本地SYSTEMTIME时间转换为方便计算的本地FILETIME形式时间,如输出结果第三行所显示。

25行LocalFileTimeToFileTime函数将本地FileTime时间转换为对应的UTC的FILETIME时间,如输出结果第四行所显示。就像前面介绍的,如果你将输出结果第三,四两行所显示的数字相减,并除以10*1000*1000*60*60,你将会得出8,你可以算下试试,记住FILETIME是以100纳秒为单位的。

最后30行FileTimeToSystemTime将FILETIME时间转换为SYSTEMTIME时间。可以看出输出结果中第五行与第二行相同,这是必须的,因为两者都是当前本地时间对应的UTC时间。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
time_t是C/C++语言标准库时间类型,表示从格林威治时间1970年1月1日00:00:00到当前时间的秒数。CTime、SYSTEMTIME、COleDateTime、COleVariant是MFC时间类型,用于便捷地进行日期和时间的操作。 下面是它们之间的互相转换代码及讲解: 1. time_t to CTime ```cpp time_t t = time(NULL); CTime time(t); ``` 这段代码将当前时间time_t类型转换为CTime类型。CTime类型的构造函数可以接受time_t类型的参数,将其转换为CTime类型。 2. CTime to time_t ```cpp CTime time(2021, 10, 1, 0, 0, 0); time_t t = time.GetTime(); ``` 这段代码将指定时间的CTime类型转换time_t类型。CTime类型的GetTime函数返回从格林威治时间1970年1月1日00:00:00到当前时间的秒数,即time_t类型。 3. SYSTEMTIME to CTime ```cpp SYSTEMTIME st; GetLocalTime(&st); CTime time(st); ``` 这段代码将当前时间的SYSTEMTIME类型转换为CTime类型。CTime类型的构造函数可以接受SYSTEMTIME类型的参数,将其转换为CTime类型。 4. CTime to SYSTEMTIME ```cpp CTime time(2021, 10, 1, 0, 0, 0); SYSTEMTIME st; time.GetAsSystemTime(st); ``` 这段代码将指定时间的CTime类型转换为SYSTEMTIME类型。CTime类型的GetAsSystemTime函数将CTime类型转换为SYSTEMTIME类型。 5. COleDateTime to CTime ```cpp COleDateTime dt; dt = COleDateTime::GetCurrentTime(); CTime time(dt.GetYear(), dt.GetMonth(), dt.GetDay(), dt.GetHour(), dt.GetMinute(), dt.GetSecond()); ``` 这段代码将当前时间的COleDateTime类型转换为CTime类型。COleDateTime类型的GetCurrentTime函数返回当前时间的COleDateTime类型,CTime类型的构造函数可以接受COleDateTime类型的参数,将其转换为CTime类型。 6. CTime to COleDateTime ```cpp CTime time(2021, 10, 1, 0, 0, 0); COleDateTime dt(time.GetYear(), time.GetMonth(), time.GetDay(), time.GetHour(), time.GetMinute(), time.GetSecond()); ``` 这段代码将指定时间的CTime类型转换为COleDateTime类型。COleDateTime类型的构造函数可以接受CTime类型的参数,将其转换为COleDateTime类型。 7. COleVariant to CTime ```cpp COleVariant var; var = COleDateTime::GetCurrentTime(); CTime time(var.date); ``` 这段代码将当前时间的COleVariant类型转换为CTime类型。COleVariant类型的构造函数可以接受COleDateTime类型的参数,将其转换为COleVariant类型,CTime类型的构造函数可以接受DATE类型的参数,将其转换为CTime类型。 8. CTime to COleVariant ```cpp CTime time(2021, 10, 1, 0, 0, 0); COleVariant var(time); ``` 这段代码将指定时间的CTime类型转换为COleVariant类型。COleVariant类型的构造函数可以接受CTime类型的参数,将其转换为COleVariant类型。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值