Last active
April 21, 2021 13:50
-
-
Save Cartman34/b2a7e0e08b674b71a458c9a85a810855 to your computer and use it in GitHub Desktop.
CalendarHelper to calculate absolute interval between two dates
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @author Florent HAZARD <f.hazard@sowapps.com> | |
* @license https://opensource.org/licenses/MIT | |
*/ | |
use DateInterval; | |
use DateTime; | |
use DateTimeImmutable; | |
use DateTimeInterface; | |
/** | |
* Class CalendarHelper | |
* This class is a helper calendar manipulation | |
* Very useful to get absolute interval between two dates using specific units | |
* | |
* @package App\Core\Calendar | |
* @see https://www.php.net/manual/fr/class.dateinterval.php | |
*/ | |
class CalendarHelper { | |
const UNIT_YEAR = 'y'; | |
const UNIT_MONTH = 'm'; | |
const UNIT_DAY = 'd'; | |
const UNIT_HOUR = 'h'; | |
const UNIT_MINUTE = 'i'; | |
const UNIT_SECOND = 's'; | |
const UNIT_MICROSECOND = 'f'; | |
/** | |
* List of all units in order from tallest to smallest | |
*/ | |
const UNITS = [ | |
// UNIT => X child units | |
// X string get property's value in interval | |
// X null stops process | |
self::UNIT_YEAR => 12, | |
self::UNIT_MONTH => 'days', | |
self::UNIT_DAY => 24, | |
self::UNIT_HOUR => 60, | |
self::UNIT_MINUTE => 60, | |
self::UNIT_SECOND => 1,// MS are a fraction of seconds, so MS are in seconds | |
self::UNIT_MICROSECOND => null, | |
]; | |
/** | |
* Get absolute interval between two date specifying the units to use. | |
* Example: Get only hours and minutes between $date1 and date2 | |
* <code><?php $calendarHelper->getAbsoluteInterval($date1, $date2, [CalendarHelper::UNIT_HOUR, CalendarHelper::UNIT_MINUTE]) ?></code> | |
* | |
* @param $date1 | |
* @param $date2 | |
* @param array $units | |
* @return DateInterval | |
* @see convertToAbsolute | |
*/ | |
public function getAbsoluteInterval($date1, $date2, array $units): DateInterval { | |
$date1 = $this->formatToDatetime($date1); | |
$date2 = $this->formatToDatetime($date2); | |
return $this->convertToAbsolute(date_diff($date1, $date2), $units); | |
} | |
/** | |
* @param DateTimeInterface|string|int $date | |
* @return DateTime | |
*/ | |
public function formatToDatetime($date): DateTime { | |
if( $date instanceof DateTime ) { | |
return $date; | |
} | |
if( $date instanceof DateTimeImmutable ) { | |
return DateTime::createFromImmutable($date); | |
} | |
if( is_string($date) ) { | |
return new DateTime($date); | |
} | |
// int | |
return new DateTime('@' . $date); | |
} | |
/** | |
* Get absolute interval from any interval | |
* | |
* @param DateInterval $interval | |
* @param array $units | |
* @return DateInterval | |
*/ | |
public function convertToAbsolute(DateInterval $interval, array $units): DateInterval { | |
$absInterval = new DateInterval('PT0S'); | |
$absInterval->invert = $interval->invert; | |
$parentCounter = 0; | |
$abs = false; | |
foreach( self::UNITS as $unit => $childCount ) { | |
$unitValue = $parentCounter + ($abs ? 0 : $interval->$unit); | |
if( in_array($unit, $units) ) { | |
// Consume inheritance | |
$absInterval->$unit = $unitValue; | |
$parentCounter = 0; | |
$abs = false; | |
} elseif( $childCount !== null ) { | |
// Transmit inheritance | |
$abs = is_string($childCount); | |
$parentCounter = $abs ? ($interval->$childCount ?: 0) : $unitValue * $childCount; | |
} | |
} | |
return $absInterval; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment