Я создаю расписание, в котором отображаются ожидаемые и фактические часы.
Продолжительность сохраняется, как показано ниже.
23:15 - 23 часа 15 минут
25:45 - 25 часов 45 минут
Мне нужно определить разницу в часах и минутах между ними (дополнительные часы работы)
Я пробовал следующее
$acutal=='23:15';
$expected=='25:45';
$start_time = new DateTime("1970-01-01 $acutal:00");
$time = $start_date->diff(new DateTime("1970-01-01 $expected:00"));
Это работает, однако, когда часы превышают 24:00, выдает ошибку (очевидно, потому что он считывает его как время)
Uncaught exception 'Exception' with message 'DateTime::__construct(): Failed to parse time string (1970-01-01 25:45:00)
Есть другой способ сделать это?
@CollinD - не могли бы вы привести пример?






Вы можете проверить, превышает ли количество часов 24, и если да, добавить день и удалить 24 часа.
$actual='23:15';
$expected='25:45';
$day = 1;
list($hrs, $min) = explode(':', $expected);
if ($hrs > 24) { $day += 1; $hrs -= 24; }
$start_time = new DateTime("1970-01-01 $actual:00");
$time = $start_time->diff(new DateTime("1970-01-$day $hrs:$min:00"));
echo $time->format('%hh %Im');
Выход:
2h 30m
Также обратите внимание, что == используется для сравнения, а не для назначения.
Вы также можете заменить if ($hrs > 24) на while(), если осталось 48 часов или больше.
редактировать
Как указывает @CollinD, если время превышает количество дней в месяце, он завершится ошибкой. Вот еще одно решение:
$actual='23:15';
$expected='25:45';
list($hrs, $min) = explode(':', $actual);
$total1 = $min + $hrs * 60;
list($hrs, $min) = explode(':', $expected);
$diff = $min + $hrs * 60 - $total1;
$start_time = new DateTime();
$expected_time = new DateTime();
$expected_time->modify("+ $diff minutes");
$time = $start_time->diff($expected_time);
echo $time->format('%hh %Im');
В качестве предупреждения я подозреваю, что это столкнется с той же проблемой, что и раньше, если ваша продолжительность превысит количество часов в январе 1970 года.
Вы правы, @CollinD, спасибо. Я обновил ответ на новый способ сделать это.
Если вы уже конвертируете все в минуты, кажется, что лучше всего просто устранить сложность, добавленную с помощью DateTime все вместе. Длительности на самом деле являются просто скалярами с размерным временем, поэтому добавление временного контекста вызывает только странные проблемы с крайним случаем, imo.
Спасибо за интересный комментарий @CollinD. (Я немного изменил код). Объект DateInterval позволяет форматировать, и я использовал это для сопоставления с исходным кодом OP.
@Syscall - ваше обновление возвращает 0h 00m при использовании этих переменных $actual='34:50'; $expected='22:00';
@Shane: См. 3v4l.org/Qev4c: $expected_time->modify(($diff < 0 ? '' : '+') . "$diff minutes"); или используйте abs($diff), или проверьте, не превышает ли значение $ actual, чем ожидалось, и инвертируйте их. Это произошло потому, что строка в modify() была "+ -770 minutes".
Вы можете попробовать использовать функции datetime, но мне кажется более простым рассматривать время как строку, использовать split или explode, чтобы получить часы и минуты, преобразовать в целые числа, получить разницу в минутах и преобразовать обратно в часы и минуты ( целое деление на 60 и остаток).
$t1=explode(':',$expected);
$t2=explode(':',$actual);
$d=60*($t1[0]-$t2[0])+t1[1]-t2[1];
$result=str_pad(floor($d/60),2,'0',STR_PAD_LEFT).':'.str_pad($d%60,2,'0',STR_PAD_LEFT);
Вы можете сделать это вручную, отслеживая количество отработанных минут - это будет точно, а также позволит вам показать отрицательные различия.
<?php
// get the difference in H:mm between two H:mm
function diff_time($actual, $expected) {
$diff_mins = mins($actual) - mins($expected);
return format_mins($diff_mins);
}
// convert a HH:mm to number of minutes
function mins($t) {
$parts = explode(':', $t);
return $parts[0] * 60 + $parts[1];
}
// convert number of minutes into HH:mm
function format_mins($m) {
$mins = $m % 60;
$hours = ($m - $mins) / 60;
// format HH:mm
return $hours . ':' . sprintf('%02d', abs($mins));
}
var_dump(diff_time('23:15', '25:45'));
var_dump(diff_time('25:15', '23:45'));
Это выводит:
string(5) "-2:30"
string(4) "1:30"
.. во-первых, на 2:30 меньше ожидаемого, для второго на 1:30 больше, чем ожидалось.
Если вас не интересуют часовые пояса и тому подобное, вероятно, проще всего просто преобразовать в минуты, вычесть и преобразовать обратно. Не нужно добавлять сложность создания реальных объектов стиля DateTime.