Oblicz całkowitą liczbę sekund w PHP DateInterval

101

Jaki jest najlepszy sposób obliczenia całkowitej liczby sekund między dwiema datami? Do tej pory próbowałem czegoś w stylu:

$delta   = $date->diff(new DateTime('now'));
$seconds = $delta->days * 60 * 60 * 24;

Jednak dayswłaściwość obiektu DateInterval wydaje się być uszkodzona w bieżącej kompilacji PHP 5.3 (przynajmniej w systemie Windows zawsze zwraca tę samą 6015wartość). Próbowałem również zrobić to w sposób, który nie pozwoliłby zachować liczby dni w każdym miesiącu (rundy do 30), lat przestępnych itp .:

$seconds = ($delta->s)
         + ($delta->i * 60)
         + ($delta->h * 60 * 60)
         + ($delta->d * 60 * 60 * 24)
         + ($delta->m * 60 * 60 * 24 * 30)
         + ($delta->y * 60 * 60 * 24 * 365);

Ale naprawdę nie jestem zadowolony z używania tego niedoścignionego rozwiązania.

efritz
źródło
Jaki jest skutek $delta->format("%r%s")?
warrenm
1
@warrenm Problem formatpolega na tym, że kiedy powiedzmy, że liczba sekund wynosi 0, a liczba minut wynosi 1, $delta->format("%r%s")okazuje się, że wynosi 0 :(
Vadim Samokhin
4
Co gorsza, mówiąc, że ktoś teraz naprawia usterkę wyłapaną podczas przeglądu kodu od programisty, który wkleił Twój DOKŁADNY kod powyżej - nie każdy miesiąc ma 30 dni, a nie każdy rok 365 dni. :) [Edytuj: a tym koderem mogłem być ja!]
taiganaut

Odpowiedzi:

212

Czy nie mógłbyś zamiast tego porównać znaczników czasu ?

$now = new DateTime('now');
$diff = $date->getTimestamp() - $now->getTimestamp()
Ben
źródło
11
Chyba nie RTFM ... To jest to, czego szukałem; wielkie dzięki!
efritz
3
+1: ładnie i czysto! Zauważ, że getTimestamp()metoda jest dostępna w PHP> = 5.3.0.
Sk8erPeter
6
Jeśli utkniesz z PHP 5.2 na swoim kiepskim współdzielonym serwerze hostingowym, użyj format('U')zamiast getTimestamp().
chiborg
4
Twoje rozwiązanie nie jest kompatybilne z błędem z roku 2038
Jack M.
9
@JackM. Dobrze wiedzieć. Mam nadzieję, że to, co jest teraz budowane, nie będzie już działać w 2037 roku. Zapraszam do przedstawienia alternatywnego rozwiązania bezpiecznego dla błędów w roku 2038.
Ben
34

Ta funkcja umożliwia uzyskanie całkowitego czasu trwania w sekundach z obiektu DateInterval

/**
 * @param DateInterval $dateInterval
 * @return int seconds
 */
function dateIntervalToSeconds($dateInterval)
{
    $reference = new DateTimeImmutable;
    $endTime = $reference->add($dateInterval);

    return $endTime->getTimestamp() - $reference->getTimestamp();
}
dave1010
źródło
2
Należy zauważyć, że DateTimeImmutable jest dostępne tylko od PHP 5.5 lub nowszego.
hschmieder
Myślę, że musisz zastąpić zmienne zwracane $endTimei $referencenawzajem, ponieważ daje mi to wynik ujemny z przyszłą wartością daty i godziny w przedziale czasu.
AlexioVay
Nie sądzę, że znacznik czasu jest w sekundach. PHP DateTime = Horrific API
Quadrivium
5

Możesz to zrobić tak:

$currentTime = time();
$timeInPast = strtotime("2009-01-01 00:00:00");

$differenceInSeconds = $currentTime - $timeInPast;

time () zwraca bieżący czas w sekundach od czasu epoki (1970-01-01T00: 00: 00), a strtotime robi to samo, ale na podstawie określonej daty / godziny, którą podasz.

xil3
źródło
4
static function getIntervalUnits($interval, $unit)
{
    // Day
    $total = $interval->format('%a');
    if ($unit == TimeZoneCalc::Days)
        return $total;
    //hour
    $total = ($total * 24) + ($interval->h );
    if ($unit == TimeZoneCalc::Hours)
        return $total;
    //min
    $total = ($total * 60) + ($interval->i );
    if ($unit == TimeZoneCalc::Minutes)
        return $total;  
    //sec
    $total = ($total * 60) + ($interval->s );
    if ($unit == TimeZoneCalc::Seconds)
        return $total;  

    return false;
}
hoofuz
źródło
0

Zawsze jest miło, gdy to, czego potrzebujesz, jest już obecne w klasie. W twoim przypadku potrzebujesz całkowitej liczby sekund. Dlaczego nie zrobić z tego zajęć? Kod mógłby wyglądać tak:

(new TotalFullSeconds(
    new IntervalFromRange(
        new DateTimeFromISO8601String('2017-07-03T14:27:39+00:00'),
        new DateTimeFromISO8601String('2017-07-05T14:27:39+00:00')
    )
))
    ->value()

Oprócz intuicyjności możesz także skorzystać z funkcji autouzupełniania swojego IDE.

Aby uzyskać bardziej przydatną implementację, możesz sprawdzić tę bibliotekę .

Vadim Samokhin
źródło
-8

Możesz po prostu wpisać twarde liczby (zamiast 60 * 60 - wpisz 3600), aby nie musiał ich obliczać za każdym razem.

Edytuj - poprawiono liczbę na podstawie Twojego komentarza.

Duniyadnd
źródło
To byłoby w porządku i prawdopodobnie działałoby o ułamek sekundy szybciej w PHP, ale nadal pozostawia mnie z tym samym błędem w obliczeniach, co w powyższym przykładzie.
efritz