DateTime with microseconds

后端 未结 10 2108
长发绾君心
长发绾君心 2020-12-05 10:02

In my code, I\'m using DateTime objects to manipulate dates, then convert them to timestamp in order to save them in some JSON files.

For some reasons,

相关标签:
10条回答
  • 2020-12-05 10:28

    There are multiple options. But as already provided by Ben, I will try to give you another solution.

    If you provided more details on what kind of calculations you want to do it could be changed further.

    $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");
    

    or

    $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");
    

    or

    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");
    

    or

    list($usec, $sec) = explode(' ', microtime());
    print date('Y-m-d H:i:s', $sec) . $usec;
    
    0 讨论(0)
  • 2020-12-05 10:32

    Here's a very simple method of creating a DateTime object that includes microtime.

    I didn't delve into this question too deeply so if I missed something I apologize but hope you find this helpful.

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

    I tested it out and tried various other ways to make this work that seemed logical but this was the sole method that worked for PHP versions prior to 7.1.

    However there was a problem, it was returning the correct time portion but not the correct day portion (because of UTC time most likely) Here's what I did (still seems simpler IMHO):

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

    Here's a working example: http://sandbox.onlinephpfunctions.com/code/66f20107d4adf87c90b5c8c914393d4edef180a2

    UPDATE
    As pointed out in comments, as of PHP 7.1, the method recommended by Planplan appears to be superior to the one shown above.

    So, again for PHP 7.1 and later it may be better to use the below code instead of the above:

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

    Please be aware that the above works only for PHP versions 7.1 and above. Previous versions of PHP will return 0s in place of the microtime, therefore losing all microtime data.

    Here's an updated sandbox showing both: http://sandbox.onlinephpfunctions.com/code/a88522835fdad4ae928d023a44b721e392a3295e

    NOTE: in testing the above sandbox I did not ever see the microtime(TRUE) failure which Planplan mentioned that he experienced. The updated method does, however, appear to record a higher level of precision as suggested by KristopherWindsor.

    NOTE2: Please be aware that there may be rare cases where either approach will fail because of an underlying decision made regarding the handling of microseconds in PHP DateTime code. Either:

    • avoid use of this for scientific purposes or anything where a very high level of accuracy is required.
    • OR be prepared for no microsecond data to return on an exact second mark... (where a microsecond ... which is 1 millionth of a second, will have no data to return as it is complete zeros... from what I've read this is not clear from what's returned and could be done in a better way but is worth creating code to handle ... again, for high precisions uses)

    Thanks for the headsup Sz. (see comments).

    0 讨论(0)
  • 2020-12-05 10:32

    since I resolved my issue i want to share it with You. Php71+ have microsecconds accuracy, if You want to convert it into nano accuracy just multiply it by 1000 (10^3).

    $nsTimestamp = (int) (new \DateTime())->getTimestamp() * 1000
    
    0 讨论(0)
  • 2020-12-05 10:33
    /*
     * 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;
      }
    
    0 讨论(0)
  • 2020-12-05 10:33

    I'm a little late with this, but I had to develop a solution that works for PHP 5, PHP 7.0, and PHP 7.1+.

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

    This gives you a valid UTC timestring with microseconds. If you need still need it as a DateTime object, you can just pass this string directly:

    $dt = new DateTime($z);
    

    This works from PHP 5.2 if you need the DateTime, but if you just need the string with microseconds it's good all the way back to PHP 4.

    0 讨论(0)
  • 2020-12-05 10:34

    /!\ EDIT /!\

    I now use https://github.com/briannesbitt/Carbon, the rest of this answer is just here for historical reasons.

    END EDIT

    I decided to extend the class DateTime using the tips you all gave me.

    The constructor takes a float (from microtime) or nothing (in this case it will be initialized with the current "micro-timestamp"). I also overrided 2 functions that were important : setTimestamp and getTimestamp.

    Unfortunately, I couldn't solve the performances issue, although it's not as slow as I thought.

    Here's the whole class :

    <?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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题