Ngoài câu trả lời rất hữu ích của @ fyrye, đây là một cách giải quyết ổn thỏa cho lỗi được đề cập (lỗi này ), DatePeriod giảm bớt một giờ khi bước vào mùa hè, nhưng không thêm một giờ khi rời khỏi thời điểm mùa hè (và do đó, tháng 3 của Châu Âu / Berlin có đúng 743 giờ nhưng tháng 10 có 744 thay vì 745 giờ):
Đếm số giờ trong tháng (hoặc bất kỳ khoảng thời gian nào), xem xét chuyển đổi DST theo cả hai hướng
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
Tái bút Nếu bạn kiểm tra khoảng thời gian (dài hơn), dẫn đến nhiều hơn hai lần chuyển đổi đó, thì giải pháp của tôi sẽ không chạm vào số giờ đã tính để giảm khả năng xảy ra các tác dụng phụ buồn cười. Trong những trường hợp như vậy, một giải pháp phức tạp hơn phải được thực hiện. Người ta có thể lặp lại tất cả các chuyển đổi được tìm thấy và so sánh hiện tại với chuyển đổi cuối cùng và kiểm tra xem nó có phải là chuyển tiếp với DST true-> false hay không.
strftime()
và chia sự khác biệt cho 3600, nhưng liệu điều đó có luôn hoạt động không? Chết tiệt, Giờ tiết kiệm ánh sáng ban ngày!