http://blog.chinaunix.net/uid-10399364-id-2958010.html
http://langkes.blog.163.com/blog/static/3959176420115741619882/
[root@localhost time]# cat localtime.c #include <time.h> /* The C Standard says that localtime and gmtime return the same pointer. */ struct tm _tmbuf; /* Return the `struct tm' representation of *T in local time, using *TP to store the result. */ struct tm * __localtime_r (t, tp) const time_t *t; struct tm *tp; { return __tz_convert (t, 1, tp); } weak_alias (__localtime_r, localtime_r) /* Return the `struct tm' representation of *T in local time. */ struct tm * localtime (t) const time_t *t; { return __tz_convert (t, 1, &_tmbuf); } libc_hidden_def (localtime)
[root@localhost time]# pwd
/usr/src/debug/glibc-2.5-20061008T1257/time
[root@localhost time]# cat tzset.c
/* Reinterpret the TZ environment variable and set `tzname'. */ #undef tzset void __tzset (void) { __libc_lock_lock (tzset_lock); tzset_internal (1, 1); if (!__use_tzfile) { /* Set `tzname'. */ __tzname[0] = (char *) tz_rules[0].name; __tzname[1] = (char *) tz_rules[1].name; } __libc_lock_unlock (tzset_lock); } weak_alias (__tzset, tzset) /* Return the `struct tm' representation of *TIMER in the local timezone. Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */ struct tm * __tz_convert (const time_t *timer, int use_localtime, struct tm *tp) { long int leap_correction; int leap_extra_secs; if (timer == NULL) { __set_errno (EINVAL); return NULL; } __libc_lock_lock (tzset_lock); /* Update internal database according to current TZ setting. POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname. This is a good idea since this allows at least a bit more parallelism. By analogy we apply the same rule to gmtime_r. */ tzset_internal (tp == &_tmbuf, 0); if (__use_tzfile) __tzfile_compute (*timer, use_localtime, &leap_correction, &leap_extra_secs, tp); else { if (! __offtime (timer, 0, tp)) tp = NULL; else tz_compute (tp); leap_correction = 0L; leap_extra_secs = 0; } if (tp) { if (use_localtime) { if (!__use_tzfile) { int isdst; /* We have to distinguish between northern and southern hemisphere. For the latter the daylight saving time ends in the next year. */ if (__builtin_expect (tz_rules[0].change > tz_rules[1].change, 0)) isdst = (*timer < tz_rules[1].change || *timer >= tz_rules[0].change); else isdst = (*timer >= tz_rules[0].change && *timer < tz_rules[1].change); tp->tm_isdst = isdst; tp->tm_zone = __tzname[isdst]; tp->tm_gmtoff = tz_rules[isdst].offset; } } else { tp->tm_isdst = 0; tp->tm_zone = "GMT"; tp->tm_gmtoff = 0L; } if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp)) tp->tm_sec += leap_extra_secs; else tp = NULL; } __libc_lock_unlock (tzset_lock); return tp; }
[root@localhost time]#cat /usr/src/debug/glibc-2.5-20061008T1257/nptl/sysdeps/pthread/bits/libc-lock.h
/* Lock the named lock variable. */ #if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) # define __libc_lock_lock(NAME) \ ({ lll_lock (NAME, LLL_PRIVATE); 0; }) #else # define __libc_lock_lock(NAME) \ __libc_maybe_call (__pthread_mutex_lock, (&(NAME)), 0) #endif
tzset,localtime也是使用了pthread_mutex_lock() 来完成互斥调用的功能的
glibc库中可能存在大量函数跟localtime()一样使用了pthread_mutex,可能导致信号处理函数死锁,
mktime(struct tm * timeptr),并且你的代码可能会运行在DST可能实行的环境中,那么最好在你调用mktime之前将timeptr->tm_isdat设置为-1。 0: 不考虑DST时间; 1: 考虑DST时间; -1: 操作系统根据当前系统设置决定是否使用DST时间;
24时区,GMT,UTC,DST,CST时间详解 全球24个时区的划分 相较于两地时间表,可以显示世界各时区时间和地名的世界时区表(World Time),就显得精密与复杂多了,通常世界时区表的表盘上会标示着全球24个时区的城市名称,但究竟这24个时区是如何产生的?过去世界各地原本各自订定当地时间,但随着交通和电讯的发达,各地交流日益频繁,不同的地方时间,造成许多困扰,于是在西元1884年的国际会议上制定了全球性的标准时,明定以英国伦敦格林威治这个地方为零度经线的起点(亦称为本初子午线),并以地球由西向东每24小时自转一周360°,订定每隔经度15°,时差1小时。而每15°的经线则称为该时区的中央经线,将全球划分为24个时区,其中包含23个整时区及180°经线左右两侧的2个半时区。就全球的时间来看,东经的时间比西经要早,也就是如果格林威治时间是中午12时,则中央经线15°E的时区为下午1时,中央经线30°E时区的时间为下午2时;反之,中央经线15°W的时区时间为上午11时,中央经线30°W时区的时间为上午10时。以台湾为例,台湾位于东经121°,换算后与格林威治就有8小时的时差。如果两人同时从格林威治的0°各往东、西方前进,当他们在经线180°时,就会相差24小时,所以经线180°被定为国际换日线,由西向东通过此线时日期要减去一日,反之,若由东向西则要增加一日。 格林威治标准时间GMT 十七世纪,格林威治皇家天文台为了海上霸权的扩张计画而进行天体观测。1675年旧皇家观测所(Old Royal Observatory) 正式成立,到了1884年决定以通过格林威治的子午线作为划分地球东西两半球的经度零度。观测所门口墙上有一个标志24小时的时钟,显示当下的时间,对全球而言,这里所设定的时间是世界时间参考点,全球都以格林威治的时间作为标准来设定时间,这就是我们耳熟能详的「格林威治标准时间」(Greenwich Mean Time,简称G.M.T.)的由来,标示在手表上,则代表此表具有两地时间功能,也就是同时可以显示原居地和另一个国度的时间。 世界协调时间UTC 多数的两地时间表都以GMT来表示,但也有些两地时间表上看不到GMT字样,出现的反而是UTC这3个英文字母,究竟何谓UTC?事实上,UTC指的是Coordinated Universal Time- 世界协调时间(又称世界标准时间、世界统一时间),是经过平均太阳时(以格林威治时间GMT为准)、地轴运动修正后的新时标以及以「秒」为单位的国际原子时所综合精算而成的时间,计算过程相当严谨精密,因此若以「世界标准时间」的角度来说,UTC比GMT来得更加精准。其误差值必须保持在0.9秒以内,若大于0.9秒则由位于巴黎的国际地球自转事务中央局发布闰秒,使UTC与地球自转周期一致。所以基本上UTC的本质强调的是比GMT更为精确的世界时间标准,不过对于现行表款来说,GMT与UTC的功能与精确度是没有差别的。 夏日节约时间DST 所谓「夏日节约时间」Daylight Saving Time(简称D.S.T.),是指在夏天太阳升起的比较早时,将时钟拨快一小时,以提早日光的使用,在英国则称为夏令时间(Summer Time)。这个构想于1784年由美国班杰明·富兰克林提出来,1915年德国成为第一个正式实施夏令日光节约时间的国家,以削减灯光照明和耗电开支。自此以后,全球以欧洲和北美为主的约70个国家都引用这个做法。目前被划分成两个时区的印度也正在商讨是否全国该统一实行夏令日光节约时间。欧洲手机上也有很多GSM系统的基地台,除了会传送当地时间外也包括夏令日光节约时间,做为手机的时间标准,使用者可以自行决定要开启或关闭。值得注意的是,某些国家有实施「夏日节约时间」的制度,出国时别忘了跟随当地习惯在表上调整一下,这可是机械表没有的功能设计哦! CST时间 CST却同时可以代表如下 4 个不同的时区: Central Standard Time (USA) UT-6:00 Central Standard Time (Australia) UT+9:30 China Standard Time UT+8:00 Cuba Standard Time UT-4:00 可见,CST可以同时表示美国,澳大利亚,中国,古巴四个国家的标准时间。
liaoph.co.nr Linux与Windows中的UTC时间 先介绍几个术语 UTC 协调世界时,又称世界标准时间或世界协调时间,简称UTC(从英文“Coordinated Universal Time”/法文“Temps Universel Cordonné”而来),是最主要的世界时间标准,其以原子时秒长为基础,在时刻上尽量接近于格林尼治平时。 GMT 格林威治标准时间(中国大陆翻译:格林尼治平均时间或格林尼治标准时间,台、港、澳翻译:格林威治标准时间;英语:Greenwich Mean Time,GMT)是指位于英国伦敦郊区的皇家格林威治天文台的标准时间,因为本初子午线被定义在通过那里的经线。 Localtime 本地时钟,即本地所在时区的当前时间。 简单意义上,UTC时间即等同于GMT时间。 操作系统使用两个时钟保存时间:硬件时钟和系统时钟。 硬件时钟(即实时时钟 RTC 或 CMOS 时钟)仅能保存:年、月、日、时、分、秒这些时间数值,无法保存时间标准(UTC 或 localtime)和是否使用夏令时调节。 系统时钟(即软件时间) 与硬件时间分别维护,保存了:时间、时区和夏令时设置。Linux 内核保存为自 UTC 时间 1970 年1月1日经过的秒数。初始系统时钟是从硬件时间计算得来,计算时会考虑/etc/adjtime的设置。系统启动之后,系统时钟与硬件时钟独立运行,Linux 通过时钟中断计数维护系统时钟。 硬件时钟是记录在BIOS中的时间。 对于Windows系统,默认会将BIOS中的硬件时钟当作Localtime,系统在关机时,Windows会将时间同步到硬件时间中去,因此BIOS时钟和系统时钟都成为Localtime.
对于Linux系统,如Red Hat系统,在安装时会有一个选项
System clock uses UTC:
当勾选此选项时,表示系统将BIOS硬件时钟当作UTC时间,因此系统时钟会通过BIOS时间加减所在时区和夏令时计算出。
如果不勾选此选项,系统将BIOS硬件时钟当作Localtime, 系统会直接同步硬件时钟到系统时钟而不经过时区的计算。
Linux系统在关机时,这里还是举例Red Hat系统,在关机时会通过/etc/rc.d/init.d/halt这个脚本判断系统是否使用UTC硬件时间,如果使用UTC时间,这将系统时钟Localtime转换为UTC同步至硬件时钟,如果没有使用UTC时间,则直接同步系统时钟到硬件时钟,系统是否启用UTC硬件时钟在/etc/sysconfig/clock中设定。 Linux和Windows系统共存时 如果安装了Windows操作系统,那么最好将Windos设置为UTC硬件时钟,方法为修改注册表。这样Linux系统也可以使用UTC时钟,使用UTC时钟的好处是系统自动根据时区和夏令时来设置系统时钟。如果Windows要使用Localtime, 那么Linux最好也将UTC关闭使用Localtime. 如果Linux系统和Windows系统使用不一样的设置(即都使用默认设置),系统在关机时会同步硬件时钟,最后结果是硬件时钟被改来改去,不是Windows慢了8个小时,就是Linux快了8个小时。
#include "time.h" #include "stdio.h" #include <string.h> int main(void) { const int nBufferlen = 64; char szBufferA[nBufferlen] = {0}; char szBufferB[nBufferlen] = {0}; struct tm tmA; struct tm tmA_reverse; struct tm tmB; struct tm tmB_reverse; memset(&tmA, 0, sizeof(tmA)); memset(&tmA_reverse, 0, sizeof(tmA_reverse)); memset(&tmB, 0, sizeof(tmB)); memset(&tmB_reverse, 0, sizeof(tmB_reverse)); time_t ltA=0; time_t ltB=0; // 2013-03-27 22:30:00 tmA.tm_year = 113; tmA.tm_mon = 2; tmA.tm_mday = 27; tmA.tm_hour = 22; tmA.tm_min = 30; tmA.tm_sec = 0; // Your attention here tmA.tm_isdst = 0; tmB = tmA; tmB.tm_isdst = -1; ltA=mktime(&tmA); ltB=mktime(&tmB); localtime_r(<A, &tmA_reverse); localtime_r(<B, &tmB_reverse); strftime(szBufferA, nBufferlen, "%Y-%m-%d %H:%M:%S", &tmA); strftime(szBufferB, nBufferlen, "%Y-%m-%d %H:%M:%S", &tmB); printf("\nltA: %d tmA_reverse: %s", ltA, szBufferA); printf("\nltB: %d tmB_reverse: %s\n\n", ltB, szBufferB); return 0; }
[root@localhost time]# g++ a.c -oa [root@localhost time]# ./a ltA: 1364452200 tmA_reverse: 2013-03-27 23:30:00 ltB: 1364448600 tmB_reverse: 2013-03-27 22:30:00