Streamline comparison methods that compare something other then the current type
Closed this issue · 5 comments
At the moment there is a isDateAfterInTimeZone
in DateTime
. To be streamlined it would need to exist for month, year and time as well. With all permutations. And it only works with a parameter of DateTime
. Perhaps it should support DateTime
, Time
, Date
, Month
and Year
as parameter. But not as separate methods, but as union types.
I really need to rethink this whole topic. Last thoughts:
*InTimeZone
methods only make sense for Moment, as it's the only one including a timeZone.
After more inspection I think I know what the problem is: I've stored a lot of data as moments, when they are specific dates in a relevant timezone and therefore have to handle comparisons on a date level of two moments.
The correct approach would be to store the date time in a precision relevant to the use case and then compare it with a moment. This way there is no need to have a isDateAfterInTimeZone
on the moment that also takes another moment as a parameter any more. Not to mention that it would need to be called isDateInTimeZoneAfter
as a date only always exists in a time zone.
This would then mean all precision value objects like Time
, Date
, Month
and Year
need the following methods:
isEqualTo
andisNotEqualTo
isAfter
andisNotAfter
isBefore
andisNotBefore
isBeforeOrEqualTo
andisNotBeforeOrEqualTo
isAfterOrEqualTo
andisNotAfterOrEqualTo
The moment class would then contain all those (10) methods x all combinations with all precision value objects (4) (always with InTimeZone
). But only with the precision value objects as parameters and never with a moment as parameter (as they are currently). In total 50 comparison methods.
Which means I also need to adapt the docs to reflect the (now more obvious) value of the bundle:
- Have more precise value objects to work with and store parts of a moment.
- Have more readable comparisons. Like instead of
!($time->setTimeZone($companyTimeZone) <= $commandExecutedAt)
have$commandExecutedAt->isTimeInTimeZoneNotAfterOrEqualTo($time)
. Need better example then that. - Explain why precise value objects should be stored instead of moments.
Or even better: Take inspiration from moment.js where there's a isBefore
that has a granularity parameter. Which we could skip and simply do the comparison depending on the parameter given.
This could even be extended with a granularity parameter to do an automatic conversion.
In comparison to moment.js we've got the advantage that we have type safety one runtime, so we could do something like this
/**
* @param Moment|Time|Date|Month|Year $before Comparison is done depending on the class of the passed object (converted with the $timeZone)
* @param \DateTimeZone|null $timeZone needs to be supplied when something other than a Moment is passed, null otherwise
*/
public function isBefore(
Moment | Time | Date | Month | Year $before,
?\DateTimeZone $timeZone = null,
): bool {
if ($before instanceof Moment
&& $timeZone !== null
) {
// TODO: Throw custom exception
throw new \InvalidArgumentException('Shit');
}
if (!$before instanceof Moment
&& $timeZone === null
) {
// TODO: Throw custom exception
throw new \InvalidArgumentException('Shit');
}
return match (true) {
$before instanceof Moment => $this->dateTime < $before->dateTime,
$before instanceof Time => $this->timeInTimeZone($timeZone)->isBefore($before),
$before instanceof Date => $this->dateInTimeZone($timeZone)->isBefore($before),
$before instanceof Month => $this->monthInTimeZone($timeZone)->isBefore($before),
$before instanceof Year => $this->yearInTimeZone($timeZone)->isBefore($before),
};
}
Resolved with #40