Php цикл по времени
БлогNot. PHP: Как организовать цикл по дням века или Даты-палиндромы
PHP: Как организовать цикл по дням века или Даты-палиндромы
Если не заморачиваться устаревшими решениями (для нашего потребуется версия PHP не ниже 5.2.0), проще всего создать два объекта DateTime, отмечающие начало и конец нужного периода времени, создать интервал DateInterval с нужным шагом по времени (необязательно один день) и организовать простой цикл, как в показанном ниже коде.
Чтобы код решал хоть какую-то задачку, заставим его заодно определить количество «палиндромных» дат в XXI веке (даты, которые читаются одинаково слева направо и справа налево, в отличие от «зеркальных дней», где мы понимали палиндромность даты иначе, с перестановкой цифр) и вывести их все.
Если век, как и положено, начинается с 1 января 2001-го года, день пишется без лидирующего нуля, а месяц — с лидирующим нулём, то для формата даты «день-месяц-год» у меня получилось 29 зеркальных дней, причём, последним из них будет 29 февраля:
10.02.2001 20.02.2002 11.02.2011 1.10.2011 21.02.2012 2.10.2012 3.10.2013 4.10.2014 5.10.2015 6.10.2016 7.10.2017 8.10.2018 9.10.2019 12.02.2021 22.02.2022 13.02.2031 23.02.2032 14.02.2041 24.02.2042 15.02.2051 25.02.2052 16.02.2061 26.02.2062 17.02.2071 27.02.2072 18.02.2081 28.02.2082 19.02.2091 29.02.2092
Вот код скрипта, решающего задачу и показывающего пример организации цикла по дням на PHP:
format('jmY'); if ($s==strrev($s)) < $cnt++; echo $start->format('j.m.Y').' '; > $start->add($interval); > while ($start<=$end); echo '
All: '.$cnt; ?>
Любопытно, что если день писать с лидирующим нулём (‘dmY’ вместо ‘jmY’ в формате даты), палиндромных дат всё равно будет 29 за век, но они будут не теми же:
10.02.2001 20.02.2002 01.02.2010 11.02.2011 21.02.2012 02.02.2020 12.02.2021 22.02.2022 03.02.2030 13.02.2031 23.02.2032 04.02.2040 14.02.2041 24.02.2042 05.02.2050 15.02.2051 25.02.2052 06.02.2060 16.02.2061 26.02.2062 07.02.2070 17.02.2071 27.02.2072 08.02.2080 18.02.2081 28.02.2082 09.02.2090 19.02.2091 29.02.2092
Без лидирующих нулей и у дня, и у месяца (формат даты ‘jnY’), «даты-перевёртыши» всё равно будут, но только 9 за весь век:
1.10.2011 2.10.2012 3.10.2013 4.10.2014 5.10.2015 6.10.2016 7.10.2017 8.10.2018 9.10.2019
Наконец, если кому-то придёт в голову писать день с лидирующим днём, а месяц — нет (‘dnY’), искомых дат, конечно, не будет совсем.
17.03.2019, 11:36 [2588 просмотров]
Перебор дат в заданном диапазоне на php.
На днях возникла задача на перебор дат в заданном диапазоне на php. Точнее — нужно было создать функцию, которая на входе принимала дату (в двух вариантах: день, месяц, год или месяц и год), а на выходе выдавала все даты месяца, который принимался в качестве аргумента, начиная с первого дня месяца, либо же с заданного, если он передается функции.
Например, передается дата 09-12-2013. Функция должна создать массив с датами, начиная с 2013-12-09 по 2013-12-31. Если же передается дата без дня, например, 12-2013, то возвращается массив дат с 2013-12-01 по 2013-12-31.
Основная трудность — это наличие различного количества дней в месяцах, поэтому мы не можем просто задать цикл из 30 или 31-го дней. Должен быть учет всех этих вариаций и наличие 29-го февраля (раз в 4 года). Но решение оказалось простым. Вот, собственно говоря, сама функция:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
function getDatesArray($day = null, $month, $year) < //инициализируем массив, в котором будем сохранять даты $dates = array(); //определяем день старта if ($day) < $date = $year . '-' . $month . '-' . $day; >else < $date = $year . '-' . $month . '-01'; >//заполняем массив датами do < $dates[] = $date; echo $date . "
"; $date = date('Y-m-d', strtotime($date . ' + 1 days')); $currDateArr = explode('-', $date); > while ($month == $currDateArr[1]); >
Для получения нового дня, используем простое выражение strtotime($date . ‘ + 1 days’). Выход из цикла осуществляется проверкой равенства месяца текущей (новой) даты и заданного месяца.
Если мы вызовем функцию со следующими аргументами:
то получим даты:
2013-10-01
2013-10-02
2013-10-03
…
2013-10-31
Встроенные в php функции по форматированию даты сами определяют, сколько дней в том или ином месяце.
P.S. Если у вас есть вариант более лаконичный — пишите в комментариях:)
Loop through all months in a date range?
If I have a start date (say 2009-02-01 ) and an end date (say 2010-01-01 ), how can I create a loop to go through all the dates (months) in the range?
8 Answers 8
$start = $month = strtotime('2009-02-01'); $end = strtotime('2011-01-01'); while($month
Relative month values are calculated based on the length of months that they pass through. An example would be «+2 month 2011-11-30», which would produce «2012-01-30». This is due to November being 30 days in length, and December being 31 days in length, producing a total of 61 days.
I tried this snippet and it does not work properly. If your start date is the end of the month and the end date is the start of the 3rd month. For example: 2014-08-31 — 2014-10-01
Example of DateTime, DateInterval and DatePeriod class combination :
$start = new DateTime('2009-02-01'); $interval = new DateInterval('P1M'); $end = new DateTime('2011-01-01'); $period = new DatePeriod($start, $interval, $end); foreach ($period as $dt) < echo $dt->format('F Y') . PHP_EOL; >
The accepted answer is not the proper way.
I tried this snippet and it does not work properly. If your start date is the end of the month and the end date is the start of the 3rd month.
For example: 2014-08-31 — 2014-10-01
$start = new DateTime('2010-12-02'); $start->modify('first day of this month'); $end = new DateTime('2012-05-06'); $end->modify('first day of next month'); $interval = DateInterval::createFromDateString('1 month'); $period = new DatePeriod($start, $interval, $end); foreach ($period as $dt) < echo $dt->format("Y-m") . "
\n"; >
$start = strtotime('2011-09-01'); $end = strtotime('2013-12-01'); while($start < $end) < echo date('F Y', $start) . '
'; $start = strtotime("+1 month", $start); >
I like the simplicity of the accepted answer, but as 3s2ng, it doesn’t always work. So I tweeked it like this:
$start = strtotime('2009-02-01'); $startmoyr = date('Y', $start) . date('m', $start); $end = strtotime('2013-12-01'); $endmoyr = date('Y', $end) . date('m', $end); while ($startmoyr "; $start = strtotime("+1month", $start); $startmoyr = date('Y', $start) . date('m', $start); >
Based on Gordon’s response this is the way I actually work when you need to get all the months between.
$end = strtotime(date("Y-m-01")); $start = $month = strtotime("-12 months", $end); while ( $month
This is the result if I execute this code now:
2018-05-01 2018-06-01 2018-07-01 2018-08-01 2018-09-01 2018-10-01 2018-11-01 2018-12-01 2019-01-01 2019-02-01 2019-03-01 2019-04-01
Notice that this doesn’t include the current month. If you need to include current month, you can set the «$end» variable to the first day of the next month.
$current_first_day_of_the_month = date("Y-m-01"); $end = strtotime("$current_first_day_of_the_month +1 month"); $start = $month = strtotime("-12 months", $end);
DatePeriod::__construct
Объекты DatePeriod можно использовать в качестве итератора для генерации ряда объектов DateTimeImmutable или DateTime из даты start , interval и end или числа recurrences .
Класс возвращаемых объектов эквивалентен классу-родителю DateTimeImmutable или DateTime объекта start .
Список параметров
Начальная дата. По умолчанию включается в набор результатов.
Количество повторений. Число возвращаемых результатов на единицу больше этого, так как дата начала включается в набор результатов по умолчанию. Должно быть больше, чем 0 .
Конечная дата. По умолчанию исключается из набора результатов.
Подмножество, содержащее интервал согласно » спецификации ISO 8601.
Примерами некоторых особенностей спецификации интервалов ISO 8601, которые PHP не поддерживает, являются:
Битовое поле, которое можно использовать для управления определённым поведением с начальной и конечной датами.
Исключить начальную дату внутри периода из набора повторяющихся дат можно с помощью константы DatePeriod::EXCLUDE_START_DATE .
Включить конечную дату внутри периода в набор повторяющихся дат можно с помощью константы DatePeriod::INCLUDE_END_DATE .
Список изменений
Версия | Описание |
---|---|
8.2.0 | Добавлена константа DatePeriod::INCLUDE_END_DATE . |
7.2.19, 7.3.6, 7.4.0 | recurrences должен быть больше 0 . |
Примеры
Пример #1 Пример использования DatePeriod
$start = new DateTime ( ‘2012-07-01’ );
$interval = new DateInterval ( ‘P7D’ );
$end = new DateTime ( ‘2012-07-31’ );
$recurrences = 4 ;
$iso = ‘R4/2012-07-01T00:00:00Z/P7D’ ;
?php
// Эти периоды эквивалентны.
$period = new DatePeriod ( $start , $interval , $recurrences );
$period = new DatePeriod ( $start , $interval , $end );
$period = new DatePeriod ( $iso );
// При переборе экземпляра DatePeriod в цикле будут отображены все отобранные даты
// периода.
foreach ( $period as $date ) echo $date -> format ( ‘Y-m-d’ ). «\n» ;
>
?>
Результат выполнения данного примера:
2012-07-01 2012-07-08 2012-07-15 2012-07-22 2012-07-29
Пример #2 Пример использования DatePeriod с DatePeriod::EXCLUDE_START_DATE
$start = new DateTime ( ‘2012-07-01’ );
$interval = new DateInterval ( ‘P7D’ );
$end = new DateTime ( ‘2012-07-31’ );
?php
$period = new DatePeriod ( $start , $interval , $end ,
DatePeriod :: EXCLUDE_START_DATE );
// При переборе экземпляра DatePeriod в цикле будут отображены все отобранные даты
// периода.
// Однако в этом случае 2012-07-01 не будет отображена.
foreach ( $period as $date ) echo $date -> format ( ‘Y-m-d’ ). «\n» ;
>
?>
Результат выполнения данного примера:
2012-07-08 2012-07-15 2012-07-22 2012-07-29
Пример #3 Пример использования DatePeriod, показывающий все последние четверги в году
$begin = new DateTime ( ‘2021-12-31’ );
$end = new DateTime ( ‘2022-12-31 23:59:59’ );
?php
$interval = DateInterval :: createFromDateString ( ‘last thursday of next month’ );
$period = new DatePeriod ( $begin , $interval , $end , DatePeriod :: EXCLUDE_START_DATE );
foreach ( $period as $dt ) echo $dt -> format ( ‘l Y-m-d’ ), «\n» ;
>
?>
Результат выполнения данного примера:
Thursday 2022-01-27 Thursday 2022-02-24 Thursday 2022-03-31 Thursday 2022-04-28 Thursday 2022-05-26 Thursday 2022-06-30 Thursday 2022-07-28 Thursday 2022-08-25 Thursday 2022-09-29 Thursday 2022-10-27 Thursday 2022-11-24 Thursday 2022-12-29
Примечания
Несвязное количество повторений, определённые в секции 4.5 ISO 8601 «Recurring time interval», не поддерживается, то есть ни передача «R/. » в isostr , ни null в end , не будут работать.