First you need to calculate the total duration in minutes. Then, just see if the duration has passed 30 minutes. If you didn’t pass, the total amount is $30, and if you passed, subtract 30 minutes from the total, and what’s left you multiply by 1.5
:
function toMins($horario) {
list($h, $m) = explode(':', $horario);
return $h * 60 + $m;
}
$entrada = '10:00';
$saida = '10:45';
$minuto_adicional = 1.5;
$total_minutos = toMins($saida) - toMins($entrada);
if ($total_minutos <= 0) {
// só por "garantia", verificar se o valor não deu zero ou negativo
// imprime alguma mensagem de erro, ou não faz nada, vc que sabe
echo "O horário de entrada é maior ou igual ao de saída";
} else {
// se entrou nesse else, é porque ficou pelo menos 1 minuto
// então já paga $30, que é o valor pelos primeiros 30 minutos
$pagar = 30;
if ($total_minutos > 30) { // se passou de 30 minutos, cobrar os minutos excedentes
$pagar += ($total_minutos - 30) * $minuto_adicional;
}
$h = floor($total_minutos / 60);
$m = $total_minutos % 60;
printf("duração: %02d:%02d\nTotal a pagar: R$%s\n", $h, $m, number_format($pagar, 2, ','));
}
I used number_format
to format with two decimal places and comma as decimal separator. The output will be:
duração: 00:45
Total a pagar: R$52,50
Of course, I am assuming that the schedule only has hours and minutes, and that always refer to the same day (there will be, for example, entrance at 23:00 and departure at 02:00 the next day).
It is also worth remembering that number_format
returns a formatted string. Of course, if the string is in the "correct" format, PHP can automatically coerce types, but in general, if it is going to do calculations, prefer not to turn the number into a string.
Another way to get the total minutes is by using DateTime
:
$total_minutos = ((new DateTime($saida))->getTimestamp() - (new DateTime($entrada))->getTimestamp()) / 60;
The rest of the code is equal. But there’s a catch: when the string only has the time, the DateTime
uses the current date and Timezone that is configured in PHP (in your case, you are explicitly setting America/Sao_Paulo
- which corresponds to the Time of Brasilia).
In most cases it is no problem, but if you run on a date when daylight saving time changes, it may give differences. For example, when daylight saving time is over, at midnight the clock is set to 23:00, that is, every minute between 23:00 and 23:59 occurs twice (one in daylight saving time and the other in regular time). If you have an interval of hours between 23:00 and 23:59, you have to know which one you refer to - and in this case only the hour and minute is not enough to make the correct calculation. But maybe I’m running too far from the scope of the question...
Another difference is that the DateTime
error if the time is invalid (for example, if it is 25:00
). Already using the first code, the validation would have to be done manually, something like:
function toMins($horario) {
list($h, $m) = explode(':', $horario);
if ($h < 0 || $h > 24) {
// hora inválida (dar erro, mostrar mensagem, etc)
}
if ($m < 0 || $m > 60) {
// minuto inválido (dar erro, mostrar mensagem, etc)
}
return $h * 60 + $m;
}
Anyway, date/time arithmetic is more complicated than it seems, full of corner cases which may or may not be relevant depending on the context. If your entries are controlled (for example, the input and output are always "hour:minute" of the same day), a simpler approach brings no problems. But if you can have schedules on different days, time zones, invalid entries, etc, then it gets more complicated, requiring additional controls (as it is not clear whether this is the case, I will stick to just mentioning that this kind of thing can happen, and in such cases should be taken into account).
Simply calculate the difference in minutes between the time of entry and the time of departure. Subtract 30 of this value, to discount the initial 30 minutes, adding R$ to the total; the remaining minutes you multiply by 1.5 and sum the result in the total.
– Woss
I couldn’t do this calculation, I’m still learning the language :/
– Jvs Corrêa
As you tried to do?
– Woss
edited as I tried to realize the code
– Jvs Corrêa