simialbi/opening-hours

基于spatie的开业时间,查询和格式化一组开业时间的辅助工具

2.1.0 2022-07-25 09:16 UTC

This package is auto-updated.

Last update: 2024-08-25 13:45:30 UTC


README

Latest Version on Packagist Software License Tests Coverage Quality Score StyleCI Total Downloads

使用 spatie/opening-hours 创建一个描述企业营业时间的对象,您可以使用它查询某天或特定日期的 openclosed 状态,或用于展示每天的营业时间。

由于 Carboncmixin/business-time 的支持,spatie/opening-hours 可以直接在 Carbon 上使用,这样您可以直接在增强的日期对象上受益于开业时间功能。

通过传递常规日程安排和异常列表,创建一组开业时间。

// Add the use at the top of each file where you want to use the OpeningHours class:
use Spatie\OpeningHours\OpeningHours;

$openingHours = OpeningHours::create([
    'monday'     => ['09:00-12:00', '13:00-18:00'],
    'tuesday'    => ['09:00-12:00', '13:00-18:00'],
    'wednesday'  => ['09:00-12:00'],
    'thursday'   => ['09:00-12:00', '13:00-18:00'],
    'friday'     => ['09:00-12:00', '13:00-20:00'],
    'saturday'   => ['09:00-12:00', '13:00-16:00'],
    'sunday'     => [],
    'exceptions' => [
        '2016-11-11' => ['09:00-12:00'],
        '2016-12-25' => [],
        '01-01'      => [],                // Recurring on each 1st of January
        '12-25'      => ['09:00-12:00'],   // Recurring on each 25th of December
    ],
]);

// This will allow you to display things like:

$now = new DateTime('now');
$range = $openingHours->currentOpenRange($now);

if ($range) {
    echo "It's open since ".$range->start()."\n";
    echo "It will close at ".$range->end()."\n";
} else {
    echo "It's closed since ".$openingHours->previousClose($now)->format('l H:i')."\n";
    echo "It will re-open at ".$openingHours->nextOpen($now)->format('l H:i')."\n";
}

可以查询一周中的某一天,这将基于常规日程安排返回结果

// Open on Mondays:
$openingHours->isOpenOn('monday'); // true

// Closed on Sundays:
$openingHours->isOpenOn('sunday'); // false

也可以查询特定日期和时间

// Closed because it's after hours:
$openingHours->isOpenAt(new DateTime('2016-09-26 19:00:00')); // false

// Closed because Christmas was set as an exception
$openingHours->isOpenOn('2016-12-25'); // false

还可以返回一周或一天的营业时间数组

// OpeningHoursForDay object for the regular schedule
$openingHours->forDay('monday');

// OpeningHoursForDay[] for the regular schedule, keyed by day name
$openingHours->forWeek();

// Array of day with same schedule for the regular schedule, keyed by day name, days combined by working hours
$openingHours->forWeekCombined();

// OpeningHoursForDay object for a specific day
$openingHours->forDate(new DateTime('2016-12-25'));

// OpeningHoursForDay[] of all exceptions, keyed by date
$openingHours->exceptions();

在构造时,您可以设置一个标志以跨日溢出时间。例如,夜总会周五和周六营业到凌晨3点

$openingHours = \Spatie\OpeningHours\OpeningHours::create([
    'overflow' => true,
    'friday'   => ['20:00-03:00'],
    'saturday' => ['20:00-03:00'],
], null);

这允许API进一步检查昨天数据,以确定营业时间是否从昨天的时段开始开放。

您可以在定义中添加数据,然后检索它们

$openingHours = OpeningHours::create([
    'monday' => [
        'data' => 'Typical Monday',
        '09:00-12:00',
        '13:00-18:00',
    ],
    'tuesday' => [
        '09:00-12:00',
        '13:00-18:00',
        [
            '19:00-21:00',
            'data' => 'Extra on Tuesday evening',
        ],
    ],
    'exceptions' => [
        '2016-12-25' => [
            'data' => 'Closed for Christmas',
        ],
    ],
]);

echo $openingHours->forDay('monday')->getData(); // Typical Monday
echo $openingHours->forDate(new DateTime('2016-12-25'))->getData(); // Closed for Christmas
echo $openingHours->forDay('tuesday')[2]->getData(); // Extra on Tuesday evening

在上面的例子中,数据是字符串,但它可以是任何类型的值。因此,您可以在数组中嵌入多个属性。

为了结构上的方便,数据-小时对可以是完全关联的数组,因此上面的例子严格等价于以下

$openingHours = OpeningHours::create([
    'monday' => [
        'hours' => [
            '09:00-12:00',
            '13:00-18:00',
        ],
        'data' => 'Typical Monday',
    ],
    'tuesday' => [
        ['hours' => '09:00-12:00'],
        ['hours' => '13:00-18:00'],
        ['hours' => '19:00-21:00', 'data' => 'Extra on Tuesday evening'],
    ],
    // Open by night from Wednesday 22h to Thursday 7h:
    'wednesday' => ['22:00-24:00'], // use the special "24:00" to reach midnight included
    'thursday' => ['00:00-07:00'],
    'exceptions' => [
        '2016-12-25' => [
            'hours' => [],
            'data'  => 'Closed for Christmas',
        ],
    ],
]);

最后一个结构工具是过滤器,它允许您传递闭包(或可调用的函数/方法引用),该闭包接受日期作为参数并返回给定日期的设置。

$openingHours = OpeningHours::create([
    'monday' => [
       '09:00-12:00',
    ],
    'filters' => [
        function ($date) {
            $year         = intval($date->format('Y'));
            $easterMonday = new DateTimeImmutable('2018-03-21 +'.(easter_days($year) + 1).'days');
            if ($date->format('m-d') === $easterMonday->format('m-d')) {
                return []; // Closed on Easter Monday
                // Any valid exception-array can be returned here (range of hours, with or without data)
            }
            // Else the filter does not apply to the given date
        },
    ],
]);

如果在 "exceptions" 属性中找到了可调用对象,它将自动添加到过滤器中,因此您可以在 exceptions 数组中混合过滤器和异常。第一个返回非空值的过滤器将优先于后续过滤器,并且 filters 数组优先于 exceptions 数组中的过滤器。

警告:我们将对所有过滤器进行循环,以获取所需日期的开业时间,无法预测或缓存结果(可以是随机函数),因此您必须小心处理过滤器,过多的过滤器或在过滤器内部进行长时间的处理可能会对性能产生重大影响。

它还可以从给定的 DateTime 返回下一个开放或关闭的 DateTime

// The next open datetime is tomorrow morning, because we’re closed on 25th of December.
$nextOpen = $openingHours->nextOpen(new DateTime('2016-12-25 10:00:00')); // 2016-12-26 09:00:00

// The next open datetime is this afternoon, after the lunch break.
$nextOpen = $openingHours->nextOpen(new DateTime('2016-12-24 11:00:00')); // 2016-12-24 13:00:00


// The next close datetime is at noon.
$nextClose = $openingHours->nextClose(new DateTime('2016-12-24 10:00:00')); // 2016-12-24 12:00:00

// The next close datetime is tomorrow at noon, because we’re closed on 25th of December.
$nextClose = $openingHours->nextClose(new DateTime('2016-12-25 15:00:00')); // 2016-12-26 12:00:00

阅读使用说明以获取完整的API。

Spatie 是一家位于比利时安特卫普的网页设计公司。您可以在我们的网站上找到所有开源项目的概述在这里

支持我们

我们投入了大量资源来创建一流的开放源代码包。您可以通过购买我们的付费产品之一来支持我们。

我们非常感谢您从家乡寄来明信片,并提到您正在使用我们哪些包裹。您可以在我们的联系方式页面找到我们的地址。我们将在我们的虚拟明信片墙上发布所有收到的明信片。

安装

您可以通过composer安装此包。

composer require spatie/opening-hours

使用

此包应仅通过OpeningHours类使用。在整个过程中还使用了三个值对象类,分别是Time,代表单个时间点,TimeRange,代表一个有开始和结束时间的时段,以及openingHoursForDay,代表一组不能重叠的TimeRange

Spatie\OpeningHours\OpeningHours

OpeningHours::create(array $data, $timezone = null, $toutputTimezone = null): Spatie\OpeningHours\OpeningHours

静态工厂方法,用于填充工作时间集合。

$openingHours = OpeningHours::create([
    'monday' => ['09:00-12:00', '13:00-18:00'],
    // ...
]);

如果没有指定时区,则OpeningHours将假设您总是传递具有与您的时间表匹配时区的DateTime对象。

如果您将$timezone作为第二个参数或通过数组键'timezone'(它可以是DateTimeZone对象或字符串)传递,那么在每次方法开始时,将传递的日期转换为这个时区,然后如果方法返回一个日期对象(如nextOpennextClosepreviousOpenpreviousClosecurrentOpenRangeStartcurrentOpenRangeEnd),则在输出之前将其转换回原始时区,以便对象可以反映用户本地时间,而OpeningHours可以保持在它自己的业务时区。

或者您也可以指定输入和输出时区(使用第二个和第三个参数)或使用数组

$openingHours = OpeningHours::create([
    'monday' => ['09:00-12:00', '13:00-18:00'],
    'timezone' => [
        'input' => 'America/New_York',
        'output' => 'Europe/Olso',
    ],
]);

OpeningHours::mergeOverlappingRanges(array $schedule) : array

出于安全起见,如果您没有明确地在工作时间数组定义中传递'overflow' => true,则创建具有重叠范围的OpeningHours对象将抛出异常。您也可以显式地将它们合并。

$ranges = [
  'monday' => ['08:00-11:00', '10:00-12:00'],
];
$mergedRanges = OpeningHours::mergeOverlappingRanges($ranges); // Monday becomes ['08:00-12:00']

OpeningHours::create($mergedRanges);
// Or use the following shortcut to create from ranges that possibly overlap:
OpeningHours::createAndMergeOverlappingRanges($ranges);

不是所有天都是必需的,如果某一天缺失,则将其设置为关闭。

OpeningHours::fill(array $data): Spatie\OpeningHours\OpeningHours

create相同,但非静态。

$openingHours = (new OpeningHours)->fill([
    'monday' => ['09:00-12:00', '13:00-18:00'],
    // ...
]);

OpeningHours::forWeek(): Spatie\OpeningHours\OpeningHoursForDay[]

返回一个包含OpeningHoursForDay对象的数组,用于常规周。

$openingHours->forWeek();

OpeningHours::forWeekCombined(): array

返回一个数组,键是具有相同小时的第一天,值是具有相同工作时间和OpeningHoursForDay对象的日期。

$openingHours->forWeekCombined();

OpeningHours::forWeekConsecutiveDays(): array

返回一个连续的日期数组,具有相同小时数的相邻天。键是具有相同小时的第一天,值是具有相同工作时间和OpeningHoursForDay对象的日期。

警告:无论初始数据的顺序如何,连续的日子都被认为是从星期一到星期日(星期一不连续于星期日)。

$openingHours->forWeekConsecutiveDays();

OpeningHours::forDay(string $day): Spatie\OpeningHours\OpeningHoursForDay

返回一个用于常规日的OpeningHoursForDay对象。一天是以英文天名称的小写字符串。

$openingHours->forDay('monday');

OpeningHours::forDate(DateTime $dateTime): Spatie\OpeningHours\OpeningHoursForDay

返回一个用于特定日期的OpeningHoursForDay对象。它在那天查找异常,否则根据常规计划返回工作时间。

$openingHours->forDate(new DateTime('2016-12-25'));

OpeningHours::exceptions(): Spatie\OpeningHours\OpeningHoursForDay[]

返回一个所有OpeningHoursForDay对象的数组,按Y-m-d日期字符串键。

$openingHours->exceptions();

OpeningHours::isOpenOn(string $day): bool

检查在常规计划中的某一天是否营业(至少包含一个开放时间范围)。

$openingHours->isOpenOn('saturday');

如果给定字符串是日期,它将检查是否营业(至少包含一个开放时间范围),同时考虑常规日计划和可能的异常。

$openingHours->isOpenOn('2020-09-03');
$openingHours->isOpenOn('09-03'); // If year is omitted, current year is used instead

OpeningHours::isClosedOn(string $day): bool

检查在常规计划中的某一天,企业是否关闭。

$openingHours->isClosedOn('sunday');

OpeningHours::isOpenAt(DateTime $dateTime): bool

检查在特定日期和特定时间,企业是否开放。

$openingHours->isOpenAt(new DateTime('2016-26-09 20:00'));

OpeningHours::isClosedAt(DateTime $dateTime): bool

检查在特定日期和特定时间,企业是否关闭。

$openingHours->isClosedAt(new DateTime('2016-26-09 20:00'));

OpeningHours::isOpen(): bool

检查企业当前是否开放。

$openingHours->isOpen();

OpeningHours::isClosed(): bool

检查企业当前是否关闭。

$openingHours->isClosed();

OpeningHours::nextOpen(DateTimeInterface $dateTime) : DateTime

从给定的 DateTime 返回下一个开放 DateTime。

$openingHours->nextOpen(new DateTime('2016-12-24 11:00:00'));

OpeningHours::nextClose(DateTimeInterface $dateTime) : DateTime

从给定的 DateTime 返回下一个关闭 DateTime。

$openingHours->nextClose(new DateTime('2016-12-24 11:00:00'));

OpeningHours::previousOpen(DateTimeInterface $dateTime) : DateTime

从给定的 DateTime 返回上一个开放 DateTime。

$openingHours->previousOpen(new DateTime('2016-12-24 11:00:00'));

OpeningHours::previousClose(DateTimeInterface $dateTime) : DateTime

从给定的 DateTime 返回上一个关闭 DateTime。

$openingHours->nextClose(new DateTime('2016-12-24 11:00:00'));

OpeningHours::diffInOpenHours(DateTimeInterface $startDate, DateTimeInterface $endDate) : float

返回两个日期/时间之间开放时间(以浮点数表示的小时数)。

$openingHours->diffInOpenHours(new DateTime('2016-12-24 11:00:00'), new DateTime('2016-12-24 16:34:25'));

OpeningHours::diffInOpenMinutes(DateTimeInterface $startDate, DateTimeInterface $endDate) : float

返回两个日期/时间之间开放时间(以浮点数表示的分钟数)。

OpeningHours::diffInOpenSeconds(DateTimeInterface $startDate, DateTimeInterface $endDate) : float

返回两个日期/时间之间开放时间(以浮点数表示的秒数)。

OpeningHours::diffInClosedHours(DateTimeInterface $startDate, DateTimeInterface $endDate) : float

返回两个日期/时间之间关闭时间(以浮点数表示的小时数)。

$openingHours->diffInClosedHours(new DateTime('2016-12-24 11:00:00'), new DateTime('2016-12-24 16:34:25'));

OpeningHours::diffInClosedMinutes(DateTimeInterface $startDate, DateTimeInterface $endDate) : float

返回两个日期/时间之间关闭时间(以浮点数表示的分钟数)。

OpeningHours::diffInClosedSeconds(DateTimeInterface $startDate, DateTimeInterface $endDate) : float

返回两个日期/时间之间关闭时间(以浮点数表示的秒数)。

OpeningHours::currentOpenRange(DateTimeInterface $dateTime) : false | TimeRange

如果企业开放,返回当前开放范围的 Spatie\OpeningHours\TimeRange 实例,如果企业关闭,返回 false。

$range = $openingHours->currentOpenRange(new DateTime('2016-12-24 11:00:00'));

if ($range) {
    echo "It's open since ".$range->start()."\n";
    echo "It will close at ".$range->end()."\n";
} else {
    echo "It's closed";
}

OpeningHours::currentOpenRangeStart(DateTimeInterface $dateTime) : false | DateTime

如果企业开放,返回企业开放以来的日期和时间 DateTime 实例,如果企业关闭,返回 false。

注意:如果使用夜间范围,日期可以是前一天。

$date = $openingHours->currentOpenRangeStart(new DateTime('2016-12-24 11:00:00'));

if ($date) {
    echo "It's open since ".$date->format('H:i');
} else {
    echo "It's closed";
}

OpeningHours::currentOpenRangeEnd(DateTimeInterface $dateTime) : false | DateTime

如果企业开放,返回企业将开放到的时间的 DateTime 实例,如果企业关闭,返回 false。

注意:如果使用夜间范围,日期可以是下一天。

$date = $openingHours->currentOpenRangeEnd(new DateTime('2016-12-24 11:00:00'));

if ($date) {
    echo "It will close at ".$date->format('H:i');
} else {
    echo "It's closed";
}

OpeningHours::asStructuredData(string $format = 'H:i', string|DateTimeZone $timezone) : array

以数组形式返回 OpeningHoursSpecification

$openingHours->asStructuredData();
$openingHours->asStructuredData('H:i:s'); // Customize time format, could be 'h:i a', 'G:i', etc.
$openingHours->asStructuredData('H:iP', '-05:00'); // Add a timezone
// Timezone can be numeric or string like "America/Toronto" or a DateTimeZone instance
// But be careful, the time is arbitrary applied on 1970-01-01, so it does not handle daylight
// saving time, meaning Europe/Paris is always +01:00 even in summer time.

Spatie\OpeningHours\OpeningHoursForDay

此类旨在只读。它实现了 ArrayAccessCountableIteratorAggregate,因此您可以以类似数组的方式处理 TimeRange 列表。

Spatie\OpeningHours\TimeRange

值对象,描述具有起始和结束时间的时段。可以以 H:i-H:i 格式转换为字符串。

Spatie\OpeningHours\Time

值对象,描述单个时间。可以以 H:i 格式转换为字符串。

适配器

OpenStreetMap

您可以使用 osm-opening-hours(感谢 mgrundkoetter)将 OpenStreetMap 格式转换为 OpeningHours 对象。

变更日志

请参阅变更日志了解最近有哪些变化。

测试

composer test

贡献

请参阅贡献指南获取详细信息。

安全

如果您发现与安全相关的错误,请发送邮件至security@spatie.be,而不是使用问题追踪器。

明信片软件

您可以使用此软件包,但如果它进入您的生产环境,我们非常希望您能从家乡给我们寄一张明信片,说明您正在使用我们的哪些软件包。

我们的地址是:Spatie,Kruikstraat 22,2018 安特卫普,比利时。

我们将在公司网站上发布所有收到的明信片。

致谢

许可证

MIT 许可证(MIT)。请参阅许可证文件了解详细信息。