Посчитать количество дней между датами php
Длительный ответ
Большинство ответов с использованием временных меток UNIX делают два предположения, которые, вместе взятые, могут привести к сценариям с неправильными результатами и небольшими ошибками, которые могут быть трудно отследить, и возникают даже дни, недели или месяцы после успешного развертывания.
Первая ошибка не учитывает, что, когда его спросили: «Сколько прошло дней со вчерашнего дня?», Компьютер может честно ответить на ноль, если между настоящим и мгновением, указанным «вчера», прошло менее одного дня .
Обычно при преобразовании «дня» в временную метку UNIX получается временная метка в полночь того дня.
Таким образом, между полуночами с 1 октября по 15 октября прошло пятнадцать дней. Но с 13:00 1 октября и 14:55 15 октября прошло пятнадцать дней минус 5 минут , и большинство решений, использующих floor() или выполняющих неявное целочисленное преобразование , сообщают на один день меньше, чем ожидалось .
Итак, «сколько дней назад был Ymd H: i: s»? даст неправильный ответ .
Вторая ошибка – один день – 86400 секунд. Это почти всегда верно – это бывает достаточно часто, чтобы не заметить время, когда этого не происходит. Но расстояние в секундах между двумя последовательными полуночами – это не 86400, по крайней мере, два раза в год, когда вступает в действие летнее время. Сравнение двух дат на границе DST снова даст неправильный ответ.
Поэтому, даже если вы используете «взломать» форсирование всех временных дат даты до фиксированного часа, скажем, в полночь (это также делается неявно на разных языках и фреймах, когда вы указываете только день-месяц-год, а не час-минута-секунда) , широко используемая формула
или пол (время () – strtotime ($ somedate)) / 86400
вернется, скажем, 17, когда DATE1 и DATE2 находятся в одном сегменте DST года; но он может вернуться 17.042, а еще хуже – 16.958. Использование floor () или любого неявного усечения в integer затем преобразует то, что должно было быть от 17 до 16.
И все становится еще более уродливым, поскольку такой код не переносится на разных платформах, потому что некоторые из них могут применять секунды прыжка, а некоторые – нет . На тех платформах, которые делают , разница между двумя датами не будет 86400, а 86401, или, может быть, 86399. Таким образом, код, который работал в мае и фактически прошел все тесты, прорвется в следующем июне, когда 1299999 дней считаются 12 днями вместо 13. Две даты который работал в 2015 году, не будет работать в 2017 году – те же даты, и ни один год не является високосным годом. Но между 2018-01-01 и 2017-01-01 на тех платформах, которые заботятся, 366 дней пройдут вместо 365, сделав 2017 год високосным.
Поэтому, если вы действительно хотите использовать временные метки UNIX:
используйте функцию round() , а не floor() .
в качестве альтернативы, не рассчитывайте разницы между D1-M1-YYY1 и D2-M2-YYY2. Эти даты будут действительно рассматриваться как D1-M1-YYY1 00:00:00 и D2-M2-YYY2 00:00:00. Скорее, конвертируйте между D1-M1-YYY1 22:30:00 и D2-M2-YYY2 04:30:00. Вы всегда получите остаток около двадцати часов. Это может стать двадцать один час или девятнадцать, а может быть, восемнадцать часов, пятьдесят девять минут тридцать шесть секунд. Не важно. Это большой запас, который останется там и останется положительным в обозримом будущем. Теперь вы можете усекать его с помощью floor() в безопасности.
Правильное решение состоит в том, чтобы
использовать библиотеку времени (Datetime, Carbon, что угодно); не сворачивайте свои собственные
пишите всесторонние тестовые примеры, используя действительно злые даты – через границы DST, через високосные годы, через прыжки секунд и т. д., а также банальные даты. В идеале (призывы к дате времени бывают быстрыми !) Генерируют четыре года (и один день) даты, собирая их из строк, последовательно и гарантируя, что разница между первым днем и днем, прошедшим тестирование, неуклонно растет. Это гарантирует, что, если что-либо изменится в низкоуровневых процедурах и секундах прыжков, попытайтесь нанести ущерб, по крайней мере, вы узнаете .
регулярно проводите эти тесты вместе с остальной частью набора тестов. Это вопрос миллисекунды и может спасти вас буквально часами царапин на голове.
Независимо от вашего решения, проверьте его
Функция funcdiff ниже реализует одно из решений (как это принято, принятое) в реальном мире.
История ужасов: стоимость «экономии времени»
Это произошло несколько месяцев назад. Гениальный программист решил сэкономить несколько микросекунд при расчете, которое заняло не более тридцати секунд, подключив печально известный код «(MidnightOfDateB-MidnightOfDateA) / 86400» в нескольких местах. Это была настолько очевидная оптимизация, что он даже не документировал ее, и оптимизация прошла интеграционные тесты и скрывалась в коде несколько месяцев, и все это незамечено.
Это произошло в программе, которая рассчитывает заработную плату для нескольких продавцов, продавших самые продаваемые продавцы, причем наименьшее из которых имеет страшное много больше, чем целая скромная команда из пяти человек, составленная вместе. Однажды несколько месяцев назад, по причинам, которые мало что значили, ошибка ударила – и некоторые из этих парней получили один день целых полных комиссий. Они определенно не позабавились.
Бесконечно худшие, они потеряли (уже очень мало) вера, которую они имели в программе, не предназначенную для тайного приведения их в порядок, и притворились – и получили – полный подробный обзор кода с тестовыми примерами был запущен и прокомментирован в терминах непрофессионала (плюс много лечения красной ковровой дорожкой в следующие недели).
Что я могу сказать: с положительной стороны, мы избавились от большого технического долга и смогли переписать и реорганизовать несколько частей беспорядка спагетти, который вернулся к заражению COBOL в качающихся 90-х годах. Программа, несомненно, работает лучше сейчас, и есть намного больше информации для отладки, чтобы быстро получить нуль, когда что-то выглядит подозрительно. Полагаю, что только это последнее спасет, возможно, один или два человеко-дня в месяц в обозримом будущем.
На минусовой стороне вся броухаха стоила компании около 200 000 евро впереди – плюс лицо, плюс, несомненно, какая-то способность торговаться (и, следовательно, еще больше денег).
Парень, ответственный за «оптимизацию», сменил работу год назад, до катастрофы, но все же был разговор, чтобы подать в суд на него за ущерб. И с верхними эшелонами не получилось, что это была «вина последнего парня» – это было похоже на настройку для нас, чтобы вылечить эту проблему, и, в конце концов, мы все еще в собачьей упряжке и одна из команд планирует выйти.
Девяносто девять раз из ста, «взлом 86400» будет работать безупречно. (Например, в PHP, strtotime() игнорирует DST и сообщает, что между полуночи последней субботы октября и дня следующего понедельника прошло ровно 2 * 24 * 60 * 60 секунд, даже если это явно не так … и две неудачи с радостью сделают одно право).
Это, дамы и господа, был одним из примеров, когда этого не произошло. Как и в случае с подушками безопасности и ремнями безопасности, вам, возможно, никогда не понадобится сложность (и простота использования) DateTime или Carbon . Но день, когда вы (или день, когда вам придется доказывать, что вы об этом подумали), придет как вор ночью. Приготовься.
Простота использования date_diff
Ну, выбранный ответ не самый правильный, потому что он выйдет за пределы UTC. В зависимости от часового пояса ( списка ) могут быть корректировки времени, создающие дни «без» 24 часов, и это приведет к сбою расчета (60 * 60 * 24).
Поэтому правильным решением будет использование DateTime
Теперь он работает
Я использую Carbon в моих проектах композитора для этой и подобных целей.
Это было бы так просто:
и, при необходимости:
Если у вас есть время в секундах (отметка времени Unix Unix), вы можете просто вычесть время и разделить на 86400 (секунды в день)
Если вы хотите повторить все дни между датой начала и окончания, я придумал следующее:
Если вы используете MySql
Вот моя улучшенная версия, которая показывает 1 год (ы) 2 Месяцев (ы) 25 дней (ы), если 2-й параметр передан.
Попробуйте использовать углерод
Также вы можете использовать
для создания объекта Carbon date с использованием заданной строки timestamp.
использовал вышеуказанный код очень просто. Благодарю.
DateTime::diff
DateTimeInterface::diff
(PHP 5 >= 5.3.0, PHP 7)
DateTime::diff — DateTimeImmutable::diff — DateTimeInterface::diff — date_diff — Возвращает разницу между двумя объектами DateTime
Описание
Возвращает разницу между двумя объектами DateTimeInterface.
Список параметров
Дата и время для сравнения.
Используется, чтобы вернуть абсолютную разницу.
Возвращаемые значения
DateInterval объект представляет разницу между двумя датами или FALSE в случае возникновения ошибки.
Примеры
Пример #1 Пример использования DateTime::diff()
Результат выполнения данных примеров:
Пример #2 Сравнение объектов DateTime
Замечание:
С версии PHP 5.2.2 объекты DateTime могут сравниваться при помощи операторов сравнения.
Результат выполнения данного примера:
Смотрите также
- DateInterval::format() — Форматирует интервал
- DateTime::add() — Добавляет заданное количество дней, месяцев, лет, часов, минут и секунд к объекту DateTime
- DateTime::sub() — Вычитает заданное количество дней, месяцев, лет, часов, минут и секунд из времени объекта DateTime
User Contributed Notes 28 notes
It is worth noting, IMO, and it is implied in the docs but not explicitly stated, that the object on which diff is called is subtracted from the object that is passed to diff.
i.e. $now->diff($tomorrow) is positive.
Be careful using:
$date1 = new DateTime(‘now’);
$date2 = new DateTime(‘tomorrow’);
$interval = date_diff($date1, $date2);
echo $interval->format(‘In %a days’);
In some situations, this won’t say «in 1 days», but «in 0 days».
I think this is because «now» is the current time, while «tomorrow» is the current day +1 but at a default time, lets say:
Now: 08:00pm, 01.01.2015
Tomorrow: 00:00am, 02.01.2015
In this case, the difference is not 24 hour, so it will says 0 days.
Better use «today», which should also use a default value like:
Today: 00:00am, 01.01.2015
Tomorrow: 00:00am, 02.01.2015
which now is 24 hour and represents 1 day.
This may sound logical and many will say «of course, this is right», but if you use it in a naiv way (like I did without thinking), you can come to this moment and facepalm yourself.
Conclusion: «Now» is «Today», but in a different clock time, but still the same day!
After wrestling with DateTime::diff for a while it finally dawned on me the problem was both in the formatting of the input string and the formatting of the output.
The task was to calculate the duration between two date/times.
1. Make sure you have a valid date variable. Both of these strings are valid:
2. Next convert the string to a date variable
3. Calculate the difference
4. Format the output
[Modified by moderator for clarify]
Using the identical (===) comparision operator in different but equal objects will return false
Be careful, the behaviour depends on the time zones in a weird way.
diff ( $d2 );
print( $diff -> format ( «Year: %Y Month: %M Day: %D» ). PHP_EOL );
>
printDiff ( «UTC» );
printDiff ( «Australia/Melbourne» );
?>
The result is different:
Year: 00 Month: 01 Day: 00
Year: 00 Month: 00 Day: 30
If you want to quickly scan through the resulting intervals, you can use the undocumented properties of DateInterval.
The function below returns a single number of years, months, days, hours, minutes or seconds between the current date and the provided date. If the date occurs in the past (is negative/inverted), it suffixes it with ‘ago’.
diff ( $datetime );
$suffix = ( $interval -> invert ? ‘ ago’ : » );
if ( $v = $interval -> y >= 1 ) return pluralize ( $interval -> y , ‘year’ ) . $suffix ;
if ( $v = $interval -> m >= 1 ) return pluralize ( $interval -> m , ‘month’ ) . $suffix ;
if ( $v = $interval -> d >= 1 ) return pluralize ( $interval -> d , ‘day’ ) . $suffix ;
if ( $v = $interval -> h >= 1 ) return pluralize ( $interval -> h , ‘hour’ ) . $suffix ;
if ( $v = $interval -> i >= 1 ) return pluralize ( $interval -> i , ‘minute’ ) . $suffix ;
return pluralize ( $interval -> s , ‘second’ ) . $suffix ;
>
?>
It seems that while DateTime in general does preserve microseconds, DateTime::diff doesn’t appear to account for it when comparing.
if( $datetime1 > $datetime2 )
echo «1 is bigger» ;
else
echo «2 is bigger» ;
?>
The var_dump shows that there is no «u» element, and «2 is bigger» is echoed.
To work around this apparent limitation/oversight, you have to additionally compare using DateTime::format.
$datetime2 )
echo «1 is bigger» ;
else if ( $datetime1 -> format ( ‘u’ ) > $datetime2 -> format ( ‘u’ ))
echo «1 is bigger» ;
else
echo «2 is bigger» ;
?>
Warning, there’s a bug on windows platforms: the result is always 6015 days (and not 42. )
Though I found a number of people who ran into the issue of 5.2 and lower not supporting this function, I was unable to find any solid examples to get around it. Therefore I hope this can help some others:
format ( ‘Y’ );
$Y2 = $newer -> format ( ‘Y’ );
$Y = $Y2 — $Y1 ;
$m1 = $older -> format ( ‘m’ );
$m2 = $newer -> format ( ‘m’ );
$m = $m2 — $m1 ;
$d1 = $older -> format ( ‘d’ );
$d2 = $newer -> format ( ‘d’ );
$d = $d2 — $d1 ;
$H1 = $older -> format ( ‘H’ );
$H2 = $newer -> format ( ‘H’ );
$H = $H2 — $H1 ;
$i1 = $older -> format ( ‘i’ );
$i2 = $newer -> format ( ‘i’ );
$i = $i2 — $i1 ;
$s1 = $older -> format ( ‘s’ );
$s2 = $newer -> format ( ‘s’ );
$s = $s2 — $s1 ;
if( $s = 1 ) <
$found_first_diff = true ;
$timespan_string .= pluralize ( $Y , ‘year’ ). ‘ ‘ ;
>
if( $m >= 1 || $found_first_diff ) <
$found_first_diff = true ;
$timespan_string .= pluralize ( $m , ‘month’ ). ‘ ‘ ;
>
if( $d >= 1 || $found_first_diff ) <
$found_first_diff = true ;
$timespan_string .= pluralize ( $d , ‘day’ ). ‘ ‘ ;
>
if( $H >= 1 || $found_first_diff ) <
$found_first_diff = true ;
$timespan_string .= pluralize ( $H , ‘hour’ ). ‘ ‘ ;
>
if( $i >= 1 || $found_first_diff ) <
$found_first_diff = true ;
$timespan_string .= pluralize ( $i , ‘minute’ ). ‘ ‘ ;
>
if( $found_first_diff ) <
$timespan_string .= ‘and ‘ ;
>
$timespan_string .= pluralize ( $s , ‘second’ );
return $timespan_string ;
>
function pluralize ( $count , $text )
<
return $count . ( ( $count == 1 ) ? ( » $text » ) : ( » $ < text >s» ) );
>
?>
$strStart = ‘2013-06-19 18:25’;
$strEnd = ’06/21/13 21:47′;
$dteStart = new DateTime($strStart);
$dteEnd = new DateTime($strEnd);
$dteDiff = $dteStart->diff($dteEnd);
print $dteDiff->format(«%H:%I:%S»);
this script not comparing the date, its working only for the time
Поиск количества дней между двумя датами
Как найти количество дней между двумя датами с помощью PHP?
Если вы используете PHP 5.3 > , это, безусловно, самый точный способ вычисления разницы:
От PHP версии 5.3 и выше, новые функции даты/времени добавлены, чтобы получить разницу:
Результат, как показано ниже:
Надеюсь, что это поможет!
Преобразуйте даты в временные метки unix, затем выложите один из другого. Это даст вам разницу в секундах, которую вы разделите на 86400 (количество секунд в день), чтобы дать вам приблизительное количество дней в этом диапазоне.
Если ваши даты в формате 25.1.2010 , 01/25/2010 или 2010-01-25 , вы можете использовать функцию strtotime :
Использование ceil округляет количество дней до следующего полного дня. Используйте floor вместо этого, если вы хотите получить количество полных дней между этими двумя датами.
Если ваши даты уже находятся в формате timestamp в формате unix, вы можете пропустить преобразование и просто сделать часть $days_between . Для более экзотических форматов даты вам, возможно, придется выполнить некоторый выборочный синтаксический анализ, чтобы получить право.
TL; DR не использует метки времени UNIX. Не используйте time() . Если вы это сделаете, будьте готовы, если его надежность 98.0825% подведет вас. Используйте DateTime (или Carbon).
Правильный ответ — тот, который дал Сакшам Гупта (другие ответы также верны):
Или процедурно как однострочник
С оговоркой: «% a» указывает на абсолютное количество дней. Если вы хотите, чтобы оно представляло собой целое число со знаком, то есть отрицательное, когда вторая дата находится перед первой, тогда вам нужно использовать префикс «% r» (т.е. format(‘%r%a’) ).
Если вам действительно нужно использовать временные метки UNIX, установите часовой пояс на GMT, чтобы избежать большинства ошибок, описанных ниже.
Длинный ответ: почему деление на 24 * 60 * 60 (86400) небезопасно
Большинство ответов, использующих метки времени UNIX (и 86400 для преобразования их в дни), делают два предположения, которые, вместе взятые, могут привести к сценариям с неправильными результатами и незначительным ошибкам, которые могут быть трудно отследить, и возникают даже через дни, недели или месяцы после успешное развертывание. Дело не в том, что решение не работает — оно работает. Сегодня. Но это может перестать работать завтра.
Первая ошибка не в том, что, когда спрашивают: «Сколько дней прошло со вчерашнего дня?», Компьютер может правдиво ответить на ноль, если между настоящим моментом и моментом, указанным «вчера», прошло менее одного целого дня.
Обычно при преобразовании «дня» в метку времени UNIX получается метка времени для полуночи этого конкретного дня.
Таким образом, с полуночи 1 октября по 15 октября прошло пятнадцать дней. Но между 13:00 1 октября и 14:55 15 октября прошло пятнадцать дней минус 5 минут, и большинство решений, использующих floor() или выполняющих неявное целочисленное преобразование , сообщат на один день меньше ожидаемого.
Итак, «сколько дней назад был Ymd H: i: s»? даст неправильный ответ.
Вторая ошибка — приравнивание одного дня к 86400 секундам. Это почти всегда так — это случается достаточно часто, чтобы не замечать того времени, когда этого не происходит. Но расстояние в секундах между двумя последовательными ночами, безусловно, не равно 86400, по крайней мере, два раза в год, когда наступает летнее время. Сравнение двух дат за границей летнего времени даст неправильный ответ.
Таким образом, даже если вы используете «хак» для принудительной установки всех временных отметок даты на фиксированный час, скажем, полночь (это также делается неявно различными языками и средами, когда вы указываете только день-месяц-год, а не час-минута-секунда; То же самое можно сказать о типе DATE в базах данных, таких как MySQL), широко используемой формуле
вернет, скажем, 17, когда DATE1 и DATE2 находятся в одном и том же сегменте DST года; но он может вернуть 17,042, и еще хуже, 16,958. Использование floor() или любого неявного усечения в целое число затем преобразует то, что должно было быть 17, в 16. В других случаях выражения, такие как «$ days> 17», будут возвращать true для 17.042, даже если это будет означать, что прошедший день количество составляет 18.
И все становится еще хуже, так как такой код не переносим между платформами, потому что некоторые из них могут применять дополнительные секунды, а некоторые нет. На этих платформах разница между двумя датами будет не 86400, а 86401, или, возможно, 86399. Поэтому код, который работал в мае и фактически прошел все тесты, прекратит работу в следующем июне, когда 12.99999 дней будут считаться 12 днями вместо 13. Две даты который работал в 2015 году, не будет работать в 2017 году — те же даты, и ни один год не является високосным. Но между 2018-03-01 и 2017-03-01, на тех платформах, которые заботятся, пройдет 366 дней вместо 365, что сделает 2017 год високосным.
Так что если вы действительно хотите использовать метки времени UNIX:
используйте функцию round() умом, а не floor() .
в качестве альтернативы не рассчитывайте разницу между D1-M1-YYY1 и D2-M2-YYY2. Эти даты будут действительно рассматриваться как D1-M1-YYY1 00:00:00 и D2-M2-YYY2 00:00:00. Скорее, конвертируйте между D1-M1-YYY1 22:30:00 и D2-M2-YYY2 04:30:00. Вы всегда получите остаток около двадцати часов. Это может быть двадцать один час или девятнадцать, а может быть, восемнадцать часов пятьдесят девять минут тридцать шесть секунд. Независимо от того. Это большой запас, который останется там и останется позитивным в обозримом будущем. Теперь вы можете обрезать его с floor() в безопасности.
Однако правильное решение, чтобы избежать магических констант, округления клуджей и долга за обслуживание, состоит в том, чтобы
использовать библиотеку времени (Datetime, Carbon, что угодно); не катай свой собственный
написать всесторонние контрольные примеры с использованием действительно неправильных выборов дат — через границы летнего времени, через високосные годы, за високосные секунды и т.д., а также заурядные даты. В идеале (вызовы datetime выполняются быстро!) Генерируют даты за целые четыре года (и один день), последовательно собирая их из строк и гарантируя, что разница между первым и тестируемым днем неуклонно возрастает на единицу. Это будет гарантировать, что, если что-то изменится в низкоуровневых подпрограммах и исправлениях високосных секунд, попытается нанести ущерб, по крайней мере, вы будете знать.
регулярно запускайте эти тесты вместе с остальным набором тестов. Они считаются миллисекундами и могут сэкономить вам буквально часы царапин на голове.
Каким бы ни было ваше решение, протестируйте его!
Функция funcdiff ниже реализует одно из решений (как это принято, принятое) в реальном сценарии.
История ужасов: стоимость «экономии времени»
Это на самом деле произошло несколько месяцев назад. Гениальный программист решил сэкономить несколько микросекунд за счет вычисления, которое занимало максимум около тридцати секунд, подключив печально известный код «(MidnightOfDateB-MidnightOfDateA)/86400» в нескольких местах. Оптимизация была настолько очевидна, что он даже не задокументировал ее, и оптимизация прошла интеграционные тесты и скрывалась в коде в течение нескольких месяцев, причем все это было незамеченным.
Это произошло в программе, которая рассчитывает заработную плату нескольких продавцов, пользующихся наибольшим спросом, у меньшего из которых ужасное влияние гораздо больше, чем у всей скромной команды программистов из пяти человек вместе взятых. Однажды, несколько месяцев назад, по причинам, которые мало что значат, ошибка произошла — и некоторые из этих ребят получили целый день лишних комиссионных. Они определенно не были удивлены.
Несомненно, они потеряли (и без того очень мало) веру, которую они имели в программе, не предназначенной для того, чтобы тайно их подбросить, и притворились — и получили — полный, подробный обзор кода с тестовыми примерами, выполненными и прокомментированными с точки зрения непрофессионала (плюс много лечения красной ковровой дорожке в следующие недели).
Что я могу сказать: с другой стороны, мы избавились от большого технического долга и смогли переписать и реорганизовать несколько кусочков спагетти-беспорядка, которые были возвращены к заражению КОБОЛОМ в бурные 90-е годы. Программа, несомненно, теперь работает лучше, и там гораздо больше отладочной информации, чтобы быстро сосредоточиться, когда все выглядит подозрительно. Я полагаю, что только эта последняя вещь сэкономит, возможно, один или два человека в месяц в обозримом будущем.
С другой стороны, вся эта затея обошлась компании примерно в 200 000 евро — плюс лицо, плюс, несомненно, некоторая переговорная сила (и, следовательно, еще больше денег).
Парень, ответственный за «оптимизацию», сменил работу год назад, до катастрофы, но все же ходили разговоры, чтобы подать в суд на него за ущерб. И с высшими эшелонами не очень хорошо, что это «последняя ошибка парня» — это выглядело как подстава для нас, чтобы разобраться в этом вопросе, и, в конце концов, мы все еще в конуре и одна из команды планирует выйти.
Девяносто девять раз из ста, «86400 взломать» будет работать безупречно. (Например, в PHP strtotime() будет игнорировать DST и сообщать, что между полуночью последней субботы октября и следующего понедельника прошло ровно 2 * 24 * 60 * 60 секунд, даже если это явно не соответствует действительности. и два блага с радостью сделают одно правым).
Дамы и господа, это был один случай, когда этого не произошло. Как и в случае с подушками безопасности и ремнями безопасности, вам, вероятно, никогда не понадобится сложность (и простота использования) DateTime или Carbon . Но день, когда вы можете (или день, когда вам придется доказать, что вы подумали об этом) ночью придет как вор. Будь готов.
php — счетчик — сколько часов прошло между двумя датами
Поиск количества дней между двумя датами (18)
количество дней между двумя датами в PHP
Как найти количество дней между двумя датами с помощью PHP?
TL; DR не используют отметки времени UNIX. Не используйте time() . Если вы это сделаете, будьте готовы, если ваша надежность 98.0825% не даст вам. Используйте DateTime (или Carbon).
Правильный ответ — тот, который дал Сакшам Гупта (другие ответы также верны):
Или процедурно как однострочный:
Если вы действительно должны использовать отметки времени UNIX, установите часовой пояс на GMT, чтобы избежать большинства ловушек, описанных ниже.
Длинный ответ: почему деление на 24 * 60 * 60 (aka 86400) является небезопасным
Большинство ответов с использованием временных меток UNIX (и 86400 для преобразования в дни) делают два предположения, которые, вместе взятые, могут привести к сценариям с неправильными результатами и тонкими ошибками, которые могут быть трудно отследить, и возникают даже дни, недели или месяцы после успешное развертывание. Дело не в том, что решение не работает — оно работает. Сегодня. Но завтра он может перестать работать.
Первая ошибка не учитывает, что, когда его спросили: «Сколько прошло дней со вчерашнего дня?», Компьютер может честно ответить на ноль, если между настоящим и мгновением, указанным «вчера», прошло менее одного дня .
Обычно при преобразовании «дня» в временную метку UNIX получается временная метка в полночь того дня.
Таким образом, между полуночами с 1 октября по 15 октября прошло пятнадцать дней. Но с 13:00 1 октября и 14:55 15 октября прошло пятнадцать дней минус 5 минут , и большинство решений, использующих floor() или выполняющих неявное целочисленное преобразование , сообщают на один день меньше, чем ожидалось .
Итак, «сколько дней назад был Ymd H: i: s»? даст неправильный ответ .
Вторая ошибка — один день — 86400 секунд. Это почти всегда верно — это бывает достаточно часто, чтобы не заметить время, когда этого не происходит. Но расстояние в секундах между двумя последовательными полуночами — это не 86400, по крайней мере, два раза в год, когда вступает в действие летнее время. Сравнение двух дат на границе DST даст неправильный ответ.
Поэтому, даже если вы используете «взломать» форсирование всех временных дат даты до фиксированного часа, скажем, в полночь (это также делается неявно на разных языках и фреймах, когда вы указываете только день-месяц-год, а не час-минута-секунду; то же самое происходит с типом DATE в таких базах данных, как MySQL), широко используемая формула
вернется, скажем, 17, когда DATE1 и DATE2 находятся в одном сегменте DST года; но он может вернуться 17.042, а еще хуже — 16.958. Использование floor () или любого неявного усечения в integer затем преобразует то, что должно было быть от 17 до 16. В других случаях выражения типа «$ days> 17» вернут true для 17.042, даже если это указывает на то, что прошедший день счетчик — 18.
И все становится еще более уродливым, поскольку такой код не переносится на разных платформах, потому что некоторые из них могут применять секунды прыжка, а некоторые — нет . На тех платформах, которые делают , разница между двумя датами не будет 86400, а 86401, или, может быть, 86399. Таким образом, код, который работал в мае и фактически прошел все тесты, прорвется в следующем июне, когда 1299999 дней считаются 12 днями вместо 13. Две даты который работал в 2015 году, не будет работать в 2017 году — те же даты, и ни один год не является високосным годом. Но между 2018-03-01 и 2017-03-01 на тех платформах, которые ухаживают, 366 дней пройдут вместо 365, сделав 2017 год високосным.
Поэтому, если вы действительно хотите использовать временные метки UNIX:
используйте функцию round() , а не floor() .
в качестве альтернативы, не рассчитывайте разницы между D1-M1-YYY1 и D2-M2-YYY2. Эти даты будут действительно рассматриваться как D1-M1-YYY1 00:00:00 и D2-M2-YYY2 00:00:00. Скорее, конвертируйте между D1-M1-YYY1 22:30:00 и D2-M2-YYY2 04:30:00. Вы всегда получите остаток около двадцати часов. Это может стать двадцать один час или девятнадцать, а может быть, восемнадцать часов, пятьдесят девять минут тридцать шесть секунд. Независимо от того. Это большой запас, который останется там и останется положительным в обозримом будущем. Теперь вы можете усекать его с помощью floor() в безопасности.
Правильное решение, однако, чтобы избежать магических констант, округления кулджей и задолженности по обслуживанию, — это
использовать библиотеку времени (Datetime, Carbon, что угодно); не сворачивайте свои собственные
пишите всесторонние тестовые примеры, используя действительно злые даты — через границы DST, через високосные годы, через прыжки секунд и т. д., а также банальные даты. В идеале (призывы к дате времени бывают быстрыми !) Генерируют четыре года (и один день) даты, собирая их из строк, последовательно и гарантируя, что разница между первым днем и днем, прошедшим тестирование, неуклонно растет. Это гарантирует, что, если что-либо изменится в низкоуровневых процедурах и секундах прыжков, попытайтесь нанести ущерб, по крайней мере, вы узнаете .
регулярно проводите эти тесты вместе с остальной частью набора тестов. Это вопрос миллисекунды и может спасти вас буквально часами царапин на голове.
Независимо от вашего решения, протестируйте его!
Функция funcdiff ниже реализует одно из решений (как это принято, принятое) в реальном мире.
История ужасов: стоимость «экономии времени»
Это произошло несколько месяцев назад. Гениальный программист решил сэкономить несколько микросекунд при расчете, которое заняло не более тридцати секунд, подключив печально известный код «(MidnightOfDateB-MidnightOfDateA) / 86400» в нескольких местах. Это была настолько очевидная оптимизация, что он даже не документировал ее, и оптимизация прошла интеграционные тесты и скрывалась в коде несколько месяцев, и все это незамечено.
Это произошло в программе, которая рассчитывает заработную плату для нескольких продавцов, продавших самые продаваемые продавцы, причем наименьшее из которых имеет страшное много больше, чем целая скромная команда из пяти человек, составленная вместе. Однажды несколько месяцев назад, по причинам, которые мало что значили, ошибка ударила — и некоторые из этих парней получили один день целых полных комиссий. Они определенно не позабавились.
Бесконечно худшие, они потеряли (уже очень мало) вера, которую они имели в программе, не предназначенную для тайного приведения их в порядок, и притворились — и получили — полный подробный обзор кода с тестовыми примерами был запущен и прокомментирован в терминах непрофессионала (плюс много лечения красной ковровой дорожкой в следующие недели).
Что я могу сказать: с положительной стороны, мы избавились от большого технического долга и смогли переписать и реорганизовать несколько частей беспорядка спагетти, который вернулся к заражению COBOL в качающихся 90-х годах. Программа, несомненно, работает лучше сейчас, и есть намного больше информации для отладки, чтобы быстро получить нуль, когда что-то выглядит подозрительно. Полагаю, что только это последнее спасет, возможно, один или два человеко-дня в месяц в обозримом будущем.
На минусовой стороне вся броухаха стоила компании около 200 000 евро впереди — плюс лицо, плюс, несомненно, какая-то способность торговаться (и, следовательно, еще больше денег).
Парень, ответственный за «оптимизацию», сменил работу год назад, до катастрофы, но все же был разговор, чтобы подать в суд на него за ущерб. И с верхними эшелонами не получилось, что это была «вина последнего парня» — это было похоже на настройку для нас, чтобы вылечить эту проблему, и, в конце концов, мы все еще в собачьей упряжке и одна из команд планирует выйти.
Девяносто девять раз из ста, «взлом 86400» будет работать безупречно. (Например, в PHP, strtotime() игнорирует DST и сообщает, что между полуночи последней субботы октября и дня следующего понедельника прошло ровно 2 * 24 * 60 * 60 секунд, даже если это явно не так . и две неудачи с радостью сделают одно право).
Это, дамы и господа, был одним из примеров, когда этого не произошло. Как и в случае с подушками безопасности и ремнями безопасности, вам, возможно, никогда не понадобится сложность (и простота использования) DateTime или Carbon . Но день, когда вы (или день, когда вам придется доказывать, что вы об этом подумали), придет как вор ночью. Будь готов.
МОДЫ Grand Theft Auto V
Крупнейший сборник модов для Grand Theft Auto V и GTA San Andreas
Посчитать количество дней между датами php
Из БД извлекаются несколько строк с календарными периодами.
Нужно посчитать количество дней между конечной датой 1 строки и начальной датой 2 строки, конечной датой 2 строки и начальной датой 3 строки. И если не в одном промежутке дат кол-во дней не превышает 1-го, тогда сделать то-то.
Т.е. фактически проверить: существует ли разрыв дат между календарными периодами, либо они все числа идут подряд!
3 ответа 3
Можно таким образом (PHP):
Почему количество секунд делим на 60 * 60 * 24 ? Количество секунд поделив на 60 получим количество минут (в одной минуте шестьдесят секунд). Затем, поделив количество минут на 60 — получим количество часов (в одном часе шестьдесят минут). А поделив количество часов на 24 — получим количество дней (в одном дне двадцать четыре часа).
Пример проверки нахождения даты между двумя датами: PHP check if date between two dates
Стоит отметить некоторые замечания:
- strtotime — преобразует текстовое представление даты на английском языке в метку времени Unix.
- Метка времени Unix — это количество секунд, прошедших с 1 января 1970 года 00:00:00 UTC.
- strtotime — возвращает временную метку в случае успеха, иначе возвращается FALSE . До версии PHP 5.1.0 в случае ошибки эта функция возвращала -1 .
Сообщество, где люди делятся уникальным опытом
Вопросы и ответы по любой теме от IT сообщества
Помогаем строить карьеру в IT-индустрии
Биржа удаленной работы для IT-специалистов
Хабр Q&A — вопросы и ответы для IT-специалистов
Получайте ответы на вопросы по любой теме из области IT от специалистов в этой теме.
Как найти количество дней между двумя датами с помощью PHP?
Если вы используете PHP 5.3 > , это, безусловно, самый точный способ вычисления разницы:
Преобразуйте даты в временные метки unix, затем выровняйте один из другого. Это даст вам разницу в секундах, которую вы разделите на 86400 (количество секунд в день), чтобы дать вам приблизительное количество дней в этом диапазоне.
Если ваши даты указаны в формате 25.1.2010 , 25.1.2010 или 2010-01-25 , вы можете использовать функцию strtotime :
Используя ceil округляет количество дней до следующего полного дня. Вместо этого используйте floor если вы хотите получить количество полных дней между этими двумя датами.
Если ваши даты уже находятся в формате timestamp в формате unix, вы можете пропустить преобразование и просто выполнить $days_between . Для более экзотических форматов даты вам, возможно, придется выполнить какой-то пользовательский синтаксический анализ, чтобы получить правильное решение.
С PHP версии 5.3 и выше были добавлены новые функции даты / времени , чтобы получить разницу:
Результат, как показано ниже:
TL; DR не используют отметки времени UNIX. Не используйте time() . Если вы это сделаете, будьте готовы, если ваша надежность 98.0825% не даст вам. Используйте DateTime (или Carbon).
Правильный ответ – тот, который дал Сакшам Гупта (другие ответы также верны):
Или процедурно как однострочный:
Если вы действительно должны использовать отметки времени UNIX, установите часовой пояс на GMT, чтобы избежать большинства ловушек, описанных ниже.
Большинство ответов с использованием временных меток UNIX делают два предположения, которые, вместе взятые, могут привести к сценариям с неправильными результатами и небольшими ошибками, которые могут быть трудно отследить, и возникают даже дни, недели или месяцы после успешного развертывания.
Первая ошибка не учитывает, что, когда его спросили: «Сколько прошло дней со вчерашнего дня?», Компьютер может честно ответить на ноль, если между настоящим и мгновением, указанным «вчера», прошло менее одного дня .
Обычно при преобразовании «дня» в временную метку UNIX получается временная метка в полночь того дня.
Таким образом, между полуночами с 1 октября по 15 октября прошло пятнадцать дней. Но с 13:00 1 октября и 14:55 15 октября прошло пятнадцать дней минус 5 минут , и большинство решений, использующих floor() или выполняющих неявное целочисленное преобразование , сообщают на один день меньше, чем ожидалось .
Итак, «сколько дней назад был Ymd H: i: s»? даст неправильный ответ .
Вторая ошибка – один день – 86400 секунд. Это почти всегда верно – это бывает достаточно часто, чтобы не заметить время, когда этого не происходит. Но расстояние в секундах между двумя последовательными полуночами – это не 86400, по крайней мере, два раза в год, когда вступает в действие летнее время. Сравнение двух дат на границе DST снова даст неправильный ответ.
Поэтому, даже если вы используете «взломать» форсирование всех временных дат даты до фиксированного часа, скажем, в полночь (это также делается неявно на разных языках и фреймах, когда вы указываете только день-месяц-год, а не час-минута-секунда) , широко используемая формула
или пол (время () – strtotime ($ somedate)) / 86400
вернется, скажем, 17, когда DATE1 и DATE2 находятся в одном сегменте DST года; но он может вернуться 17.042, а еще хуже – 16.958. Использование floor () или любого неявного усечения в integer затем преобразует то, что должно было быть от 17 до 16.
И все становится еще более уродливым, поскольку такой код не переносится на разных платформах, потому что некоторые из них могут применять секунды прыжка, а некоторые – нет . На тех платформах, которые делают , разница между двумя датами не будет 86400, а 86401, или, может быть, 86399. Таким образом, код, который работал в мае и фактически прошел все тесты, прорвется в следующем июне, когда 1299999 дней считаются 12 днями вместо 13. Две даты который работал в 2015 году, не будет работать в 2017 году – те же даты, и ни один год не является високосным годом. Но между 2018-01-01 и 2017-01-01 на тех платформах, которые заботятся, 366 дней пройдут вместо 365, сделав 2017 год високосным.
Поэтому, если вы действительно хотите использовать временные метки UNIX:
используйте функцию round() , а не floor() .
в качестве альтернативы, не рассчитывайте разницы между D1-M1-YYY1 и D2-M2-YYY2. Эти даты будут действительно рассматриваться как D1-M1-YYY1 00:00:00 и D2-M2-YYY2 00:00:00. Скорее, конвертируйте между D1-M1-YYY1 22:30:00 и D2-M2-YYY2 04:30:00. Вы всегда получите остаток около двадцати часов. Это может стать двадцать один час или девятнадцать, а может быть, восемнадцать часов, пятьдесят девять минут тридцать шесть секунд. Не важно. Это большой запас, который останется там и останется положительным в обозримом будущем. Теперь вы можете усекать его с помощью floor() в безопасности.
Правильное решение состоит в том, чтобы
использовать библиотеку времени (Datetime, Carbon, что угодно); не сворачивайте свои собственные
пишите всесторонние тестовые примеры, используя действительно злые даты – через границы DST, через високосные годы, через прыжки секунд и т. д., а также банальные даты. В идеале (призывы к дате времени бывают быстрыми !) Генерируют четыре года (и один день) даты, собирая их из строк, последовательно и гарантируя, что разница между первым днем и днем, прошедшим тестирование, неуклонно растет. Это гарантирует, что, если что-либо изменится в низкоуровневых процедурах и секундах прыжков, попытайтесь нанести ущерб, по крайней мере, вы узнаете .
регулярно проводите эти тесты вместе с остальной частью набора тестов. Это вопрос миллисекунды и может спасти вас буквально часами царапин на голове.
Функция funcdiff ниже реализует одно из решений (как это принято, принятое) в реальном мире.
Это произошло несколько месяцев назад. Гениальный программист решил сэкономить несколько микросекунд при расчете, которое заняло не более тридцати секунд, подключив печально известный код «(MidnightOfDateB-MidnightOfDateA) / 86400» в нескольких местах. Это была настолько очевидная оптимизация, что он даже не документировал ее, и оптимизация прошла интеграционные тесты и скрывалась в коде несколько месяцев, и все это незамечено.
Это произошло в программе, которая рассчитывает заработную плату для нескольких продавцов, продавших самые продаваемые продавцы, причем наименьшее из которых имеет страшное много больше, чем целая скромная команда из пяти человек, составленная вместе. Однажды несколько месяцев назад, по причинам, которые мало что значили, ошибка ударила – и некоторые из этих парней получили один день целых полных комиссий. Они определенно не позабавились.
Бесконечно худшие, они потеряли (уже очень мало) вера, которую они имели в программе, не предназначенную для тайного приведения их в порядок, и притворились – и получили – полный подробный обзор кода с тестовыми примерами был запущен и прокомментирован в терминах непрофессионала (плюс много лечения красной ковровой дорожкой в следующие недели).
Что я могу сказать: с положительной стороны, мы избавились от большого технического долга и смогли переписать и реорганизовать несколько частей беспорядка спагетти, который вернулся к заражению COBOL в качающихся 90-х годах. Программа, несомненно, работает лучше сейчас, и есть намного больше информации для отладки, чтобы быстро получить нуль, когда что-то выглядит подозрительно. Полагаю, что только это последнее спасет, возможно, один или два человеко-дня в месяц в обозримом будущем.
На минусовой стороне вся броухаха стоила компании около 200 000 евро впереди – плюс лицо, плюс, несомненно, какая-то способность торговаться (и, следовательно, еще больше денег).
Парень, ответственный за «оптимизацию», сменил работу год назад, до катастрофы, но все же был разговор, чтобы подать в суд на него за ущерб. И с верхними эшелонами не получилось, что это была «вина последнего парня» – это было похоже на настройку для нас, чтобы вылечить эту проблему, и, в конце концов, мы все еще в собачьей упряжке и одна из команд планирует выйти.
Девяносто девять раз из ста, «взлом 86400» будет работать безупречно. (Например, в PHP, strtotime() игнорирует DST и сообщает, что между полуночи последней субботы октября и дня следующего понедельника прошло ровно 2 * 24 * 60 * 60 секунд, даже если это явно не так … и две неудачи с радостью сделают одно право).
Это, дамы и господа, был одним из примеров, когда этого не произошло. Как и в случае с подушками безопасности и ремнями безопасности, вам, возможно, никогда не понадобится сложность (и простота использования) DateTime или Carbon . Но день, когда вы (или день, когда вам придется доказывать, что вы об этом подумали), придет как вор ночью. Приготовься.
Простота использования date_diff
Ну, выбранный ответ не самый правильный, потому что он выйдет за пределы UTC. В зависимости от часового пояса ( списка ) могут быть корректировки времени, создающие дни «без» 24 часов, и это приведет к сбою расчета (60 * 60 * 24).
Поэтому правильным решением будет использование DateTime
Теперь он работает
Я использую Carbon в моих проектах композитора для этой и подобных целей.
Это было бы так просто:
и, при необходимости:
Если у вас есть время в секундах (отметка времени Unix Unix), вы можете просто вычесть время и разделить на 86400 (секунды в день)
Если вы хотите повторить все дни между датой начала и окончания, я придумал следующее:
Если вы используете MySql
Вот моя улучшенная версия, которая показывает 1 год (ы) 2 Месяцев (ы) 25 дней (ы), если 2-й параметр передан.
Попробуйте использовать углерод
Также вы можете использовать
для создания объекта Carbon date с использованием заданной строки timestamp.
использовал вышеуказанный код очень просто. Благодарю.