如何以微秒为单位从Unix时间戳正确实例化DateTime?
php > echo (DateTime::createFromFormat('U.u', '-128649660.000000'))->format('Y-m-d H:i:s.u U.u');
1965-12-03 23:59:00.000000 -128649660.000000
php > echo (DateTime::createFromFormat('U.u', '-128649659.999998'))->format('Y-m-d H:i:s.u U.u');
1965-12-03 23:59:01.999998 -128649659.999998
如您所见,时间戳中的2us
差异总计为2s-2us
的差异。
我相信正确的结果是1965-12-03 23:59:00.000002
。
如何在没有手动重新计算负时间戳的情况下实现便捷的方式?
也许我应该始终将“ U.u”格式解释为“ U + 0.u”值吗?
我的意思是u
不是微秒部分,而是与整数部分有正差?
答案 0 :(得分:2)
一种方法是,假设时间戳记为负,则强制进行微秒的计算:
$date = DateTime::createFromFormat('U', '-128649659');
$ms = (1000000-999998);
echo $date->modify("-1 second +$ms microsecond")->format('Y-m-d H:i:s.u U.u');
1965-12-03 23:59:00.000002 -128649660.000002
因此,基本上,起初您忽略了微秒部分。稍后,您只需要计算微秒部分。
如果做笔记,U.u
部分将是错误的,因此在这种情况下没有用。
不确定是否适用于每种情况,我们将不胜感激任何建议。
答案 1 :(得分:1)
您可以使用类似的方法将时间字符串转换为正确的格式。
function convertNegativeTimestamp(string $ts) {
$parts = explode('.', $ts);
if( count($parts) != 2 ) {
return $ts;
}
$parts[0] = intval($parts[0]);
if( $parts[0] < 0 ) {
$parts[1] = intval(str_pad($parts[1], 6, '0'));
$parts[1] = 1000000 - $parts[1];
return sprintf('%d.%06d', $parts[0], $parts[1]);
} else {
return $ts;
}
}
答案 2 :(得分:0)
好,那么我的解决方法是:
function uDate($ts) {
$dts = floor($ts); // integer part
$uts = number_format($ts - $dts, 6, '.', ''); // fraction part
return DateTime::createFromFormat('U\+0.u', "$dts+$uts");
}
function uTime(\DateTimeInteface $dt) { // Reverse action
$dts = $dt->format('U');
$uts = $dt->format('0.u');
return number_format($dts+$uts, 6, '.', '');
}
echo uDate('-128649659.999998')->format('Y-m-d H:i:s.u'), PHP_EOL; // 1965-12-03 23:59:00.000002
echo uDate('-128649660.000002')->format('Y-m-d H:i:s.u'), PHP_EOL; // 1965-12-03 23:58:59.999998
echo uDate('1544639767.999998')->format('Y-m-d H:i:s.u'), PHP_EOL; // 2018-12-12 18:36:07.999998
floor
函数可以简单地提取整数部分,因为它总是四舍五入为“最近的最小整数”。