web-dev-qa-db-fra.com

DateTime avec microsecondes

Dans mon code, j'utilise des objets DateTime pour manipuler les dates, puis les convertis en horodatage afin de les enregistrer dans des fichiers JSON.

Pour certaines raisons, je souhaite avoir la même chose que DateTime (ou quelque chose de proche), mais avec une précision de l'ordre de la microseconde (que je convertirais en float lors de l'insertion dans les fichiers JSON).

Ma question est la suivante: existe-t-il un objet PHP semblable à DateTime, mais qui peut également traiter microsecondes?

Le but est de pouvoir manipuler des microtimes avec des objets.

Dans le date () documentation, quelque chose indique que DateTime peut être créé avec des microsecondes, mais je n'ai pas pu trouver comment.

u Microsecondes (ajouté dans PHP 5.2.2). Notez que la date () sera toujours générer 000000 puisqu'il prend un paramètre entier, alors que DateTime :: format () prend en charge les microsecondes si DateTime a été créé avec des microsecondes.

J'ai essayé de définir l'horodatage d'un objet DateTime avec une valeur flottante (microtime(true)), mais cela ne fonctionne pas (je pense qu'il convertit l'horodatage en int, ce qui entraîne la perte de la microseconde).

Voici comment j'ai essayé

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

Le .4 n'est pas pris en compte comme vous pouvez le voir ici (même si nous pouvons utiliser le format u, qui correspond aux microsecondes).

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)

EDIT: J'ai vu ce code, qui permet d'ajouter des microsecondes à un DateTime, mais j'aurais besoin d'appliquer de nombreuses modifications au microtime avant de créer le DateTime. Etant donné que je vais beaucoup l’utiliser, je souhaite apporter le moins de modifications possible au microtime avant d’obtenir "l’objet microtime".

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

/!\ MODIFIER /!\

J'utilise maintenant https://github.com/briannesbitt/Carbon , le reste de cette réponse n’est là que pour des raisons historiques.

FIN ÉDITER

J'ai décidé d'étendre la classe DateTime en utilisant les conseils que vous m'avez tous donnés.

Le constructeur prend un float (de microtime) ou rien (dans ce cas, il sera initialisé avec le "micro-timestamp" actuel) . J'ai également remplacé 2 fonctions importantes: setTimestamp et getTimestamp.

Malheureusement, je n'ai pas pu résoudre le problème de performances, même si ce n'est pas aussi lent que je le pensais.

Voici toute la classe:

<?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;
    }
}
4
Heru-Luin

Voici une méthode très simple pour créer un objet DateTime incluant microtime.

Je n'ai pas trop approfondi cette question, alors si je rate quelque chose, je m'en excuse, mais j'espère que vous trouverez cela utile.

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

Je l'ai testé et essayé différentes façons de rendre ce travail qui semblait logique mais c'était la seule méthode qui fonctionnait ..__ Cependant, il y avait un problème, il retournait la bonne heure mais pas la bonne journée (à cause de Le temps UTC le plus probable) Voici ce que j'ai fait (semble encore plus simple 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'));

Voici un exemple de travail: http://sandbox.onlinephpfunctions.com/code/66f20107d4adf87c90b5c8c914393d4edef180a2

METTRE &AGRAVE; JOUR
Comme indiqué dans les commentaires, à partir de PHP 7.1, la méthode recommandée par Planplan semble être supérieure à celle présentée ci-dessus.

Donc, encore une fois pour PHP 7.1 et les versions ultérieures, il peut être préférable d’utiliser le code ci-dessous au lieu de celui-ci:

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

Veuillez noter que ce qui précède ne fonctionne que pour les versions de PHP 7.1 et supérieures. Les versions précédentes de PHP renverront des 0 à la place du microtime, perdant ainsi toutes les données microtimes.

Voici un bac à sable mis à jour affichant les deux: http://sandbox.onlinephpfunctions.com/code/a88522835fdad4ae928d023a44b721e392a3295e

REMARQUE: en testant le bac à sable ci-dessus, je n'ai jamais vu l'échec de microtime (TRUE) que Planplan a mentionné qu'il a rencontré. La méthode mise à jour semble toutefois enregistrer un niveau de précision supérieur à celui suggéré par KristopherWindsor.

17
MER

Consultation d'une réponse dans le manuel PHP DateTime :

DateTime ne prend pas en charge les secondes (microsecondes, millisecondes, etc.) Je ne sais pas pourquoi ce n'est pas documenté . Le constructeur de la classe les acceptera sans se plaindre, mais ils seront rejetés . Il ne semble pas y avoir de moyen de prendre une chaîne telle que "2012-07-08 11: 14: 15.638276" et de la stocker sous une forme objective de manière complète.

Donc, vous ne pouvez pas faire de maths sur deux chaînes comme:

<?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
)

*/
?>

Vous obtenez 0 quand vous voulez réellement obtenir 0,251066 secondes.


Cependant, en prenant une réponse de ici :

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

Recommandé et utilise la classe dateTime() à partir de la référence: 

$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).

Référence de dateTime() sur php.net: http://php.net/manual/fr/datetime.construct.php#

5
Ben

Il y a plusieurs options. Mais comme déjà fourni par Ben, je vais essayer de vous donner une autre solution. 

Si vous fournissez plus de détails sur le type de calcul que vous voulez faire, il pourrait être modifié.

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

ou 

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

ou 

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

ou

list($usec, $sec) = explode(' ', microtime());
print date('Y-m-d H:i:s', $sec) . $usec;
2
davejal
/*
 * 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;
  }
1
Valerii

depuis que j'ai résolu mon problème, je souhaite le partager avec vous . Php71 + possède une précision microsecconds, si vous souhaitez le convertir en nano-précision, il vous suffit de le multiplier par 1000 (10 ^ 3).

$nsTimestamp = (int) (new \DateTime())->getTimestamp() * 1000
0
Błażej Krzakala