#php #datetime
#php #datetime
Вопрос:
Я использую объект PHP DateTime для манипулирования датами. Я нашел странный случай, когда дата результата кажется неправильной:
$dt = new DateTime('2020-02-29 23:59:59');
$dt->modify('-1 year');
echo $dt->format('Y-m-d H:i:s');
Этот код выдает 2019-03-01 23:59:59
вместо 2019-02-28 23:59:59
. Я считаю, что это связано с тем, что в 2020 году 29 февраля, но я понятия не имею, как исправить эту проблему.
Обратите внимание, что модификатором может быть что угодно, а не только -1 year
. Решение, которое изолировало бы номер года минус один, не соответствовало бы моим потребностям.
Комментарии:
1. Что именно заставляет вас думать, что это неправильная дата? 1 год обычно равен 365 дням. Если вы это сделаете
$dt->modify('-365 days');
, вы получите именно то, что получаете сейчас. Если у вашего приложения другие потребности, вы должны компенсировать это с вашей стороны.2. Расплывчатые утверждения, такие как «-1 год», на самом деле не имеют однозначного ответа, и вы не можете ожидать, что PHP волшебным образом достигнет результата, который вы имеете в виду . Если вы хотите «конец того же месяца прошлого года», это вычисление, которое вам придется явно выполнять вручную.
3. На мой взгляд, PHP дает вам правильную дату. Оба этих дня — на следующий день после 28 февраля. Если бы это дало вам 28 февраля, это было бы «-1 год и день».
4. @pistou И все же…
$dt = new DateTime('2020-03-31 23:59:59'); $dt->modify('-1 month');
результаты2020-03-02 23:59:59
. DateTime в php, как известно, привередлив, и вам гораздо лучше разобраться с шагами, которые гарантируют выбор правильного дня, вместо того, чтобы находить идеальную строку modify для использования->modify(..)
. Год или месяц не всегда относятся к одному и тому же промежутку времени, и обычно это приводит к странным и интересным сбоям.5. На самом деле все сводится к правильному определению потребностей вашего приложения. Если вам нужен «конец того же месяца прошлого года», как предложил deceze, тогда сделайте так, чтобы ваше приложение делало это, а не что-то, что не является определенным эквивалентом. Очевидно, что у PHP-разработчиков был какой-то выбор при их реализации, и, хотя вы можете с ними не согласиться, вы должны работать с ними так, как они есть.
Ответ №1:
Я сам придумал обходной путь, который, похоже, работает.
Я отметил, что все хорошо работает с первым днем месяца:
$dt = new DateTime('2020-02-01 00:00:01');
$dt->modify('-1 year');
echo $dt->format('Y-m-d H:i:s'); // 2019-02-01 00:00:01
Из этого утверждения я просто добавил несколько шагов, когда мне нужно манипулировать датами «конец месяца»:
$dt = new DateTime('2020-02-29 23:59:59');
$dt->modify('first day of this month');
$dt->modify('-1 year');
$dt->modify('last day of this month');
echo $dt->format('Y-m-d H:i:s'); // 2020-02-28 23:59:59
Комментарии:
1. Это блестяще в своей простоте. Он учитывает месяцы разной длины и даже високосные годы. Молодец.