Intereting Posts
php strtotime «последний понедельник», если сегодня понедельник? Установить ini max_execution_time не работает Автоматически запускать определенные тесты при смене файла? Как избежать символов Junk / garbage при чтении данных с нескольких языков? Создать пользователя с подготовленным заявлением MySQLi Google API php client: отправить etag Графические диаграммы для HTML-задач Как получить последнюю запись в таблице базы данных MySQL с помощью PHP? Как получить роль пользователя в Yii2? загрузить несколько файлов на php-сервер с помощью командной строки curl Проблема с кодировкой php: file_get_contents как отображать ошибку MySql в php Любая идея для отправки POST для функции (url) через jquery-fancybox? Почему я получаю «не могу изменить заголовки заголовков заголовков, уже отправленных с помощью registration_model» в codeigniter? Правильно закодируйте символы в почтовой форме PHP («Я» превращается в «I \ m»)

Не удается получить предыдущий месяц из DateTime в PHP. Является ли это (довольно большой) ошибкой?

Мне нужно создать функции в PHP, которые позволяют мне увеличивать / уменьшать количество единиц времени. В частности, мне нужно иметь возможность перейти к следующему / предыдущему месяцу с текущего.

Я думал, что могу сделать это, используя DateTime :: add / sub (P1M). Однако, когда вы пытаетесь получить предыдущий месяц, это испортится, если значение даты = 31- выглядит так, будто оно пытается подсчитать 30 дней, а не уменьшать значение месяца !:

$prevMonth = new DateTime('2010-12-31'); 

Попробуйте уменьшить месяц:

 $prevMonth->sub(new DateInterval('P1M')); // = '2010-12-01' $prevMonth->add(DateInterval::createFromDateString('-1 month')); // = '2010-12-01' $prevMonth->sub(DateInterval::createFromDateString('+1 month')); // = '2010-12-01' $prevMonth->add(DateInterval::createFromDateString('previous month')); // = '2010-12-01' 

Это, безусловно, похоже на неправильное поведение. У кого-нибудь есть понимание? Благодаря-

ПРИМЕЧАНИЕ. Версия PHP 5.3.3

(Кредит на самом деле принадлежит Алексу за указание на это в комментариях)

Проблема не в PHP, а в GNU, как описано здесь:

Относительные элементы в строках даты

Ключевым моментом здесь является дифференциация понятия «эта дата в прошлом месяце», которая, поскольку месяцы являются «нечеткими единицами» с различным количеством дат, невозможно определить для даты, например, 31 декабря (поскольку 31 ноября не существует) , и понятие «в прошлом месяце, независимо от даты».

Если нас интересует только предыдущий месяц, единственный способ дать правильный расчет DateInterval – сбросить значение даты до 1-го или другого числа, которое будет иметь каждый месяц.

Что действительно меня поражает, так это то, как недокументированная эта проблема, в PHP и в других местах, – учитывая, насколько сильно зависит от времени программное обеспечение, зависящее от даты.

Вот безопасный способ справиться с этим:

 /* Handles month/year increment calculations in a safe way, avoiding the pitfall of 'fuzzy' month units. Returns a DateTime object with incremented month/year values, and a date value == 1. */ function incrementDate($startDate, $monthIncrement = 0, $yearIncrement = 0) { $startingTimeStamp = $startDate->getTimestamp(); // Get the month value of the given date: $monthString = date('Y-m', $startingTimeStamp); // Create a date string corresponding to the 1st of the give month, // making it safe for monthly/yearly calculations: $safeDateString = "first day of $monthString"; // Increment date by given month/year increments: $incrementedDateString = "$safeDateString $monthIncrement month $yearIncrement year"; $newTimeStamp = strtotime($incrementedDateString); $newDate = DateTime::createFromFormat('U', $newTimeStamp); return $newDate; } 

Самый простой способ добиться этого, на мой взгляд, – использовать mktime.

Как это:

 $date = mktime(0,0,0,date('m')-1,date('d'),date('Y')); echo date('dm-Y', $date); 

Greetz Michael

Документацию ps mktime можно найти здесь: http://nl2.php.net/mktime

Вы можете пойти на старую школу и просто использовать функции даты и strtotime.

 $ date = '2010-12-31';
 $ monthOnly = date ('Y-m', strtotime ($ date));
 $ previousMonth = date ('Ym-d', strtotime ($ monthOnly. '-1 month'));

(Это может быть комментарий, но это долго для одного)

Вот как это работает на Windows 7 Apache 2.2.15 с PHP 5.3.3:

 <?php $dt = new DateTime('2010-12-31'); $dt->sub(new DateInterval('P1M')); print $dt->format('Ym-d').'<br>'; $dt->add(DateInterval::createFromDateString('-1 month')); print $dt->format('Ym-d').'<br>'; $dt->sub(DateInterval::createFromDateString('+1 month')); print $dt->format('Ym-d').'<br>'; $dt->add(DateInterval::createFromDateString('previous month')); print $dt->format('Ym-d').'<br>'; ?> 2010-12-01 2010-11-01 2010-10-01 2010-09-01 

Так что это, похоже, подтверждает, что это связано с GNU выше.

Примечание: IMO приведенный ниже код работает должным образом.

  $dt->sub(new DateInterval('P1M')); 

Текущий месяц: 12
В прошлом месяце: 11
Количество дней в 12-м месяце: 31
Количество дней в 11-м месяце: 30
31 декабря – 31 день = 31 ноября
31 ноября = Ноябрь 1 + 31 Дней = 1 декабря (30 + 1)