2013-05-08 5 views
1

Кажется, что вы не можете использовать strotime, если вам нужны надежные и точные манипуляции с датой. Например, если месяц имеет 31 день, то оказывается, что strtotime просто минус 30 дней, а не целый месяц.Удаление ровно одного месяца с даты

Так, например, если $event["EndDate"] равно "2013-10-31 00:00:01", следующий код:

echo date("Y/n/j", strtotime('-1 month', strtotime($event["EndDate"])); 

Выходы: 2013/10/1 вместо 2013/09/30.

ВОПРОС: Теперь, как я знаю, как НЕ делать это, есть ли другой, более точный способ сделать PHP вычитанием (или добавлением) ровно целым месяцем, а не только 30 дней?

+5

Если вы работаете с событиями с датами и временем, а затем сделать жизнь проще для себя и использовать объекты DateTime –

+2

Я думаю, что реальная проблема заключается в том, что это вычитание одного месяца с Oct.31, возвращаясь Sept.31, который не существует и вместо этого преобразуется в Oct.1. Если я возьму ваш код и отправлю его 29 октября, я получу 29 сентября, как и ожидалось. – Blazemonger

+0

http://stackoverflow.com/questions/9087462/php-strtotime-is-not-returning-the-correct-month – Lawson

ответ

2

Основная проблема заключается в том, что 2013/09/31 не существует, поэтому лучше использовать first day или last day предыдущего месяца.

$date = new DateTime("2013-10-31 00:00:01"); 
$date->modify("last day last month"); 
echo $date->format("Y/n/j"); // 2013/9/30 

Когда дата 2013-10-15

$date = new DateTime("2013-10-15 00:00:01"); 
$day = $date->format("d"); 
$year = $date->format("Y"); 

$date->modify("last day last month"); 
$month = $date->format("m"); 

if (checkdate($month, $day, $year)) { 
    $date->setDate($year, $month, $day); 
} 

echo $date->format("Y/n/j"); // 2013-9-15 
+0

Это нехорошо, если дата 2013-10-15 - но сейчас я вижу проблему. Черт! –

+0

'DateTime' очень гибкий. Я бы обновил свой код, чтобы показать, как вы можете это достичь ... – Baba

1

Вы говорите: -

кажется, что вы не можете использовать strotime, если вам нужно надежное и точное манипулирование даты

Вы можете, вам просто нужно знать, как он себя ведет. Ваш вопрос побудил меня провести пару тестов.


PHP не просто вычесть 30 дней с даты, когда вычитая месяц, хотя кажется, что он делает из одного случая вы смотрите. На самом деле мой тест here предполагает, что он добавляет 31 день к началу предыдущего месяца (результат 3 марта предлагает это мне) в этом случае.

$thirtyOnedayMonths = array(
    1, 3, 5, 7, 8, 10, 12 
); 

$oneMonth = new \DateInterval('P1M'); 
$format = 'Y-m-d'; 

foreach($thirtyOnedayMonths as $month){ 
    $date = new \DateTime("2013-{$month}-31 00:00:01"); 
    var_dump($date->format($format)); 
    $date->sub($oneMonth); 
    var_dump($date->format($format)); 
} 

Есть 31 дней между 2013-11-12 и 2013-10-12 и PHP вычисляет месяц вычитание правильно, как можно видеть here.

$date = new \DateTime('2013-11-12 00:00:01'); 
var_dump($date); 
$interval = new DateInterval('P1M'); 
$date->sub($interval); 
var_dump($date); 

В вашем конкретном случае 2013-10-31 - 1 месяц - 2013-09-31, которого нет. Любая функция даты/времени должна вернуть действительную дату, которой нет в 2013-09-31.

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

Как только вы знаете ожидаемое поведение, вы можете запрограммировать его соответствующим образом. Если текущее поведение не соответствует вашему варианту использования, вы можете расширить класс DateTime, чтобы обеспечить поведение, которое работает для вас.

Я предположил, что strtotime и DateTime::sub() ведут себя одинаково, this test предлагает им это сделать.

$thirtyOnedayMonths = array(
    1, 3, 5, 7, 8, 10, 12 
); 

$format = 'Y-m-d'; 

foreach($thirtyOnedayMonths as $month){ 
    $date = date($format, strtotime('-1 month', strtotime("2013-{$month}-31 00:00:01"))); 
    var_dump($date); 
} 
Смежные вопросы