2015-11-13 13 views
12

W moim kodzie używam obiektów DateTime do manipulowania datami, a następnie konwertowania ich na znaczniki czasu w celu ich zapisania w niektórych plikach JSON.DateTime z mikrosekundami

Z pewnych powodów chcę mieć to samo co DateTime (lub coś bliskiego), ale z dokładnością mikrosekund (które konwertowałem by unosić podczas wstawiania wewnątrz plików JSON).

Moje pytanie brzmi: czy istnieje obiekt PHP że jest jak DateTime, ale może obsłużyć mikrosekund też?

Celem jest umożliwienie manipulowania mikrotimes z obiektami.

W dokumentacji date() jest coś, co wskazuje, że DateTime można utworzyć z mikrosekund, ale nie byłem w stanie znaleźć.

u Microseconds (dodane w PHP 5.2.2). Zauważ, że date() zawsze będzie generować 000000, ponieważ pobiera parametr integer, natomiast DateTime :: format() obsługuje mikrosekundy, jeśli DateTime został utworzony z mikrosekundami.

Próbowałem ustawić znacznik czasu DateTime obiektu o wartości pływającego (microtime(true)), ale to nie działa (myślę, że konwertuje znacznik czasu do int, powodując utratę mikrosekund).

Oto jak próbowałem

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

The .4 nie jest brane pod uwagę, jak można zobaczyć tutaj (chociaż możemy użyć formatu na u, która odpowiada mikrosekund).

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: Widziałem ten kod, który pozwala na dodanie mikrosekund do DateTime, ale muszę zastosować wiele modyfikacji microtime przed utworzeniem DateTime. Ponieważ wykorzystam to dużo, chcę zrobić jak najmniej zmian w mikrotime, zanim otrzymam "obiekt mikrotomowy".

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

Twoje pytanie właśnie stało się vaque, czego szukasz? – davejal

+0

Szukam skutecznego sposobu przechowywania dat za pomocą mikrosekund, z tymi samymi możliwościami (porównywanie, formatowanie itp.) Jako DateTime. –

+0

zapisz je w db Zakładam, który? – davejal

Odpowiedz

2

postanowiłem rozszerzyć klasę DateTime użyciu wskazówek wszyscy mi dałeś.

Konstruktor przyjmuje wartość zmiennoprzecinkową (od microtime) lub nic (w tym przypadku zostanie zainicjowany przy użyciu bieżącego "mikroprogramu"). Nadpisałem także dwie funkcje, które były ważne: setTimestamp i getTimestamp.

Niestety, nie udało mi się rozwiązać problemu z występami, chociaż nie jest tak powolny, jak myślałem.

Oto cała klasa:

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

Looking at a response on the PHP DateTime manual:

DateTime nie obsługuje ułamku sekundy (mikrosekundy lub milisekund etc.) nie wiem dlaczego nie jest to udokumentowane. Konstruktor klasy zaakceptuje je bez reklamacji, ale zostaną one odrzucone. Wygląda na to, że nie ma sposobu, aby napisać tekst "2012-07-08 11: 14: 15.638276" i zapisać go w formie obiektywnej w sposób kompletny.

Więc nie można zrobić datę matematyki na dwa ciągi takie jak:

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

*/ 
?> 

Wracasz 0, gdy rzeczywiście chcesz dostać 0.251066 sekund.


Biorąc jednak odpowiedź od 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>"; 

Zalecane i używać dateTime() klasę z odwoływać:

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

referencyjny dateTime() na php.net: http://php.net/manual/en/datetime.construct.php#

+0

Dzięki temu rozwiązaniu nie mogę porównywać mikrotimes z łatwością, a tworzenie obiektu DateTime z mikrotime zabiera dużo zasobów (zamierzam użyć go dużo). –

1

Istnieje wiele opcji. Ale jak już dostarczył Ben, spróbuję dać ci inne rozwiązanie.

Jeśli podałeś więcej szczegółów na temat tego, jakie obliczenia chcesz wykonać, możesz je zmienić.

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

lub

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

lub

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

lub

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

Oto bardzo prosty sposób tworzenia obiektu DateTime, który zawiera microtime.

Nie zagłębiałem się w to pytanie zbyt głęboko, więc jeśli coś przeoczyłem, przepraszam, ale mam nadzieję, że uznasz to za pomocne.

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

Przetestowałem to i próbowałem różnych innych sposobów, aby ta praca wydawała się logiczna, ale była to jedyna metoda, która działała. Jednak nie był to problem, to wracał właściwą część czasu, ale nie poprawny część dni (ze względu na czas UTC najprawdopodobniej) oto co zrobiłem (wciąż wydaje się prostsze 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')); 

Oto robocza przykład: http://sandbox.onlinephpfunctions.com/code/66f20107d4adf87c90b5c8c914393d4edef180a2

+1

W rzadkich przypadkach mikrotime (true) może zwracać zmienną float z tylko częścią całkowitą, co powoduje, że format "U.u" nie działa. To jest trochę brzydkie, ale to zawsze będzie działać z DateTime :: createFromFormat ("0.u00 U", microtime()); – Planplan

+0

@ Plan Planowy Warto wiedzieć. Myślę jednak, że utrata danych z mikrosekundami wydaje się sprzeczna z tym, o co prosił OP ...? Podejrzewam więc, że złapałem to jako błąd, a następnie zrobienie tego w sposób, w jaki mówisz, byłoby prawdopodobnie najlepszym rozwiązaniem. – MER

0
/* 
* 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; 
    }