Pull to refresh

Comments 25

Если я правильно понимаю, то изначальная проблема лишь в том, что перед сравнением объекты небыли приведены к одному формату. И для решения этой проблемы надо дополнительно писать библиотеку? По мне — это немного бредовая идея
О какой библиотеке идёт речь?
Автор предлагает написать простой ValueObject, что в целом очень удобно и даёт дополнительную проверку типов.

То есть в пхп нет простого способа отбросить часы, минуты и секунды?
И приходится писать свою обертку каждый раз, когда понадобится работать с датами?

Что не так со вторым решением? Какие еще операции сравнения нужны и почему они не будут работать?

Похожую проблему я поднимал в своей статье, где привёл в пример библиотеку $jin.time, которая хранит время не "с некоторой точностью", а "покомпонентно". Например, "Полдень в любом часовом поясе любого дня 2017 года" — это в соответствии с ISO8601 "2017T12:00:00". Если сегодня "1 апреля 2017 года" (2017-04-01), то приведение "2017T12:00:00" к числу даст штамп времени для "полудня 1 апреля 2017 года".


В вашем примере, я бы сделал так:


if( now.toString( 'YYYY-MM-DD' ) > estimatedDeliveryDate.toString( 'YYYY-MM-DD' ) ) {
...
}

Что в точности соответствовало бы поставленной задаче. Особенность iso8601 в том, что временные отметки с одинаковым набором временных компонент (и в одном часовом поясе) можно сравнивать как строки.

Не особо силен в PHP — а как учитывается разный часовой пояс тогда?

Это JS :-) В общем случае, часовой пояс учитывается приведением к одному часовому поясу. Но в данном он будет одинаковый, так как будет просто взят текущий.

Что-то меня гложут сомнения, что запись 2017T12:00:00 будет корректной — насколько я помню, нельзя просто так брать и отбрасывать значения из средины выражения.
«От даты и времени можно отбросить любое число полей, но менее значимые поля обязательно должны быть отброшены раньше более значимых.»

Вы правы: "the date component shall not be represented with reduced accuracy".
Но это логичное и удобное расширение ISO8601.

Использую карбон — он и с тестированием отлично помогает и со сравнениями, и с таймзонами


 public function testSameDates()
    {
        Carbon::setTestNow('2017-08-14 23:59:59.59');
        $d0 = Carbon::now();
        $d1 = Carbon::today();
        $d2 = Carbon::createFromFormat('Y-m-d', '2017-08-14');
        expect_that($d1->isSameDay($d2));
        expect_that($d0->isSameDay($d2));
        expect_that($d0->isSameDay($d1));
        expect_that($d0->isSameMonth($d1));
        expect_that($d0->isSameYear($d1));
        expect_that($d0->toDateString() === $d1->toDateString());
        expect_that($d0->toDateString() === $d2->toDateString());
        expect_that($d1->toDateString() === $d2->toDateString());
    }
не понимаю, почему нельзя сравнить даты с любой необходимой точностью

$estimatedDeliveryDate = new DateTimeImmutable('2017-08-16');
// представим, что сегодня ТАКЖЕ 2017-08-16
$now = new DateTimeImmutable('now');

/** @link http://php.net/manual/en/dateinterval.format.php */
$diffInFormat = $estimatedDeliveryDate->diff($now)->format('necessary_format');
Моделируя работу с числами считается хорошим тоном указывать точность. Неважно о чем идет речь — о деньгах, размере или весе; округляйте до заданного десятичного знака.

На будущее: Деньги никогда и не при каких случаях не хранятся в float/double, только int/long.

Чаще удобнее как decimal или просто строки — точностью можно управлять динамически, а если нет деления, только сложение, вычитание и умножение, то точность может быть неограниченной (в разумных пределах, конечно).

Я написал как правильно, а не как удобнее. Удобнее, например, фигурные скобки не писать в if/else, а правильно — тыкать палочкой (можно и чем потяжелее) в тех, которые их опускают.

Нет единого "правильно" в разработке. У int/long свои плюсы и минусы, у decimal свои, у string свои, и даже у float/double есть плюсы.

Удобнее работать с деньгами как с valueObject. А хранить уже не особо принципиально как. Единственно что хранение в виде дробей может быть сопряжено с потенциальными проблемами. Особенно если динамически управлять точностью.

Удобнее, да. Но хранение — важная часть реализации. И хранение в виде целых тоже может быть сопряжено с проблемами.

Тут соглашусь. Округлять деньги — гиблое дело.

Их очень часто приходится округлять в реальном мире. И проблемы в целом даже не в точности, а в том, что иногда деньги надо делить, а у них есть минимальная неделимая единица — копейка, цент и т. п… Как не крути, но если надо обсчитать реальные денежные движения, то разделить 1 копейку/цент попалам никак не получится.

Это ещё проблема часовых поясов не затронута. Даже с точностью до дня, месяца или года могут быть ситуации, что в одном поясе сгод наступил, а в другом нет. Первый вопрос к эскпертам предметной области как только упомянули даты — "часовой пояс какой"?

Оффтоп
Оказывается, если нажать «редактировать» и в форме, после редактирования, нажать большую кнопку «Отправить» — комментарий не редактируется, а создаётся новый.

Простите пожалуйста за спам выше в этой ветке. А удалить, как известно, комментарий невозможно.

Всё зависит от бизнес-логики, а точнее какими временными величинами она готова оперировать. Помещать, скажем DateTime, в VO с описанием точности в названии, а затем сравнивать эти объекты не самый лучший вариант. Если вы уже и работаете со временем, то лучшей практикой является вычисление временных интервалов для DateTime объектов, например, через date_diff(). Делается на уровне бизнес-логики и сравнивается разница в неделях, днях, часах и т. д. Здесь вопрос с точностью сам собой отпадает.

Разница может очень криво себя показывать. Например, разница между 2017-08-17T20:59:59 и 2017-07-17T21:00:00 покажет секунду, а для бизнеса это сутки, а то и неделя/месяц/год/… Суть поста в целом — сравнение дат, вычисление разниц и т. п. инкапсулируем в VO, там реализуется бизнес-логика работы с датовременем. Можно вообще абстрагироваться от DateTimeInterface, а можно его реализовывать с учётом бизнес-правил.

Only those users with full accounts are able to leave comments. Log in, please.