--------------------------------------------------------------------------------
标题: 日期时间与 time_t 相互转换
作者: 叶飞虎
日期: 2012.05.25
--------------------------------------------------------------------------------
time_t 类型表示从 UTC(Universal Time Coordinated) 时间1970年1月1日00:00:00 (称为
UNIX 系统的Epoch时间)到当前时刻的秒数。
假设 time_t 使用 int64_t 类型存储, 与日期时间相互转换的代码如下:
// 月天数表类型
typedef unsigned short Word;
typedef Word TMonthDays[12];
// 月天数
const TMonthDays _Month_Days[2]
= {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
// 月偏移天数
const TMonthDays _Month_Offsets[2]
= {{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}};
// 从 0001.01.01 到 1970.01.01 之间的天数
const long _Delta_1970_1_1 = 719163;
// 判断是否闰年
inline bool _IsLeapYear(Word AYear)
{
return ((AYear & 3) == 0) && (((AYear % 100) != 0) || ((AYear % 400) == 0));
}
// 判断是否闰年
inline bool _IsLeapYear(long AYear)
{
return ((AYear & 3) == 0) && (((AYear % 100) != 0) || ((AYear % 400) == 0));
}
// 转换成相对 1970.01.01 的日期值
bool _EncodeDate1970(Word AYear, Word AMonth, Word ADay, long& ADate)
{
// 初始化
bool result = false;
bool boolLeap;
// 判断是否闰年
boolLeap = _IsLeapYear(AYear);
AMonth--;
AYear--;
// 检查日期是否合法
if ((AYear < 9999) && (AMonth < 12) && (ADay != 0)
&& (ADay <= _Month_Days[boolLeap][AMonth]))
{
ADate = (AYear * 365) + (AYear / 4) - (AYear / 100) + (AYear / 400);
ADate += _Month_Offsets[boolLeap][AMonth] + ADay - _Delta_1970_1_1;
result = true;
}
// 返回结果
return result;
}
// 转换成相对 1970.01.01 的日期值(注: AYear, AMonth, ADay 合法)
long _EncodeDate1970(Word AYear, Word AMonth, Word ADay)
{
// 初始化
long result;
bool boolLeap;
// 判断是否闰年
boolLeap = _IsLeapYear(AYear);
// 计算
AYear--;
result = (AYear * 365) + (AYear / 4) - (AYear / 100) + (AYear / 400);
result += _Month_Offsets[boolLeap][AMonth - 1] + ADay - _Delta_1970_1_1;
// 返回结果
return result;
}
// 转换成 time_t 的日期值(注: 不检查参数是否合法)
int64_t _EncodeTime_t0(Word AYear, Word AMonth, Word ADay,
Word AHour, Word AMinute, Word ASecond)
{
return (int64_t)_EncodeDate1970(AYear, AMonth, ADay) * 86400
+ (AHour * 3600) + (AMinute * 60) + ASecond;
}
// 转换成 time_t 的日期值
int64_t _EncodeTime_t(Word AYear, Word AMonth, Word ADay,
Word AHour, Word AMinute, Word ASecond)
{
// 初始化
int64_t result = 0;
long intDate;
// 转换日期
if ((AHour < 24) && (AMinute < 60) && (ASecond < 60)
&& _EncodeDate1970(AYear, AMonth, ADay, intDate))
result = (int64_t)intDate * 86400 + (AHour * 3600) + (AMinute * 60) + ASecond;
// 返回结果
return result;
}
// 分解相对 1970.01.01 的日期值
void _DecodeDate1970(long ADate, Word& AYear, Word& AMonth, Word& ADay)
{
// 年的天基数
static const long Y1 = 365;
static const long Y4 = Y1 * 4 + 1;
static const long Y100 = Y4 * 25 - 1;
static const long Y400 = Y100 * 4 + 1;
// 初始化
long intValue, intYear, intDays;
Word* pOffsets;
// 检查日期是否合法
intDays = ADate + _Delta_1970_1_1 - 1;
if (intDays < 0)
{
AYear = 0;
AMonth = 0;
ADay = 0;
return;
}
// 400 年分解
intValue = intDays / Y400;
intDays %= Y400;
intYear = intValue * 400 + 1;
// 100 年分解
intValue = intDays / Y100;
intDays %= Y100;
intYear += intValue * 100;
if (intValue == 4)
{
intYear -= 100;
intDays += Y100;
}
// 4 年分解
intValue = intDays / Y4;
intDays %= Y4;
intYear += intValue * 4;
// 1 年分解
intValue = intDays / Y1;
intDays %= Y1;
intYear += intValue;
if (intValue == 4)
{
intYear--;
intDays += Y1;
}
// 计算月份索引
pOffsets = (Word*)_Month_Offsets[_IsLeapYear(intYear)];
intValue = intDays / 29;
if (intValue == 12)
intValue = 11;
else if (intDays < pOffsets[intValue])
intValue--;
// 取年月日
AYear = (Word)intYear;
AMonth = (Word)intValue + 1;
ADay = (Word)intDays - pOffsets[intValue] + 1;
}
// 分解 time_t 的日期值
void _DecodeTime_t(int64_t ATime, Word& AYear, Word& AMonth, Word& ADay,
Word& AHour, Word& AMinute, Word& ASecond)
{
// 初始化
long intDate;
long intTime;
// 判断符号
intDate = (long)(ATime / 86400);
intTime = (long)(ATime % 86400);
if (ATime < 0)
{
intDate--;
intTime += 86400;
}
// 分解日期
_DecodeDate1970(intDate, AYear, AMonth, ADay);
// 分解时间
AHour = intTime / 3600;
intTime %= 3600;
AMinute = intTime / 60;
ASecond = intTime % 60;
}