gzhegow/calendar8

此包最新版本(1.2.0)没有可用的许可证信息。

1.2.0 2024-09-01 00:51 UTC

This package is auto-updated.

Last update: 2024-10-01 01:01:04 UTC


README

这是什么

在PHP中处理日期简直是地狱。每项操作都需要转换成三到四行代码,每行都可能抛出异常,每行在PHPStorm中都会亮起警告...

这个包旨在让处理日期更加方便。此外,你可以查看如何合理地继承PHP内置的糟糕功能,以便管理和添加自己的功能。

美好的旧时光

最初,你只是使用Date类,并确信只需要“正确地处理”。

然后你了解到Immutable,明白复杂性翻倍,直到你明白何时选择哪个。开始将一个引入另一个,并撞上精心设置的陷阱,如异常和PHP版本的不兼容性。

然后你接触到Laravel框架,其中Carbon包在核心层面使用,初始化时花费60毫秒来处理正则表达式。你想摆脱它,却做不到。然后你可能会做到)

当你最终摆脱它时,你想让你的日期API看起来能够被前端轻松解析,同时不需要配置整个symfony/serializer。你开始从现有类中继承,并意识到一半的功能仍然返回内置对象,并忽略了你的序列化。

不幸的是,日期不仅涉及处理它们,还涉及在内部存储状态,并不断在微秒级别犯错。需要非常小心才能写出稳定的代码。

这是一个关于面向对象编程是另一个大问题的故事...有时你只需要像JavaScript一样操作,添加功能到对象上,使用组合...同时理解组合使你与数据结构脱钩,并绑定到行为。总的来说,每天都是一场舞蹈。

免责声明 8.0

某个聪明的人把mixed类型添加到PHP8中JsonSerializable接口。这个检查没有任何作用,但破坏了向后兼容性。我会解雇他,但他来自伦敦。

安装

composer require gzhegow/calendar;

示例

<?php

use Gzhegow\Calendar\Lib;
use Gzhegow\Calendar\Calendar;


require_once __DIR__ . '/vendor/autoload.php';


// > настраиваем PHP
ini_set('memory_limit', '32M');

// > настраиваем обработку ошибок
error_reporting(E_ALL);
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
    if (error_reporting() & $errno) {
        throw new \ErrorException($errstr, -1, $errno, $errfile, $errline);
    }
});
set_exception_handler(function ($e) {
    var_dump(Lib::php_dump($e));
    var_dump($e->getMessage());
    var_dump(($e->getFile() ?? '{file}') . ': ' . ($e->getLine() ?? '{line}'));

    die();
});


// > создаем календарь
$calendar = new Calendar();

// > можно изменить классы дат на свои собственные реализации
// \Gzhegow\Calendar\Type::setInstance(new \Gzhegow\Calendar\Type());

// > создаем дату
$tests[ '_calendar_date' ] = $calendar->parseDateTime($datetime = 'now', $formats = null, $timezoneIfParsed = null);
Lib::assert_true('is_a', [ $tests[ '_calendar_date' ], DateTime::class ]);

// > создаем/распознаем дату
$tests[ '_calendar_date_immutable' ] = $calendar->parseDateTimeImmutable($datetime = 'now', $formats = null, $timezoneIfParsed = null);
Lib::assert_true('is_a', [ $tests[ '_calendar_date_immutable' ], DateTimeImmutable::class ]);

// > проводим действия над датой, чтобы убедится что Immutable работает
$tests[ '_calendar_date_immutable_add' ] = $tests[ '_calendar_date_immutable' ]->add(new \DateInterval('P1D'));
$tests[ '_calendar_date_immutable_sub' ] = $tests[ '_calendar_date_immutable' ]->sub(new \DateInterval('P1D'));
$tests[ '_calendar_date_immutable_modify' ] = $tests[ '_calendar_date_immutable' ]->modify('+ 10 hours');
Lib::assert_true('is_a', [ $tests[ '_calendar_date_immutable_add' ], DateTimeImmutable::class ]);
Lib::assert_true('is_a', [ $tests[ '_calendar_date_immutable_sub' ], DateTimeImmutable::class ]);
Lib::assert_true('is_a', [ $tests[ '_calendar_date_immutable_modify' ], DateTimeImmutable::class ]);
if ($tests[ '_calendar_date_immutable_add' ] === $tests[ '_calendar_date_immutable_sub' ]) throw new \RuntimeException();
if ($tests[ '_calendar_date_immutable_sub' ] === $tests[ '_calendar_date_immutable_modify' ]) throw new \RuntimeException();
if ($tests[ '_calendar_date_immutable_add' ] === $tests[ '_calendar_date_immutable_modify' ]) throw new \RuntimeException();

// > создает дату "сейчас", просто alias для _calendar_date($date)
$tests[ '_calendar_now' ] = $calendar->now($timezone = null);
$tests[ '_calendar_now_immutable' ] = $calendar->nowImmutable($timezone = null);
Lib::assert_true('is_a', [ $tests[ '_calendar_now' ], DateTime::class ]);
Lib::assert_true('is_a', [ $tests[ '_calendar_now_immutable' ], DateTimeImmutable::class ]);

// > создает/распознает временную зону
$tests[ '_calendar_timezone' ] = $calendar->parseDateTimeZone($timezone = 'UTC');
Lib::assert_true('is_a', [ $tests[ '_calendar_timezone' ], DateTimeZone::class ]);
Lib::assert_true(function () use ($tests) {
    return 'UTC' === $tests[ '_calendar_timezone' ]->getName();
});

// > создает/распознает интервал
$tests[ '_calendar_interval' ] = $calendar->parseDateInterval($interval = 'P0D', $formats = null);
Lib::assert_true('is_a', [ $tests[ '_calendar_interval' ], DateInterval::class ]);
Lib::assert_true(function () use ($tests) {
    return 'P0D' === $tests[ '_calendar_interval' ]->jsonSerialize();
});

// > возвращает разницу между датами
$now = $calendar->nowImmutable();
$past = $now->modify('- 10 hours');
$tests[ '_calendar_diff' ] = $calendar->diff($now, $past, $absolute = false); // : ?DateInterval;
Lib::assert_true('is_a', [ $tests[ '_calendar_diff' ], DateInterval::class ]);
Lib::assert_true(function () use ($tests) {
    return 'PT10H' === $tests[ '_calendar_diff' ]->jsonSerialize();
});

var_dump(json_encode($tests, JSON_PRETTY_PRINT));

// string(730) "{
//     "_calendar_date": "2024-05-09T19:47:39.074+03:00",
//     "_calendar_date_immutable": "2024-05-09T19:47:39.074+03:00",
//     "_calendar_date_immutable_add": "2024-05-10T19:47:39.074+03:00",
//     "_calendar_date_immutable_sub": "2024-05-08T19:47:39.074+03:00",
//     "_calendar_date_immutable_modify": "2024-05-10T05:47:39.074+03:00",
//     "_calendar_now": "2024-05-09T19:47:39.074+03:00",
//     "_calendar_now_immutable": "2024-05-09T19:47:39.074+03:00",
//     "_calendar_timezone": "UTC",
//     "_calendar_interval": "P0D",
//     "_calendar_diff": "PT10H"
// }"

$dump = [];
foreach ( $tests as $i => $test ) {
    $dump[ $i ] = Lib::php_dump($test);
}
var_dump($dump);

// array(13) {
//   ["_calendar_date"]=>
//   string(48) "{ object(Gzhegow\Calendar\Struct\DateTime # 8) }"
//   ["_calendar_date_immutable"]=>
//   string(57) "{ object(Gzhegow\Calendar\Struct\DateTimeImmutable # 9) }"
//   ["_calendar_date_immutable_add"]=>
//   string(58) "{ object(Gzhegow\Calendar\Struct\DateTimeImmutable # 10) }"
//   ["_calendar_date_immutable_sub"]=>
//   string(58) "{ object(Gzhegow\Calendar\Struct\DateTimeImmutable # 11) }"
//   ["_calendar_date_immutable_modify"]=>
//   string(57) "{ object(Gzhegow\Calendar\Struct\DateTimeImmutable # 7) }"
//   ["_calendar_now"]=>
//   string(49) "{ object(Gzhegow\Calendar\Struct\DateTime # 12) }"
//   ["_calendar_now_immutable"]=>
//   string(58) "{ object(Gzhegow\Calendar\Struct\DateTimeImmutable # 13) }"
//   string(58) "{ object(Gzhegow\Calendar\Struct\DateTimeImmutable # 15) }"
//   ["_calendar_timezone"]=>
//   string(53) "{ object(Gzhegow\Calendar\Struct\DateTimeZone # 16) }"
//   ["_calendar_interval"]=>
//   string(53) "{ object(Gzhegow\Calendar\Struct\DateInterval # 17) }"
//   ["_calendar_diff"]=>
//   string(53) "{ object(Gzhegow\Calendar\Struct\DateInterval # 20) }"
// }