Zusätzlich zu der sehr hilfreichen Antwort von @ fyrye ist dies eine gute Lösung für den erwähnten Fehler ( dieser) ), bei dem DatePeriod beim Eintritt in die Sommerzeit eine Stunde abzieht, beim Verlassen der Sommerzeit jedoch keine Stunde hinzufügt (und somit der März in Europa / Berlin seinen hat korrekte 743 Stunden, aber der Oktober hat 744 statt 745 Stunden):
Zählen der Stunden eines Monats (oder einer beliebigen Zeitspanne) unter Berücksichtigung der Sommerzeitübergänge in beide Richtungen
function getMonthHours(string $year, string $month, \DateTimeZone $timezone): int
{
// or whatever start and end \DateTimeInterface objects you like
$start = new \DateTimeImmutable($year . '-' . $month . '-01 00:00:00', $timezone);
$end = new \DateTimeImmutable((new \DateTimeImmutable($year . '-' . $month . '-01 23:59:59', $timezone))->format('Y-m-t H:i:s'), $timezone);
// count the hours just utilizing \DatePeriod, \DateInterval and iterator_count, hell yeah!
$hours = iterator_count(new \DatePeriod($start, new \DateInterval('PT1H'), $end));
// find transitions and check, if there is one that leads to a positive offset
// that isn't added by \DatePeriod
// this is the workaround for https://bugs.php.net/bug.php?id=75685
$transitions = $timezone->getTransitions((int)$start->format('U'), (int)$end->format('U'));
if (2 === count($transitions) && $transitions[0]['offset'] - $transitions[1]['offset'] > 0) {
$hours += (round(($transitions[0]['offset'] - $transitions[1]['offset'])/3600));
}
return $hours;
}
$myTimezoneWithDST = new \DateTimeZone('Europe/Berlin');
var_dump(getMonthHours('2020', '01', $myTimezoneWithDST)); // 744
var_dump(getMonthHours('2020', '03', $myTimezoneWithDST)); // 743
var_dump(getMonthHours('2020', '10', $myTimezoneWithDST)); // 745, finally!
$myTimezoneWithoutDST = new \DateTimeZone('UTC');
var_dump(getMonthHours('2020', '01', $myTimezoneWithoutDST)); // 744
var_dump(getMonthHours('2020', '03', $myTimezoneWithoutDST)); // 744
var_dump(getMonthHours('2020', '10', $myTimezoneWithoutDST)); // 744
PS Wenn Sie eine (längere) Zeitspanne überprüfen, die zu mehr als diesen beiden Übergängen führt, berührt meine Problemumgehung die gezählten Stunden nicht, um das Potenzial für lustige Nebenwirkungen zu verringern. In solchen Fällen muss eine kompliziertere Lösung implementiert werden. Man könnte alle gefundenen Übergänge durchlaufen und den Strom mit dem letzten vergleichen und prüfen, ob es einer mit DST true-> false ist.
strftime()
und die Differenz durch 3600 zu teilen. Aber wird das immer funktionieren? Verdammt, Sommerzeit!