Uinx 时间戳的转换

Unix时间戳(Unix timestamp), 定义为从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数。


//Unix时间戳从1970-1-1 (星期4) 0:0:0 开始计算
#define IsLeapYear(wy) ((wy%400 == 0) || ((wy%4==0) && (wy%100)))
#define DAYSECONDS (24*60*60I64)
#define TIMESTAMP_BEGIN_YEAR 1970
#define TIMESTAMP_BEGIN_WEEK 4
typedef LONGLONG int64;

//返回某一年的总天数
inline int GetYearDays(int wYear)
{
  return IsLeapYear(wYear)? 366:365;
}
#define GetYearDaysTick(wYear) (GetYearDays(wYear) * DAYSECONDS)

//返回某月的总天数
inline int GeMonthDays(int wYear, int wMonth)
{  
  static const int mothDays[]=
  {
    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  };

  return (mothDays[wMonth - 1] + ((wMonth == 2 && IsLeapYear(wYear))? 1:0));
}
#define GeMonthDaysTick(wYear, wMonth) (GeMonthDays(wYear, wMonth) * DAYSECONDS)

//Unix时间戳转换为本地时间
//iUnixTimeStamp UNIX timestamp
//fZoneHours 时区时间 0=UTC 8=Begin etc.
//tmLocal 本地时间
BOOL ConvUnixTimestamp2SystemTime(
  __in int64 iUnixTimeStamp, __in double fZoneHours, __out SYSTEMTIME &tmLocal)
{
  int wYear=TIMESTAMP_BEGIN_YEAR, wMonth=1, wDay=1;

  int64 iTotalTick = iUnixTimeStamp;
  iTotalTick += (int64)(fZoneHours * 60*60); //+时区时

  //计算星期 (Sunday = 0, Monday = 1, and so on)
  int wWeek = TIMESTAMP_BEGIN_WEEK;
  {
    int iWeekOff = (int)((iTotalTick/DAYSECONDS) % 7);
    if(iTotalTick < 0) { iWeekOff += 6; } //往前推算
    wWeek = (wWeek + iWeekOff) % 7;
  }

  //负数时计算出一个起始为正值的年份
  while(iTotalTick < 0)
  {    
    wYear--;
    iTotalTick += GetYearDaysTick(wYear);
  }

  //按剩余天数推算年  
  while(1)
  {
    int64 iYearDaysTick = GetYearDaysTick(wYear);
    if(iTotalTick >= iYearDaysTick)
    {
      iTotalTick -= iYearDaysTick;
      wYear++;;
    }
    else
    {
      break;
    }
  }

  //月
  while(1)
  {
    int64 iMonthDaysTick = GeMonthDaysTick(wYear, wMonth);   
    if(iTotalTick >= iMonthDaysTick)
    {
      iTotalTick -= iMonthDaysTick;
      wMonth++;
    }
    else
    {
      break;
    }
  }

  //日
  {
    wDay += (int)(iTotalTick / DAYSECONDS);
    iTotalTick -= (wDay - 1)*DAYSECONDS;
  }
  
  //时分秒
  int LeftTime = (int)(iTotalTick % DAYSECONDS); //剩余秒
  int wHour = LeftTime / (60*60);
  LeftTime -= wHour * (60*60);
  int wMinute = LeftTime / 60;
  LeftTime -= wMinute * 60;
  int wSecond = LeftTime;

  //结果赋值
  memset(&tmLocal, 0, sizeof(tmLocal));
  tmLocal.wYear = wYear;
  tmLocal.wMonth = wMonth;
  tmLocal.wDayOfWeek = wWeek;
  tmLocal.wDay = wDay;
  tmLocal.wHour = wHour;
  tmLocal.wMinute = wMinute;
  tmLocal.wSecond = wSecond;

  return TRUE;
}

//本地时间转换为Unix时间戳
//tmLocal 本地时钟
//fZoneHours 时区时间 0=UTC +8=北京 ect
//返回Unix时间戳
int64 ConvSystemTime2UnixTimestamp(__in SYSTEMTIME &tmLocal, __in double fZoneHours)
{
  //总天数
  int64 iTotalDays = 0;

  //年
  {
    int wYear;
    //负数?
    for(wYear=TIMESTAMP_BEGIN_YEAR-1; wYear>=tmLocal.wYear; wYear--)
    {
      iTotalDays -= GetYearDays(wYear);
    }
    //正数?
    for(wYear=TIMESTAMP_BEGIN_YEAR; wYear<tmLocal.wYear; wYear++)
    {
      iTotalDays += GetYearDays(wYear);
    }
  }

  //月
  {
    for(int wMonth=1; wMonth<tmLocal.wMonth; wMonth++)
    {
      iTotalDays += GeMonthDays(tmLocal.wYear, wMonth);
    }
  }
  
  //日
  {
    iTotalDays += tmLocal.wDay-1;
  }

  //转换成秒
  int64 iUnixTimeStamp = 0;
  iUnixTimeStamp += iTotalDays * DAYSECONDS;
  iUnixTimeStamp += tmLocal.wHour * (60 * 60);
  iUnixTimeStamp += tmLocal.wMinute * 60;
  iUnixTimeStamp += tmLocal.wSecond;

  //-时区时转为秒
  iUnixTimeStamp -= (int64)(fZoneHours * 60*60); 
  
  return iUnixTimeStamp;
}


//测试用例

{
  SYSTEMTIME tmLocal;
  LONGLONG iUnixTimeStamp = 100000000i64;
  double fZoneHours = +8;

  //转换成系统时间
  ConvUnixTimestamp2SystemTime(iUnixTimeStamp, fZoneHours, tmLocal);

  TRACE(_T("%I64d = %04d-%02d-%02d %02d:%02d:%02d [Week%d][Zone=%+.*g]\n"), 
    iUnixTimeStamp, 
    tmLocal.wYear, tmLocal.wMonth, tmLocal.wDay,
    tmLocal.wHour, tmLocal.wMinute, tmLocal.wSecond,
    tmLocal.wDayOfWeek,
    5, fZoneHours);

  //系统时间转换成Unix Timestamp 
  LONGLONG iUnixTimeStampO = ConvSystemTime2UnixTimestamp(tmLocal, fZoneHours);

  ASSERT(iUnixTimeStamp == iUnixTimeStampO);
}

//测试输出

-100000000 = 1966-10-31 22:13:20 [Week1][Zone=+8]

猜你喜欢

转载自blog.csdn.net/zgl7903/article/details/78235259