分享

UTC转换本地时间

 鹰击彩霞 2016-06-05

//=====================================================================
//TITLE:
//    UTC转换本地时间
//AUTHOR:
//    norains
//DATE:
//    Friday 26- March-2010
//Environment:
//     WINDOWS XP
//     WINDOWS CE
//=====================================================================


  一般情况下,我们很少需要用到UTC转换为本地时间--因为如果仅仅是获取本机的本地时间,我们完全可以不用如此麻烦,直接调用GetLocalTime即可。

 

  即使万一真的需要用到UTC转换到特定时区的本地时间,只要你是在WinXP的环境下,也并不会花费太大的劲,只要调用SystemTimeToTzSpecificLocalTime函数:
  

  1. SYSTEMTIME sysTime = {0};  
  2.   
  3. //获取系统时间。和GetLocalTime不同,该函数返回的为UTC时间  
  4. GetSystemTime(&sysTime);  
  5.   
  6. //中国时区的信息  
  7. TIME_ZONE_INFORMATION DEFAULT_TIME_ZONE_INFORMATION = {-480};  
  8.   
  9. //将UTC时间转换为中国时区的本地时间  
  10. SystemTimeToTzSpecificLocalTime(&DEFAULT_TIME_ZONE_INFORMATION,&sysTime,&sysTime);  


  就这么简单,调用一个函数即可进行转换。可能大家唯一疑惑的是DEFAULT_TIME_ZONE_INFORMATION的取值是怎么来的,其实很简单,TIME_ZONE_INFORMATION的时差是以分钟为单位的,北京时差为8个小时,所以8*60=480。如果是别的时区,可以依此进行更改。
    WinXP是简单了,但对于WinCE却是麻烦了。相对于WinXP来说,需要用到时区转换的机会更多,因为很多系统定制时,习惯于定义系统的默认语言为英文,以此加快加载速度和减小系统容量,所以在显示时间时必须要进行一次UTC的时间转换。可这更常使用的场合,却偏偏没有SystemTimeToTzSpecificLocalTime函数!
    没辙,活人总不能被尿给憋死吧?微软不为我们准备,那我们就自己丰衣足食咯!
    我们先从原理上想想这时区的转换,其实无非就是UTC时间偏移多少个小时,也就一个简简单单的加加减减。但问题在于,SYSTEMTIME是一个结构体,成员有秒、分、时等等。如果只是时间上的加减倒还是简单,毕竟都是60进制的;但涉及到日期,却不是一般的麻烦了。比如是今天是1号,那前一天是几号?这个不仅涉及到大小月,还有闰月的问题。不仅如此,还需要判断当前是星期几,这也不是一件轻松的事情。所以,直接采用SYSTEMTIME进行计算,对于我们来说是不太现实。
    那我们换个角度来想,SYSTEMTIME不方便,那么我们转换为FILETIME来计算不就可以了么?FILETIME可是以100个亿分之一秒为单位的啊,这不就可以直接加减了么?话虽如此,但还是有个问题。我们来看看FILETIME的声明:

  1. typedef struct _FILETIME {   
  2.   DWORD dwLowDateTime;   
  3.   DWORD dwHighDateTime;   
  4. } FILETIME;  

    问题就来了,FILETIME是一个结构体,包含了两个成员,我们无法直接进行算术运算!
    别急,问题还不是很严重。仔细观察一下,FILETIME是由两个DWORD组成,每个DWORD是32bit,一共64bit。那么,我们直接用一个64bit的变量存储该数值,不就可以简单地进行运算了?
    所以,我们WinCE下自力更生的SystemTimeToTzSpecificLocalTime函数出炉了:
  1.     
  2. BOOLSystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION lpTimeZone,LPSYSTEMTIME lpUniversalTime,LPSYSTEMTIME lpLocalTime)  
  3. {  
  4.  if(lpTimeZone == NULL || lpUniversalTime == NULL || lpLocalTime == NULL)  
  5.  {  
  6.   //如果指针为空,则没有必要进行任何计算  
  7.   return FALSE;  
  8.  }  
  9.   
  10.  //将UTC时间由SYSTEMTIME转换为FILETIME格式  
  11.  FILETIME ftUniversalTime = {0};  
  12.  SystemTimeToFileTime(lpUniversalTime,&ftUniversalTime);  
  13.   
  14.  //将FILETIME格式时间的数值存储到一个DWORD64变量中  
  15.  DWORD64 ddwUniversalTime = ftUniversalTime.dwHighDateTime;  
  16.  ddwUniversalTime = ddwUniversalTime << 32;  
  17.  ddwUniversalTime += ftUniversalTime.dwLowDateTime;  
  18.   
  19.   
  20.  //因为FILETIME的时间单位是100个亿分之一秒,然后TIME_ZONE_INFORMATION的时间单位是分,所以这里需要乘以600000000   
  21.  DWORD64 ddwBias = abs(lpTimeZone->Bias);   
  22.  ddwBias *= 600000000;  
  23.   
  24.   
  25.  //转换公式为:LOCAL_TIME = UTC - BIAS  
  26.  DWORD64 ddwLocalTime = 0;  
  27.  if(lpTimeZone->Bias > 0)  
  28.  {    
  29.   ddwLocalTime = ddwUniversalTime - ddwBias;  
  30.  }  
  31.  else if(lpTimeZone->Bias < 0)  
  32.  {  
  33.   ddwLocalTime = ddwUniversalTime + ddwBias;  
  34.  }  
  35.   
  36.   
  37.  //将DWORD64数值转换为FILETIME格式  
  38.  FILETIME ftLocalTime = {0};  
  39.  ftLocalTime.dwLowDateTime = static_cast<DWORD>(ddwLocalTime);  
  40.  ftLocalTime.dwHighDateTime = static_cast<DWORD>(ddwLocalTime >> 32);  
  41.   
  42.  //将FILETIME数值转换为SYSTEMTIME格式并返回  
  43.  return FileTimeToSystemTime(&ftLocalTime,lpLocalTime);  
  44.   
  45.   
  46.   }  

    因为该函数的接口和WinXP的一模一样,所以文章开头的代码,我们可以不用做任何更改就能正确地在WinCE中运行了!
  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多