timezone is set on passed object when getting hours for a specific date
ragingdave opened this issue · comments
When calling forDate
on the OpeningHours object, if the hours are in for example America/New_York, but the passed DateTimeInterface is in UTC, the result is that the passed object's timezone is changed unexpectedly. This appears to be in relation to a fix applied in #157 , as the timezone is applied directly to the passed object.
Indeed, my recommendation in the meantime is to always work DateTimeImmutable
instead of DateTime
which is way safer as it avoids this kind of mess by creating copy instead of modifying the current object.
For the record, DateTime
still exist in PHP just for backward compatibility. It is a design mistake, And date and time should always be represented in an immutable way.
Because actually mutable date-time makes no sense, you can't change a date. When $appointment->startDate
changes, it's not semantically correct to say "Monday 8AM NY time becomes something else", no "Monday 8AM NY time" won't change, it's still the same for everybody, only your appointment change, and you actually set startDate to an other value.
$monday8AM = new DateTime('2022-07-25 08:00 America/New_York');
$appointment1->startDate = $monday8AM;
$appointment2->startDate = $monday8AM;
$appointment1->startDate->modify('2022-07-26 10:00 America/New_York');
You can see in this example that using DateTime
does not properly reflect reality and lead to mistake.
Here $monday8AM
get modified and $appointment2->startDate
is affected by changing $appointment1->startDate
.
Also there is no mutation of $appointment1
in the code.
DateTimeImmutable
is a way better way to reflect the reality of date/time manipulation and lead to less mistakes:
$monday8AM = new DateTimeImmutable('2022-07-25 08:00 America/New_York');
$appointment1->startDate = $monday8AM;
$appointment2->startDate = $monday8AM;
$appointment1->startDate = $appointment1->startDate->modify('2022-07-26 10:00 America/New_York');
If we call modify
(or setTimezone
) it returns a new instance.
So here we don't mutate $monday8AM
, $appointment2->startDate
is unaffected and the mutation of $appointment1
becomes explicit.
Of course we should still fix support for DateTime
in spatie/opening-hours