您的位置:首页 > 其它

UTC转换本地时间

2010-03-26 16:35 531 查看
//=====================================================================
//TITLE:
// UTC转换本地时间
//AUTHOR:
// norains
//DATE:
// Friday 26- March-2010
//Environment:
// WINDOWS XP
// WINDOWS CE
//=====================================================================

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



  即使万一真的需要用到UTC转换到特定时区的本地时间,只要你是在WinXP的环境下,也并不会花费太大的劲,只要调用SystemTimeToTzSpecificLocalTime函数:
  
SYSTEMTIME sysTime = {0};
     
     //获取系统时间。和GetLocalTime不同,该函数返回的为UTC时间
     GetSystemTime(&sysTime);
     
     //中国时区的信息
     TIME_ZONE_INFORMATION DEFAULT_TIME_ZONE_INFORMATION = {-480};
     
     //将UTC时间转换为中国时区的本地时间
     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的声明:
  typedef struct _FILETIME { 
    DWORD dwLowDateTime; 
    DWORD dwHighDateTime; 
  } FILETIME;

  
  问题就来了,FILETIME是一个结构体,包含了两个成员,我们无法直接进行算术运算!
  
  别急,问题还不是很严重。仔细观察一下,FILETIME是由两个DWORD组成,每个DWORD是32bit,一共64bit。那么,我们直接用一个64bit的变量存储该数值,不就可以简单地进行运算了?
  
  所以,我们WinCE下自力更生的SystemTimeToTzSpecificLocalTime函数出炉了:
  
BOOLSystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION lpTimeZone,LPSYSTEMTIME lpUniversalTime,LPSYSTEMTIME lpLocalTime)
{
 if(lpTimeZone == NULL || lpUniversalTime == NULL || lpLocalTime == NULL)
 {
  //如果指针为空,则没有必要进行任何计算
  return FALSE;
 }

 //将UTC时间由SYSTEMTIME转换为FILETIME格式
 FILETIME ftUniversalTime = {0};
 SystemTimeToFileTime(lpUniversalTime,&ftUniversalTime);

 //将FILETIME格式时间的数值存储到一个DWORD64变量中
 DWORD64 ddwUniversalTime = ftUniversalTime.dwHighDateTime;
 ddwUniversalTime = ddwUniversalTime << 32;
 ddwUniversalTime += ftUniversalTime.dwLowDateTime;

 //因为FILETIME的时间单位是100个亿分之一秒,然后TIME_ZONE_INFORMATION的时间单位是分,所以这里需要乘以600000000 
 DWORD64 ddwBias = abs(lpTimeZone->Bias); 
 ddwBias *= 600000000;

 //转换公式为:LOCAL_TIME = UTC - BIAS
 DWORD64 ddwLocalTime = 0;
 if(lpTimeZone->Bias > 0)
 {  
  ddwLocalTime = ddwUniversalTime - ddwBias;
 }
 else if(lpTimeZone->Bias < 0)
 {
  ddwLocalTime = ddwUniversalTime + ddwBias;
 }

 
 //将DWORD64数值转换为FILETIME格式
 FILETIME ftLocalTime = {0};
 ftLocalTime.dwLowDateTime = static_cast<DWORD>(ddwLocalTime);
 ftLocalTime.dwHighDateTime = static_cast<DWORD>(ddwLocalTime >> 32);
  
 //将FILETIME数值转换为SYSTEMTIME格式并返回
 return FileTimeToSystemTime(&ftLocalTime,lpLocalTime);

     }

  
  因为该函数的接口和WinXP的一模一样,所以文章开头的代码,我们可以不用做任何更改就能正确地在WinCE中运行了!
  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: