DateTime with microseconds

时间:2015-11-13 11:12:08

标签: php datetime

在我的代码中,我使用DateTime个对象来操作日期,然后将它们转换为时间戳,以便将它们保存在一些JSON文件中。

由于某些原因,我希望与DateTime(或接近的东西)具有相同的功能,但是具有微秒精度(在JSON文件中插入时我将转换为float)。

我的问题是: PHP对象是否像DateTime一样,但也可以处理微秒

目标是能够用物体操纵微量滴点。

date()文档中,有一些东西表明可以用微秒创建DateTime,但我无法找到。

  

u Microseconds(在PHP 5.2.2中添加)。请注意,date()将始终   生成000000,因为它采用整数参数,而   如果创建了DateTime,DateTime :: format()确实支持微秒   用微秒。

我曾尝试使用浮动值(microtime(true))设置DateTime对象的时间戳,但它不起作用(我认为它将时间戳转换为int,导致丢失微秒)。

这是我试过的方式

$dt = new DateTime();
$dt->setTimestamp(3.4); // I replaced 3.4 by microtime(true), this is just to give an example
var_dump($dt);
var_dump($dt->format('u'));

正如您在此处看到的那样.4未被考虑(即使我们可以使用与微秒相对应的u格式)。

object(DateTime)[1]
  public 'date' => string '1970-01-01 01:00:03' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'Europe/Berlin' (length=13)

string '000000' (length=6)
编辑:我看到了这段代码,它允许向DateTime添加微秒,但我需要在创建DateTime之前对microtime应用大量修改。因为我会经常使用它,所以我想在获得" microtime对象之前尽可能少地修改微量片段。

$d = new DateTime("15-07-2014 18:30:00.111111");

10 个答案:

答案 0 :(得分:18)

这是创建包含microtime的DateTime对象的一种非常简单的方法。

我没有深入研究这个问题所以,如果我错过了一些我道歉但希望你觉得这有用的话。

$date = DateTime::createFromFormat('U.u', microtime(TRUE));
var_dump($date->format('Y-m-d H:i:s.u')); 

我测试了它并尝试了各种其他方法来使这项工作看似合乎逻辑,但这是唯一有效的方法。 然而,有一个问题,它返回正确的时间部分,但没有正确的一天部分(因为最有可能的UTC时间) 这就是我的所作所为(恕我直言似乎更简单):

$dateObj = DateTime::createFromFormat('U.u', microtime(TRUE));
$dateObj->setTimeZone(new DateTimeZone('America/Denver'));
var_dump($dateObj->format('Y-m-d H:i:s:u'));

以下是一个工作示例:http://sandbox.onlinephpfunctions.com/code/66f20107d4adf87c90b5c8c914393d4edef180a2

<强>更新
正如评论中所指出的,从PHP 7.1开始,Planplan推荐的方法似乎优于上面显示的方法。

因此,对于PHP 7.1及更高版本,最好使用以下代码而不是上述代码:

$dateObj = DateTime::createFromFormat('0.u00 U', microtime());
$dateObj->setTimeZone(new DateTimeZone('America/Denver'));
var_dump($dateObj->format('Y-m-d H:i:s:u'));

请注意,上述内容仅适用于PHP 7.1及更高版本。以前版本的PHP将返回0代替microtime,因此会丢失所有的微量时间数据。

这是一个更新的沙箱,显示两者: http://sandbox.onlinephpfunctions.com/code/a88522835fdad4ae928d023a44b721e392a3295e

注意:在测试上面的沙箱时,我没有看到Planplan提到他经历过的微时间(TRUE)故障。然而,更新的方法似乎记录了KristopherWindsor建议的更高精度。

答案 1 :(得分:5)

Looking at a response on the PHP DateTime manual

  

DateTime不支持分秒(微秒或毫秒等)   我不知道为什么没有记录。   类构造函数会毫无怨言地接受它们,但它们会被丢弃。   似乎没有办法像#34; 2012-07-08 11:14:15.638276&#34;并以完整的方式将其存储在客观的形式中。

     

所以你不能对两个字符串进行日期数学运算,例如:

<?php
$d1=new DateTime("2012-07-08 11:14:15.638276");
$d2=new DateTime("2012-07-08 11:14:15.889342");
$diff=$d2->diff($d1);
print_r( $diff ) ;

/* returns:

DateInterval Object
(
    [y] => 0
    [m] => 0
    [d] => 0
    [h] => 0
    [i] => 0
    [s] => 0
    [invert] => 0
    [days] => 0
)

*/
?>
  

当你真的想要获得0.251066秒时,你会回到0。

但是,从here收到回复:

$micro_date = microtime();
$date_array = explode(" ",$micro_date);
$date = date("Y-m-d H:i:s",$date_array[1]);
echo "Date: $date:" . $date_array[0]."<br>";

推荐并使用引用的dateTime()类:

$t = microtime(true);
$micro = sprintf("%06d",($t - floor($t)) * 1000000);
$d = new DateTime( date('Y-m-d H:i:s.'.$micro, $t) );

print $d->format("Y-m-d H:i:s.u"); //note "u" is microseconds (1 seconds = 1000000 µs).

php.net上dateTime()的参考:http://php.net/manual/en/datetime.construct.php#

答案 2 :(得分:4)

/!\ EDIT /!\

我现在使用https://github.com/briannesbitt/Carbon,其余的答案仅仅是出于历史原因。

结束编辑

我决定使用你们给我的提示扩展课程DateTime

构造函数采用float(来自microtime)或什么都没有(在这种情况下,它将使用当前&#34;微时间戳&#34;来初始化)。 我还覆盖了两个重要的功能:setTimestampgetTimestamp

不幸的是,我无法解决性能问题,虽然它并不像我想象的那么慢。

全班同学:

<?php
class MicroDateTime extends DateTime
{
    public $microseconds = 0;

    public function __construct($time = 'now')
    {
        if ($time == 'now')
            $time = microtime(true);

        if (is_float($time + 0)) // "+ 0" implicitly converts $time to a numeric value
        {
            list($ts, $ms) = explode('.', $time);
            parent::__construct(date('Y-m-d H:i:s.', $ts).$ms);
            $this->microseconds = $time - (int)$time;
        }
        else
            throw new Exception('Incorrect value for time "'.print_r($time, true).'"');
    }

    public function setTimestamp($timestamp)
    {
        parent::setTimestamp($timestamp);
        $this->microseconds = $timestamp - (int)$timestamp;
    }

    public function getTimestamp()
    {
        return parent::getTimestamp() + $this->microseconds;
    }
}

答案 3 :(得分:2)

有多种选择。但正如Ben已经提供的那样,我会尝试给你另一个解决方案。

如果您提供了有关您希望进行何种计算的详细信息,则可以进一步更改。

$time =microtime(true);
$micro_time=sprintf("%06d",($time - floor($time)) * 1000000);
$date=new DateTime( date('Y-m-d H:i:s.'.$micro_time,$time) );
print "Date with microseconds :<br> ".$date->format("Y-m-d H:i:s.u");

$time =microtime(true);
var_dump($time);

$micro_time=sprintf("%06d",($time - floor($time)) * 1000000);
$date=new DateTime( date('Y-m-d H:i:s.'.$micro_time,$time) );
print "Date with microseconds :<br> ".$date->format("Y-m-d H:i:s.u");

list($ts,$ms) = explode(".",microtime(true));
$dt = new DateTime(date("Y-m-d H:i:s.",$ts).$ms);
echo $dt->format("Y-m-d H:i:s.u");

list($usec, $sec) = explode(' ', microtime());
print date('Y-m-d H:i:s', $sec) . $usec;

答案 4 :(得分:1)

/*
 * More or less standard complete example. Tested.
 */
  private static function utime($format, $utime = null, $timezone = null) {
    if(!$utime) {
      // microtime(true) had too fiew digits of microsecconds
      $time_arr = explode( " ", microtime( false ) );
      $utime = $time_arr[1] . substr( $time_arr[0], 1, 7 );
    }
    if(!$timezone) {
      $timezone = date_default_timezone_get();
    }
    $date_time_zone = timezone_open( $timezone );
    //date_create_from_format( "U.u", $utime ) - had a bug with 3-rd parameter
    $date_time = date_create_from_format( "U.u", $utime );
    date_timezone_set( $date_time, $date_time_zone );
    $timestr = date_format( $date_time, $format );
    return $timestr;
  }

答案 5 :(得分:1)

这在PHP 7.2中对我有用:

$dateTime = \DateTime::createFromFormat('U.u', sprintf('%f', $aFloat), $optionalTimezone);

我开始考虑,由于格式代码'u'在转换为字符串时仅输出日期的微秒部分,因此进行相反的操作是相同的。并且它还期望使用句点字符'.',因此,如果$aFloat恰好是整数,则默认转换为字符串将保留小数点。最初,我认为需要'%.6f'到字符串的浮点转换,但是'u'期望得到一个左对齐的字符串。尾随零是不必要的。

答案 6 :(得分:0)

自从我解决了问题以来,我想与您分享。 Php71 +具有微秒级精度,如果要将其转换为纳米精度,只需将其乘以1000(10 ^ 3)。

$nsTimestamp = (int) (new \DateTime())->getTimestamp() * 1000

答案 7 :(得分:0)

$micro_seconds = microtime(false) * 1000000;
echo date('Y-m-d H:i:s.'. floor($micro_seconds));

有关日期的更多信息: https://www.php.net/manual/en/function.date.php

有关微时间的更多信息:https://www.php.net/manual/en/function.microtime.php

答案 8 :(得分:0)

我有点迟了,但是我不得不开发一种适用于PHP 5,PHP 7.0和PHP 7.1+的解决方案。

list($msec, $now) = explode(' ', microtime(false));
$z = gmdate('Y-m-d\TH:i:s' . substr($msec, 1) . '\Z', $now);

这将为您提供有效的UTC时间字符串(以微秒为单位)。如果仍然需要将其作为DateTime对象,则可以直接传递以下字符串:

$dt = new DateTime($z);

如果您需要DateTime,则从PHP 5.2开始有效,但是如果您只需要微秒的字符串,那么从PHP 4开始一直是很好的。

答案 9 :(得分:0)

美好的日期和时间,一步一步地

请注意,microtime()会告知时间 AND 微时间(句点后的数字)

echo microtime(true) ."<br>"; //1601674357.9448
sleep(0.99);
echo microtime(true) ."<br>"; //1601674357.9449
sleep(0.99);
echo microtime(true) ."<br>"; //1601674357.945

因此,让我们在句点之后加上数字:

echo substr(microtime(true), 11,4) . "<br>"; //945

但是,如果您在句点之后只有一两位数字吗?我们用零完成...

好,现在我们总是有4位数字,即微秒

echo str_pad(substr(microtime(true), 11,4), 4, '0', STR_PAD_RIGHT) . "<br>"; //9450

因此,让我们添加日期... 最终结果:

$date = gmdate('Y-m-d h:i:s.');
$time = str_pad(substr(microtime(true), 11,4), 4, '0', STR_PAD_RIGHT);

echo $date . $time; //2020-10-02 09:43:57.9450