Комментарии 25
Что не так со вторым решением? Какие еще операции сравнения нужны и почему они не будут работать?
Похожую проблему я поднимал в своей статье, где привёл в пример библиотеку $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 в том, что временные отметки с одинаковым набором временных компонент (и в одном часовом поясе) можно сравнивать как строки.
Использую карбон — он и с тестированием отлично помогает и со сравнениями, и с таймзонами
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 или просто строки — точностью можно управлять динамически, а если нет деления, только сложение, вычитание и умножение, то точность может быть неограниченной (в разумных пределах, конечно).
Удобнее работать с деньгами как с valueObject. А хранить уже не особо принципиально как. Единственно что хранение в виде дробей может быть сопряжено с потенциальными проблемами. Особенно если динамически управлять точностью.
Тут соглашусь. Округлять деньги — гиблое дело.
Их очень часто приходится округлять в реальном мире. И проблемы в целом даже не в точности, а в том, что иногда деньги надо делить, а у них есть минимальная неделимая единица — копейка, цент и т. п… Как не крути, но если надо обсчитать реальные денежные движения, то разделить 1 копейку/цент попалам никак не получится.
Это ещё проблема часовых поясов не затронута. Даже с точностью до дня, месяца или года могут быть ситуации, что в одном поясе сгод наступил, а в другом нет. Первый вопрос к эскпертам предметной области как только упомянули даты — "часовой пояс какой"?
Простите пожалуйста за спам выше в этой ветке. А удалить, как известно, комментарий невозможно.
Всё зависит от бизнес-логики, а точнее какими временными величинами она готова оперировать. Помещать, скажем DateTime, в VO с описанием точности в названии, а затем сравнивать эти объекты не самый лучший вариант. Если вы уже и работаете со временем, то лучшей практикой является вычисление временных интервалов для DateTime объектов, например, через date_diff(). Делается на уровне бизнес-логики и сравнивается разница в неделях, днях, часах и т. д. Здесь вопрос с точностью сам собой отпадает.
Разница может очень криво себя показывать. Например, разница между 2017-08-17T20:59:59 и 2017-07-17T21:00:00 покажет секунду, а для бизнеса это сутки, а то и неделя/месяц/год/… Суть поста в целом — сравнение дат, вычисление разниц и т. п. инкапсулируем в VO, там реализуется бизнес-логика работы с датовременем. Можно вообще абстрагироваться от DateTimeInterface, а можно его реализовывать с учётом бизнес-правил.
Точность через неточность: Улучшаем Time-объекты