web-dev-qa-db-fra.com

PHP microsecondes DateTime renvoie toujours 0

ce code retourne toujours 0 en PHP 5.2.5 pour les microsecondes:

<?php
$dt = new DateTime();
echo $dt->format("Y-m-d\TH:i:s.u") . "\n";
?>

Production:

[root@www1 ~]$ php date_test.php
2008-10-03T20:31:26.000000
[root@www1 ~]$ php date_test.php
2008-10-03T20:31:27.000000
[root@www1 ~]$ php date_test.php
2008-10-03T20:31:27.000000
[root@www1 ~]$ php date_test.php
2008-10-03T20:31:28.000000

Des idées?

70
eydelber

Cela semble fonctionner, bien qu'il semble illogique que http://us.php.net/date documente le spécificateur de microsecondes mais ne le supporte pas vraiment:

function getTimestamp()
{
        return date("Y-m-d\TH:i:s") . substr((string)microtime(), 1, 8);
}
26
eydelber

Vous pouvez spécifier que votre entrée contient des microsecondes lors de la construction d'un objet DateTime et utiliser microtime(true) directement comme entrée.

Malheureusement, cela échouera si vous atteignez une seconde exacte, car il n'y aura pas de . dans la sortie microtime; utilisez donc sprintf pour le forcer à contenir un .0 dans ce cas:

date_create_from_format(
    'U.u', sprintf('%.f', microtime(true))
)->format('Y-m-d\TH:i:s.uO');

Ou de manière équivalente (plus de style OO)

DateTime::createFromFormat(
    'U.u', sprintf('%.f', microtime(true))
)->format('Y-m-d\TH:i:s.uO');
19
tr0y

Cette fonction est tirée de http://us3.php.net/date

function udate($format, $utimestamp = null)
{
    if (is_null($utimestamp))
        $utimestamp = microtime(true);

    $timestamp = floor($utimestamp);
    $milliseconds = round(($utimestamp - $timestamp) * 1000000);

    return date(preg_replace('`(?<!\\\\)u`', $milliseconds, $format), $timestamp);
}

echo udate('H:i:s.u'); // 19:40:56.78128

Très compliqué, vous devez implémenter cette fonction pour que "u" fonctionne ...: \

17
jmccartie

Essayez ceci et cela montre les micro secondes:

$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");
14
dbwebtek
\DateTime::createFromFormat('U.u', microtime(true));

Vous donnera (au moins sur la plupart des systèmes):

object(DateTime)(
  'date' => '2015-03-09 17:27:39.456200',
  'timezone_type' => 3,
  'timezone' => 'Australia/Darwin'
)

Mais il y a une perte de précision à cause de PHP arrondi flottant. Ce n'est pas vraiment des microsecondes.

Mise à jour

Il s'agit probablement du meilleur compromis des options createFromFormat() et il offre une précision totale.

\DateTime::createFromFormat('0.u00 U', microtime());

gettimeofday ()

Plus explicite et peut-être plus robuste. Résout le bug trouvé par Xavi.

$time = gettimeofday(); 
\DateTime::createFromFormat('U.u', sprintf('%d.%06d', $time['sec'], $time['usec']));
8
Ryan

Bon, j'aimerais clarifier cela une fois pour toutes.

Une explication de la façon d'afficher le ISO 8601 format date et heure en PHP avec milli secondes et micro secondes ...

milli secondes ou 'ms' ont 4 chiffres après la virgule décimale par ex. 0,1234. les micro secondes ou 'µs' ont 7 chiffres après la décimale. Explication des fractions/noms en secondes ici

La fonction date() de PHP ne se comporte pas entièrement comme prévu avec des millisecondes ou des microsecondes car elle ne fera qu'exclure un entier, comme expliqué dans les php date docs sous le caractère de format 'u'.

Basé sur l'idée de commentaire de Lucky ( ici ), mais avec la correction de la syntaxe PHP et la gestion correcte des secondes (Le code de Lucky a ajouté un "0" supplémentaire incorrect après les secondes)

Ceux-ci éliminent également les conditions de course et formate correctement les secondes.

Date PHP avec milli secondes

Équivalent de travail de date('Y-m-d H:i:s').".$milliseconds";

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

Sortie = 2016-07-12 16:27:08.5675

Date PHP avec micro secondes

Équivalent de travail de date('Y-m-d H:i:s').".$microseconds"; ou date('Y-m-d H:i:s.u') si la fonction date s'est comportée comme prévu avec microsecondes/microtime()/'u'

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

Sortie = 2016-07-12 16:27:08.56752900

5
hozza

Cela a fonctionné pour moi et est un simple trois lignes:

function udate($format='Y-m-d H:i:s.', $microtime=NULL) {
    if(NULL === $microtime) $microtime = microtime();
    list($microseconds,$unix_time) = explode(' ', $microtime);
    return date($format,$unix_time) . array_pop(explode('.',$microseconds));
}

Par défaut (aucun paramètre fourni), cela retournera une chaîne dans ce format pour la microseconde actuelle, elle a été appelée:

AAAA-MM-JJ HH: MM: SS.UUUUUUUU

Un modèle encore plus simple/plus rapide (quoique avec seulement la moitié de la précision) serait le suivant:

function udate($format='Y-m-d H:i:s.', $microtime=NULL) {
    if(NULL === $microtime) $microtime = microtime(true);
    list($unix_time,$microseconds) = explode('.', $microtime);
    return date($format,$unix_time) . $microseconds;
}

Celui-ci s'imprimerait dans le format suivant:

AAAA-MM-JJ HH: MM: SS.UUUU

4
KyleFarris

Que dis-tu de ça?

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

exemple de sortie

2013-07-17 08: 23: 37: 0.88862400

1
Nadeem

date_create

time: String dans un format accepté par strtotime (), par défaut "now".

strtotime

time: la chaîne à analyser, selon la syntaxe GNU "Date Input Formats. Avant PHP 5.0.0, les microsecondes n'étaient pas autorisées dans le temps, depuis PHP 5.0.0 ils sont autorisés mais ignorés.

1
scronide

En travaillant à partir de Luckycomment et ceci demande de fonctionnalité dans la base de données PHP bug , j'utilise quelque chose comme cette:

class ExtendedDateTime extends DateTime {
    /**
     * Returns new DateTime object.  Adds microtime for "now" dates
     * @param string $sTime
     * @param DateTimeZone $oTimeZone 
     */
    public function __construct($sTime = 'now', DateTimeZone $oTimeZone = NULL) {
        // check that constructor is called as current date/time
        if (strtotime($sTime) == time()) {
            $aMicrotime = explode(' ', microtime());
            $sTime = date('Y-m-d H:i:s.' . $aMicrotime[0] * 1000000, $aMicrotime[1]);
        }

        // DateTime throws an Exception with a null TimeZone
        if ($oTimeZone instanceof DateTimeZone) {
            parent::__construct($sTime, $oTimeZone);
        } else {
            parent::__construct($sTime);
        }
    }
}

$oDate = new ExtendedDateTime();
echo $oDate->format('Y-m-d G:i:s.u');

Production:

2010-12-01 18:12:10.146625
1
enobrev

Cela devrait être le plus flexible et le plus précis:

function udate($format, $timestamp=null) {
    if (!isset($timestamp)) $timestamp = microtime();
    // microtime(true)
    if (count($t = explode(" ", $timestamp)) == 1) {
        list($timestamp, $usec) = explode(".", $timestamp);
        $usec = "." . $usec;
    }
    // microtime (much more precise)
    else {
        $usec = $t[0];
        $timestamp = $t[1];
    }
    // 7 decimal places for "u" is maximum
    $date = new DateTime(date('Y-m-d H:i:s' . substr(sprintf('%.7f', $usec), 1), $timestamp));
    return $date->format($format);
}
echo udate("Y-m-d\TH:i:s.u") . "\n";
echo udate("Y-m-d\TH:i:s.u", microtime(true)) . "\n";
echo udate("Y-m-d\TH:i:s.u", microtime()) . "\n";
/* returns:
2015-02-14T14:10:30.472647
2015-02-14T14:10:30.472700
2015-02-14T14:10:30.472749
*/
1
mgutt

Certaines réponses utilisent plusieurs horodatages, ce qui est conceptuellement incorrect, et des problèmes de chevauchement peuvent survenir: des secondes de 21:15:05.999 Combinées par des microsecondes de 21:15:06.000 Donnent 21:15:05.000.

Apparemment, le plus simple est d'utiliser DateTime::createFromFormat() avec U.u, Mais comme indiqué dans un commentaire , il échoue s'il n'y a pas de microsecondes.

Donc, je suggère ce code:

function udate($format, $time = null) {

    if (!$time) {
        $time = microtime(true);
    }

    // Avoid missing dot on full seconds: (string)42 and (string)42.000000 give '42'
    $time = number_format($time, 6, '.', '');

    return DateTime::createFromFormat('U.u', $time)->format($format);
}
0
Gras Double

Chaîne dans un format accepté par strtotime () Ça marche!

0
hosting

Dans une application que j'écris, j'ai besoin de définir/afficher le microtime sur les objets DateTime. Il semble que le seul moyen pour que l'objet DateTime reconnaisse les microsecondes est de l'initialiser avec l'heure au format "AAAA-MM-JJ HH: MM: SS.uuuuuu". L'espace entre les parties de date et d'heure peut également être un "T" comme c'est généralement le cas au format ISO8601.

La fonction suivante renvoie un objet DateTime initialisé dans le fuseau horaire local (le code peut bien sûr être modifié selon les besoins pour répondre aux besoins individuels):

// Return DateTime object including microtime for "now"
function dto_now()
{
    list($usec, $sec) = explode(' ', microtime());
    $usec = substr($usec, 2, 6);
    $datetime_now = date('Y-m-d H:i:s\.', $sec).$usec;
    return new DateTime($datetime_now, new DateTimeZone(date_default_timezone_get()));
}
0
crashmaxed

La documentation PHP dit clairement " Notez que date () générera toujours 000000 car elle prend un paramètre entier ...". Si vous souhaitez un remplacement rapide de la fonction date() utilisez la fonction ci-dessous:

function date_with_micro($format, $timestamp = null) {
    if (is_null($timestamp) || $timestamp === false) {
        $timestamp = microtime(true);
    }
    $timestamp_int = (int) floor($timestamp);
    $microseconds = (int) round(($timestamp - floor($timestamp)) * 1000000.0, 0);
    $format_with_micro = str_replace("u", $microseconds, $format);
    return date($format_with_micro, $timestamp_int);
}

(disponible sous Gist ici: date_with_micro.php )

0
Manu Manjunath

Sur la base du commentaire de Lucky, j'ai écrit un moyen simple de stocker des messages sur le serveur. Dans le passé, j'ai utilisé des hachages et des incréments pour obtenir des noms de fichiers uniques, mais la date avec des micro-secondes fonctionne bien pour cette application.

// Create a unique message ID using the time and microseconds
    list($usec, $sec) = explode(" ", microtime());
    $messageID = date("Y-m-d H:i:s ", $sec) . substr($usec, 2, 8);
    $fname = "./Messages/$messageID";

    $fp = fopen($fname, 'w');

Voici le nom du fichier de sortie:

2015-05-07 12:03:17 65468400
0
JScarry