php дней между двумя списками дат

Вы знаете, в чем проблема, глядя на код?

Буду рад, если вы мне поможете:

list($from_day,$from_month,$from_year)    = explode(".","27.09.2012");
list($until_day,$until_month,$until_year) = explode(".","31.10.2012");

$iDateFrom = mktime(0,0,0,$from_month,$from_day,$from_year);
$iDateTo   = mktime(0,0,0,$until_month,$until_day,$until_year);

while ($iDateFrom <= $iDateTo) {
    print date('d.m.Y',$iDateFrom)."<br><br>";
    $iDateFrom += 86400; 
}

Дата написания одной и той же задачи 2 раза

Октябрь (31) для написания 2 раза в истории сводит концы с концами 30 октября :(

27.09.2012

28.09.2012

...

26.10.2012

27.10.2012

[[28.10.2012]]

[[28.10.2012]]

29.10.2012

30.10.2012


person darkofpain    schedule 26.09.2012    source источник
comment
Я скопировал и вставил ваш код, и у меня нет никаких проблем....   -  person cegfault    schedule 27.09.2012


Ответы (4)


  1. Ваша проблема в том, что вы установили время на 00:00:00, установите его на 12:00:00. Это связано с летним временем.
  2. Прекратите использовать функцию date(), используйте классы Date и Time.

Решение (PHP >= 5.4):

$p = new DatePeriod(
    new DateTime('2012-09-27'),
    new DateInterval('P1D'),
    (new DateTime('2012-10-31'))->modify('+1 day')
);
foreach ($p as $d) {
    echo $d->format('d.m.Y') . "\n";
}

Решение (PHP ‹ 5.4)

$end = new DateTime('2012-10-31');
$end->modify('+1 day');
$p = new DatePeriod(
    new DateTime('2012-09-27'),
    new DateInterval('P1D'),
    $end
);
foreach ($p as $d) {
    echo $d->format('d.m.Y') . "\n";
}
person Glavić    schedule 26.09.2012
comment
Вы уверены, что это проблема с его кодом? Я только что запустил тот же код в своей среде с PHP версии 5.3.13, и он работал нормально. - person Flosculus; 27.09.2012
comment
есть проблема октября, привлечение 31 - до 30 написал :( - person darkofpain; 27.09.2012
comment
Это потому, что летнее время. - Предоставленный - person Flosculus; 27.09.2012
comment
@BatuhanBerkayGöksu: я исправил код, так что теперь он должен работать. Но это php ›= 5.4.x. Если у вас его нет, инициализируйте последний параметр DatePeriod снаружи, например $end = new DateTime('2012-10-31'); $end->modify('+1 day'); - person Glavić; 27.09.2012
comment
@glavic [26-Sep-2012 20:39:32 UTC] Ошибка синтаксического анализа PHP: синтаксическая ошибка, неожиданный T_OBJECT_OPERATOR в C:\Program Files (x86)\Zend\Apache2\htdocs\calendar\index.php в строке 134 строка 134 (новый DateTime('2012-10-31'))->изменить('+1 день') - person darkofpain; 27.09.2012
comment
Как я уже говорил в своем предыдущем комментарии (я написал вам решение), это стиль PHP 5.4.... Я обновил свой ответ для PHP ‹ 5.4. - person Glavić; 27.09.2012

У вас проблемы с переходом на летнее время. Добавление секунд из одной временной метки в другую подвержено проблемам, связанным с такими граничными условиями (хорошо, високосные дни могут быть проблематичными). Вы должны привыкнуть к использованию PHP-объектов DateTime и DateInterval. Это упрощает работу с датами.

$start_date = new DateTime('2012-09-27');
$end_date = new DateTime('2012-10-31');
$current_date = clone $start_date;
$date_interval = new DateInterval('P1D');

while ($current_date < $end_date) {
    // your logic here

    $current_date->add($date_interval);
}
person Mike Brant    schedule 26.09.2012
comment
[26-Sep-2012 20:42:48 UTC] Перехватываемая фатальная ошибка PHP: объект класса DateTime не удалось преобразовать в строку в C:\Program Files (x86)\Zend\Apache2\htdocs\calendar\index.php в строка 139 строка 139 $current_date-›add($date_interval); $start_date = новый DateTime('2012-08-27'); $end_date = новый DateTime('2012-09-31'); $current_date = клон $start_date; $date_interval = новый DateInterval('P1D'); while ($current_date ‹ $end_date) { print $current_date; $current_date-›добавить($date_interval); } - person darkofpain; 27.09.2012
comment
Ваша ошибка в print $current_date. Вам нужно использовать что-то вроде print $current_date->format('d.m.Y'); - person Mike Brant; 27.09.2012

Моя идея для решения этой проблемы была бы примерно такой;

$firstDate = "27.09.2012";
$secondDate = "31.10.2012";

$daysDifference = (strtotime($secondDate) - strtotime($firstDate)) / (60 * 60 * 24);
$daysDifference = round($daysDifference);

for ($i = 0; $i <= $daysDifference; $i++)
{
    echo date("d.m.Y", strtotime('+'.$i.' day', strtotime($firstDate))) . "<BR>";
}

Это должно решить вашу проблему и быть намного проще для чтения (имхо). Я только что протестировал код, и он выводит все даты и не удваивает. Это также избавит вас от всех несоответствий летнего времени.

person Roy Jacobs    schedule 26.09.2012

Я не знаю, откуда вы, но, вероятно, вы переключаетесь на летнее время в своем часовом поясе (где я живу 4 ноября - ровно через неделю после 28 октября). Вы не можете полагаться на то, что день длится ровно 86400 секунд.

Если вы увеличиваете цикл с помощью mktime, все должно быть в порядке:

list($from_day,$from_month,$from_year)    = explode(".","27.09.2012");
list($until_day,$until_month,$until_year) = explode(".","31.10.2012");

$iDateFrom = mktime(0,0,0,$from_month,$from_day,$from_year);
$iDateTo   = mktime(0,0,0,$until_month,$until_day,$until_year);

while ($iDateFrom <= $iDateTo)
{
    print date('d.m.Y',$iDateFrom)."<br><br>";
    $from_day = $from_day + 1;
    $iDateFrom = mktime(0,0,0,$from_month,$from_day,$from_year);
}

Несмотря на то, что $from_day, скорее всего, превысит 31, mktime сделает за вас математическое преобразование. (т.е. 32 дня в 31-дневном месяце = 1-й день следующего месяца)

РЕДАКТИРОВАТЬ: извините, у меня было приращение не в том месте.

person chops    schedule 26.09.2012
comment
пишет первые два раза с 27.09.2012 :( - person darkofpain; 27.09.2012
comment
Моя вина, я поставил инкремент не в том месте. Исправлено. - person chops; 27.09.2012