Selain jawaban @ fyrye yang sangat membantu, ini adalah solusi yang oke untuk bug yang disebutkan (yang ini ), DatePeriod mengurangi satu jam ketika memasuki musim panas, tetapi tidak menambahkan satu jam ketika meninggalkan musim panas (dan dengan demikian Maret Eropa / Berlin memiliki mengoreksi 743 jam tetapi Oktober memiliki 744, bukan 745 jam):
Menghitung jam dalam sebulan (atau rentang waktu apa pun), dengan mempertimbangkan transisi DST di kedua arah
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
NB Jika Anda memeriksa rentang waktu (lebih lama), yang mengarah ke lebih dari dua transisi tersebut, solusi saya tidak akan menyentuh jam yang dihitung untuk mengurangi potensi efek samping yang lucu. Dalam kasus seperti itu, solusi yang lebih rumit harus diterapkan. Seseorang dapat mengulang semua transisi yang ditemukan dan membandingkan arus dengan yang terakhir dan memeriksa apakah itu satu dengan DST true-> false.
strftime()
dan membagi perbedaan dengan 3600, tetapi apakah itu akan selalu berhasil? Sialan, Waktu Musim Panas!