Skip to content

Instantly share code, notes, and snippets.

@Cartman34
Last active April 21, 2021 13:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Cartman34/b2a7e0e08b674b71a458c9a85a810855 to your computer and use it in GitHub Desktop.
Save Cartman34/b2a7e0e08b674b71a458c9a85a810855 to your computer and use it in GitHub Desktop.
CalendarHelper to calculate absolute interval between two dates
<?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