近日,想把负数的UTC时间戳,即1970年之前的时间,转换成可阅读的年/月/日格式。然后悲剧的发现,这个目标用标准C库中的gmtime/mktime/ctime等函数无法实现,原因是不支持UTC时间戳为负数。第一反应是,先到网上寻找在线计算工具。这里以UTC = -3597611104 为例,在各网站上进行试算。
1. Epoch Convert : Online Unix Timestamp Converter
看下图, -3597611104 转换成 GMT后,把它填入右边的格子中,抓换回来发现,时间戳变了、本地时间错乱了,但GMT时间却跟左边相同。
2. 时间戳 UNIX时间戳转换 (Unix timestamp)时间戳转换工具 iP138在线工具
这里,把时间戳抓换成本地时间。然后我们就按这个结果,重新转换回时间戳,如下图,转化后的时间戳跟原来不一样了!
3. 时间戳(Unix timestamp)转换工具 - 在线工具 (tool.lu)
转换过程如下,先把时间戳转换成年月日,再转回来。发现,转回来后的时间戳与之前相同,但是这年月日格式的结果肯定是错了,因为时间戳是偶数,但转换后的秒数部分,却是奇数39.
4. Timestamp Converter (timestamp-converter.com)
如下图,这个页面的转换结果也有问题。时间戳是偶数,但本地年月日格式的秒数部分是奇数39。另外,UTC时区和本地时区的时间差不是8小时,这是很不可思议的。
我们把上图中的ISO 8601时间复制到同页面右侧的输入框,得到如下结果。这个结果就错得离谱了!
5. Timestamp Converter
这个页面的转换结果也同样是错误的。
使用 Windows API 计算
尝试用Windows API实现这个目标。
LONGLONG UTCTime = -3597611104LL;
ULARGE_INTEGER LargeInt;
LargeInt.QuadPart = UTCTime * 10000000LL + 116444736000000000LL;
FILETIME FileTime = { LargeInt.LowPart, LargeInt.HighPart };
SYSTEMTIME SystemTime = {};
BOOL ok = FileTimeToSystemTime(&FileTime, &SystemTime);
计算结果是
那么问题来了,以上各种情况,到底哪些是正确的?