182 lines
5.3 KiB
PHP
182 lines
5.3 KiB
PHP
<?php
|
|
|
|
namespace KupShop\KupShopBundle\Util;
|
|
|
|
use Yasumi\ProviderInterface;
|
|
use Yasumi\Yasumi;
|
|
|
|
class DateUtil
|
|
{
|
|
public static function calcWorkingDaysWithHours($days, $hours, $seconds, $fromDay = null, $workdayFunction = null)
|
|
{
|
|
$secondsTotal = $days * 24 * 60 + $hours * 60 + $seconds;
|
|
|
|
$days = $secondsTotal > 0 ? floor($secondsTotal / 24 / 60) : ceil($secondsTotal / 24 / 60);
|
|
|
|
$seconds = $secondsTotal - $days * 24 * 60;
|
|
|
|
$fromDay = self::calcWorkingDays($days, $fromDay, $workdayFunction);
|
|
|
|
if (!$seconds) {
|
|
return $fromDay;
|
|
}
|
|
|
|
$timeDiff = new \DateInterval('PT'.abs($seconds).'M');
|
|
$timeDiff->invert = $seconds < 0;
|
|
$fromDay->add($timeDiff);
|
|
|
|
if (!is_callable($workdayFunction)) {
|
|
$workdayFunction = [self::class, 'isWorkday'];
|
|
}
|
|
|
|
$timeDiffDay = new \DateInterval('P1D');
|
|
$timeDiffDay->invert = $seconds < 0;
|
|
|
|
$i = 0;
|
|
while (!$workdayFunction($fromDay)) {
|
|
if ($i++ > 20) {
|
|
getRaven()->captureMessage('Calculate working days from minutes error');
|
|
break;
|
|
}
|
|
$fromDay->add($timeDiffDay);
|
|
}
|
|
|
|
return $fromDay;
|
|
}
|
|
|
|
/**
|
|
* @param null $fromDay
|
|
* @param null $workdayFunction
|
|
*
|
|
* @return \DateTime|null
|
|
*
|
|
* @throws \ReflectionException
|
|
*/
|
|
public static function calcWorkingDays($days, $fromDay = null, $workdayFunction = null, ?array $countries = null)
|
|
{
|
|
if (empty($fromDay)) {
|
|
$fromDay = new \DateTime();
|
|
}
|
|
|
|
if ($days > 20) {
|
|
// if more than 20 days, don't calculate working days, just add days
|
|
// see https://sentry.wpj.cz/organizations/wpj/issues/467352/ - Calculate working days error, 101 loops reached
|
|
$fromDay->add(new \DateInterval('P'.abs($days).'D'));
|
|
|
|
return $fromDay;
|
|
}
|
|
|
|
$dayDiff = new \DateInterval('P1D');
|
|
if ($days < 0) {
|
|
$dayDiff->invert = 1;
|
|
}
|
|
$days = abs($days);
|
|
|
|
if (!is_callable($workdayFunction)) {
|
|
$workdayFunction = [self::class, 'isWorkday'];
|
|
}
|
|
|
|
$i = 0;
|
|
while ($days > 0) {
|
|
if ($i++ > 100) {
|
|
getRaven()->captureMessage('Calculate working days error, 101 loops reached');
|
|
break;
|
|
}
|
|
$fromDay->add($dayDiff);
|
|
if ($workdayFunction($fromDay, $countries)) {
|
|
$days--;
|
|
}
|
|
}
|
|
|
|
return $fromDay;
|
|
}
|
|
|
|
/**
|
|
* @param $date \DateTime
|
|
*
|
|
* @return bool
|
|
*
|
|
* @throws \ReflectionException
|
|
*/
|
|
public static function isWorkday($date, ?array $countries = null)
|
|
{
|
|
if (empty($countries)) {
|
|
$countries = ['CZ'];
|
|
}
|
|
|
|
$result = true;
|
|
|
|
foreach ($countries as $country) {
|
|
$result = $result && static::createHolidays($country, (int) $date->format('Y'))->isWorkingDay($date);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
public static function compareTimes($first, $second = null): bool
|
|
{
|
|
$first = new \DateTime('2000-01-01 '.$first);
|
|
|
|
if (!$second) {
|
|
$second = date('H:i:s');
|
|
}
|
|
$second = new \DateTime('2000-01-01 '.$second);
|
|
|
|
return $first < $second;
|
|
}
|
|
|
|
public static function isOpen(array $opening_hours, $dayOfWeek = null, $compareTime = null): array
|
|
{
|
|
if ($dayOfWeek === null) {
|
|
$dayOfWeek = (new \DateTime())->format('N');
|
|
}
|
|
if ($compareTime === null) {
|
|
$compareTime = date('H:i:s');
|
|
}
|
|
|
|
$result = [
|
|
'is_open' => false,
|
|
'is_open_today' => false,
|
|
];
|
|
|
|
if (($from = ($opening_hours[$dayOfWeek][0] ?? false))
|
|
&& ($to = ($opening_hours[$dayOfWeek][1] ?? false))) {
|
|
$breakFrom = ($opening_hours[$dayOfWeek][2] ?? false);
|
|
$breakTo = ($opening_hours[$dayOfWeek][3] ?? false);
|
|
if (DateUtil::compareTimes($from, $compareTime) && !DateUtil::compareTimes($to, $compareTime)) {
|
|
if (!$breakFrom || !$breakTo || DateUtil::compareTimes($compareTime, $breakFrom) || DateUtil::compareTimes($breakTo,
|
|
$compareTime)) {
|
|
$result['is_open'] = true;
|
|
}
|
|
}
|
|
$result['is_open_today'] = ['from' => $from, 'to' => $to, 'break_from' => $breakFrom, 'break_to' => $breakTo];
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
private static function createHolidays(string $country, int $year): ProviderInterface
|
|
{
|
|
static $holidaysCache = [];
|
|
|
|
$cacheKey = implode('-', [$country, $year]);
|
|
|
|
if (!($holidaysCache[$cacheKey] ?? false)) {
|
|
try {
|
|
// method `createByISO3166_2` does not exists in older versions of Yasumi lib (< 1.7.0)
|
|
$holidaysCache[$cacheKey] = Yasumi::createByISO3166_2($country, $year);
|
|
} catch (\Throwable $e) {
|
|
// fallback
|
|
$holidaysCache[$cacheKey] = Yasumi::create('CzechRepublic', $year);
|
|
}
|
|
}
|
|
|
|
return $holidaysCache[$cacheKey];
|
|
}
|
|
|
|
public static function getNowWithOffset(int $offset)
|
|
{
|
|
return (new \DateTime())->modify(($offset > 0 ? '+' : '-').abs($offset).' days');
|
|
}
|
|
}
|