Как на PHP корректно прибавить месяц к дате
Как на PHP корректно прибавить месяц к дате
Одна из интересных задач, с которой мне приходилось сталкиваться на практике при работе с датами на PHP, это так называемый "календарный месяц". То есть некий интервал дат, отличающийся на месяц. Если дата находится где-то в середине или в начале месяца, то никаких сложностей, просто увеличиваем номер месяца на единицу, при необходимости корректируем год. А проблема начинается в тех случаях, когда дата начала интервала приходится на какое-нибудь число в конце месяца. Просто увеличить значение месяца на следующий, оставив число без изменений, нельзя, полученная дата может оказаться несуществующей. Добавлять 30 или 31 день тоже некорректно, в коротком феврале итоговая дата после такого прибавления перемахнет на начало марта. Вот для наглядности несколько примеров, чтобы было понятно, о чем идет речь:
Code (PHP) : Убрать нумерацию
- //------------------------------------------------------
- // Дата в начале или в середине месяца
- //------------------------------------------------------
- echo date('d.m.Y',strtotime('2015-01-12 +1 month'));
- // 12.02.2015 - правильно
- //------------------------------------------------------
- // Дата в конце месяца
- //------------------------------------------------------
- echo date('d.m.Y',strtotime('2015-01-29 +1 month'));
- // 01.03.2015 - неправильно! Ожидалось 28.02.2015
- echo date('d.m.Y',strtotime('2015-01-31 +1 month'));
- // 03.03.2015 - неправильно! Ожидалось 28.02.2015
- echo date('d.m.Y',strtotime('2015-11-30 +1 month'));
- // 30.12.2015 - неправильно! Ожидалось 31.12.2015
Конечно, окончательное решение зависит от поставленной задачи и от воли начальства. Например,
Code (PHP) : Убрать нумерацию
- //----------------------------------------------------------------------
- // Добавление 1 календарного месяца к TIMESTAMP
- //----------------------------------------------------------------------
- function add_month($time) {
- $d=date('j',$time); // день
- $m=date('n',$time); // месяц
- $y=date('Y',$time); // год
- // Прибавить месяц
- $m++;
- if ($m>12) { $y++; $m=1; }
- // Это последний день месяца?
- if ($d==date('t',$time)) {
- $d=31;
- }
- // Открутить дату до последнего дня месяца
- if (!checkdate($m,$d,$y)){
- $d=date('t',mktime(0,0,0,$m,1,$y));
- }
- // Вернуть новую дату в TIMESTAMP
- return mktime(0,0,0,$m,$d,$y);
- }
Code (PHP) : Убрать нумерацию
- //------------------------------------------------------
- // Корректная дата в конце месяца
- //------------------------------------------------------
- echo date('d.m.Y',add_month(strtotime('2015-01-29')));
- // 28.02.2015 - теперь все правильно
- echo date('d.m.Y',add_month(strtotime('2015-01-31')));
- // 28.02.2015 - тоже правильно
- echo date('d.m.Y',add_month(strtotime('2015-11-30')));
- // 31.12.2015 - все правильно, прибавлен календарный месяц
Code (PHP) : Убрать нумерацию
- //---------------------------------------------------------------------
- // Добавление одного или нескольких календарных месяцев к TIMESTAMP
- //---------------------------------------------------------------------
- function add_month($time, $num=1) {
- $d=date('j',$time); // день
- $m=date('n',$time); // месяц
- $y=date('Y',$time); // год
- // Прибавить месяц(ы)
- $m+=$num;
- if ($m>12) {
- $y+=floor($m/12);
- $m=($m%12);
- // Дополнительная проверка на декабрь
- if (!$m) {
- $m=12;
- $y--;
- }
- }
- // Это последний день месяца?
- if ($d==date('t',$time)) {
- $d=31;
- }
- // Открутить дату, пока она не станет корректной
- while(true) {
- if (checkdate($m,$d,$y)){
- break;
- }
- $d--;
- }
- // Вернуть новую дату в TIMESTAMP
- return mktime(0,0,0,$m,$d,$y);
- }
Просмотров: 17348 | Комментариев: 6
Метки: PHP, полезные функции
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(16.05.2018 в 06:54):
Коля, статью совсем не читал, да?
Коля
(16.05.2018 в 02:34):
$tomorrow = mktime(0, 0, 0, date("m") , date("d")+1, date("Y"));
$lastmonth = mktime(0, 0, 0, date("m")-1, date("d"), date("Y"));
$nextyear = mktime(0, 0, 0, date("m"), date("d"), date("Y")+1);
Получил unix метку, а дальше делай что хочешь и никогда не ошибешься.
$lastmonth = mktime(0, 0, 0, date("m")-1, date("d"), date("Y"));
$nextyear = mktime(0, 0, 0, date("m"), date("d"), date("Y")+1);
Получил unix метку, а дальше делай что хочешь и никогда не ошибешься.
Максим
(31.01.2016 в 09:27):
Спасибо за функцию. А то столько решений однотипных, которые не решают вопрос с концом месяца
user
(27.11.2015 в 22:57):
Я об этом и говорю. Как я бы делал - получилась бы громадная неэлегантная процедура, ни грамма не оптимальная и даже чуток туповатая. Главное чтоб считала верно.
)) воспроизвести человеческий интеллект, лругими словами.
(Не путать с AI).
А вообще, в случае с предоставлением услуг наверное логичнее было бы взымать оплату поденно. Ну, то уж хозяин-барин.
)) воспроизвести человеческий интеллект, лругими словами.
(Не путать с AI).
А вообще, в случае с предоставлением услуг наверное логичнее было бы взымать оплату поденно. Ну, то уж хозяин-барин.
ManHunter
(27.11.2015 в 21:25):
Считать Пасху на 65525-й год и выставлять клиентам счета за календарный месяц услуг - это несколько разные задачи. Так что понятие "правильно" в разных системах счисления может сильно отличаться. Особенно когда начальству придется объяснять клиенту, почему это у него сервер отключили не 31-го, а 28-го, и после этого разницу за простой и неустойку вычтут из премии, вот тогда все сразу встанет на свои места.
user
(27.11.2015 в 20:08):
Между прочим, это, пожалуй, и есть самый нормальный вариант.
Прописать в алгоритме все правила изменения дат и задать начало (например, сегодня, когда ни у кого нет сомнения, что нвнче 27 ноября, пятница). А дальше пускай программа крутит алгоритм сколько надо - всё равно понадобиться может плюс-минус 50 лет, не больше, а это ерунда.
Возился когда-то с календарями, и понял, что все формулы это фуфло. Нет нормальных. Вернее, нормальная только та, что я описал - но она возможна лишь с применением ЭВМ (чем мы и занимаемся).
Куча ошибок в определении дат тому подтверждение.
Вот, между прочим, рекомендую - прога печатает настенный календарь любого года. Вплоть до 65535-го:
old-dos.ru/dl.php?id=6527
Там в архиве для примера официальный церковный календарь до 2050-го года, где пасха дважды приходится на понедельник. Считали..
Добавить комментарий
Заполните форму для добавления комментария