上一篇 | 这是最后一篇日志下一篇
文章 订阅所有文章的日志

关于time_t

关于time_t

1. time_t用于表示一个绝对时间。其本质是一个unsigned int,保存的是自1970年1月1日0点0分0秒起所经过的秒数。

2.Unix中的世界末日:2038年1月19日,凌晨3点14分07秒。
嗯,因为32位字长的Unix,其unsigned int最多只能表示到2^32,于是从1970年1月1日0点0分0秒开始数够2^32秒后便到了头——这是Unix能表示的时间最大值。

3.__time32_t和__time64_t:由于2^32秒只能保存到2038年,因此你如果想让你的电脑在2039年还工作正常,你最好还是将保存时间的变量由32位扩充至64位。于是原来的time_t被搞成两种类型:__time32_t是老式的和Unix兼容的32位时间,__time64_t则是64位的时间。这样就可以保存到1970年以后的2^64秒的年月。不过鉴于我们还用不了那么遥远,于是windows下限定__time64_t最多表示到23:59:59, December 31, 3000。嗯,我想应该是够用了。

time_t会根据是否定义了_USE_32BIT_TIME_T宏来决定自己到底是到底是__time32_t还是__time64_t。
和TCHAR很像,两面派呵呵。

4.tm。鉴于time_t保存的秒数让大多数人使用困难(比如我给你345639你能说出是哪一年哪一月吗?),于是定义了一个tm类型来表示人能看懂的时间:
C++ 代码:
struct tm {
        int tm_sec;     /* seconds after the minute - [0,59] */
        int tm_min;     /* minutes after the hour - [0,59] */
        int tm_hour;    /* hours since midnight - [0,23] */
        int tm_mday;    /* day of the month - [1,31] */
        int tm_mon;     /* months since January - [0,11] */
        int tm_year;    /* years since 1900 */
        int tm_wday;    /* days since Sunday - [0,6] */
        int tm_yday;    /* days since January 1 - [0,365] */
        int tm_isdst;   /* daylight savings time flag */
        };

这个就把时间按照年月日时分秒分的很清楚了,人们使用起来就直观了。
关于最后一个字段tm_isdst解释下:这个是一个标志,表示是否启用夏令时。1表示启用,0表示不启用,国内一般不怎么用了。(你那里用夏令时吗?)

5.tm <---> time_t
提供了这么几个函数来达到二者的互相转换:
gmtime 将time_t转换成tm。传入一个time_t,传出一个tm。
localtime将time_t转换成tm。不过这里假定time_t是一个UTC(世界标准时间),转换出来的tm是当地时间,已经经过了时区调整。(比如你在中国,是东8区,因此+8个小时)
mktime 将tm转换成time_t。传入一个tm,传出一个time_t。假定传入的是当地时间,会将其调整成UTC。(注意这时tm中的tm_wday和tm_yday两项会被忽略)
_mkgmtime*将tm转换成time_t。不进行时区调整。不过此函数只有VC才带有,标准time.h中没有。


6.mktime的实现。
想想mktime干了些什么:将年月日时分秒换算成了自1970年1月1日以来的秒数。这其中有多少需要考虑的:年有闰年和非闰年之分,而一个月有31天的,还有30天的,还有28、29天的……真是复杂。
不过自有牛人来完成这个壮举:
C++ 代码:
static inline unsigned long mktime (unsigned int year, unsigned int mon,
    unsigned int day, unsigned int hour,
    unsigned int min, unsigned int sec)
        ...{
    if (0 >= (int) (mon -= 2)) ...{    /**//* 1..12 -> 11,12,1..10 */
         mon += 12;      /**//* Puts Feb last since it has leap day */
         year -= 1;
    }

    return (((
             (unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
             year*365 - 719499
          )*24 + hour /**//* now have hours */
       )*60 + min /**//* now have minutes */
    )*60 + sec; /**//* finally seconds */
}

这是Linux下的mktime实现,就在这么短短几行之内完成了如此复杂的换算。里面一些magic number估计都会让你眼花缭乱了。如果想仔细剖析这个代码的原理,请看这里:http://blog.csdn.net/axx1611/archive/2007/09/20/1792827.aspx



[本日志由 sandy1 于 2009-11-20 04:52 PM 编辑]
文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags:
评论: 1 | 引用: 0 | 查看次数: 358
回复回复boluor[2009-11-23 11:47 AM | del]
magic number真是诡异阿。记得之前跟我看过的开方函数的magic number,完全没思路。
发表评论
昵 称:
密 码: 游客发言不需要密码.
内 容:
验证码: 验证码
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.
字数限制 1000 字 | UBB代码 开启 | [img]标签 关闭