С конца месяца до начала месяца, безотносительно к конкретному году

1

Чтобы отобразить продукты фермы, доступные в текущем сезоне, я могу спросить:

Is ('Ym-d',strtotime('today')) больше $start_of_season и меньше $end_of_season, и до тех пор, пока дата начала до даты окончания, логика проста.

$date_format = 'Y-m-d';
if ((date_i18n($date_format,strtotime('today')) > date_i18n($date_format,strtotime($start_of_season))) &&
     (date_i18n($date_format,strtotime('today')) < date_i18n($date_format,strtotime($end_of_season)))):

# display the produce

Но что, если я хочу игнорировать год и измерять в период с ноября по февраль? Если сегодня 1 декабря это больше ноября, но и больше февраля.

Моя первая попытка - сказать,

  • если end_date больше, чем start_date

    • если сегодня во второй половине года
      • Затем вызовите end_date 12-31
    • еще
      • вызовите start_date 01-01

Это код:

$date_format = 'm-d';
if (date_i18n($date_format,strtotime($start_of_season)) > date_i18n($date_format,strtotime($end_of_season))):
    if (date_i18n($date_format,strtotime('today')) > date_i18n($date_format,strtotime('2000-06-01'))):
        $end_of_season = '2000-12-31';
    else:
        $start_of_season = '2000-01-01';
    endif;
endif;

if ((date_i18n($date_format,strtotime('today')) > date_i18n($date_format,strtotime($start_of_season))) &&
     (date_i18n($date_format,strtotime('today')) < date_i18n($date_format,strtotime($end_of_season)))):

Кажется, что "работает" для большинства случаев.

Но если есть пункт, сезон которого - декабрь по июль, а текущая дата - 1 июля, тогда будет $start_of_season > $end_of_season, но так как после 1 июня $end_of_season будет установлен до 31 декабря, помещение нас за пределы окно отображения "in_season".

Я уверен, что есть разумные, красноречивые способы сделать это и можно использовать некоторое просветление.

Теги:
strtotime

3 ответа

1
Лучший ответ

Лично я должен инкапсулировать эту логику и использовать объекты даты. Вот самый простой способ, о котором я мог думать в данный момент. Свойства класса являются общедоступными для краткости.

<?php

date_default_timezone_set('America/New_York');

class Season {

    public $startMonth;
    public $startDay;
    public $endMonth;
    public $endDay;

    public function setStart($month, $day) {
        $this->startMonth = (int) $month;
        $this->startDay   = (int) $day;
    }

    public function setEnd($month, $day) {
        $this->endMonth = (int) $month;
        $this->endDay   = (int) $day;
    }

    function isActiveForDate(DateTime $date) {

        $seasonStartDate = new DateTime(sprintf('%d-%d-%d', $date->format('Y'), $this->startMonth, $this->startDay));
        $seasonEndDate   = new DateTime(sprintf('%d-%d-%d', $date->format('Y'), $this->endMonth, $this->endDay));

        // Edge case
        if ($this->startMonth > $this->endMonth) {
            $seasonStartDate->modify('-1 year');

            // This line is only useful if you wish to calculate inclusively
            if ($date == $seasonStartDate || $date == $seasonEndDate) return true;

            // If this condition is true, no need to calculate anything
            if ($date->format('n') < $this->startMonth && $date->format('n') >= $this->endMonth) {
                return false;
            }

            $seasonEndDate->modify('+1 year');
        }

        return ($date->getTimestamp() >= $seasonStartDate->getTimestamp() 
            && $date->getTimestamp() <= $seasonEndDate->getTimestamp());
    }
}

Определите сезон:

$season = new Season();
$season->setStart(11, 1);
$season->setEnd(7, 1);

И проверить результат:

echo ($season->isActiveForDate(new DateTime("2000-7-2")))   ? "pass" : "fail"; // fail
echo ($season->isActiveForDate(new DateTime("2000-10-31"))) ? "pass" : "fail"; // fail
echo ($season->isActiveForDate(new DateTime("2000-11-1")))  ? "pass" : "fail"; // pass
echo ($season->isActiveForDate(new DateTime("2000-6-31")))  ? "pass" : "fail"; // pass
  • 0
    Я не знал о методе modify для объектов DateTime. Это действительно хорошее предложение. Приспосабливая это и высоко ценится.
1

Вы можете создать массив допустимых месяцев. Затем проверьте, находится ли месяц в массиве разрешенных месяцев. Если да, вам просто нужно проверить, находитесь ли вы в первый или последний месяц сезона. Если в течение первого месяца вы должны проверить, больше ли день или равен стартовому дню. Если в последний месяц вы должны проверить, меньше или меньше дня, чем в конце дня.

Вот пример кода:

function getMonthArray($startMonth, $endMonth) {
    $return = array();
    $return[] = $startMonth;

    while($startMonth != $endMonth) {
        $startMonth++;
        if ($startMonth > 12) {
            $startMonth = 1;
        }
        $return[] = $startMonth;
    }
    return $return;
}

function isInSeason($start, $end, $check) {
    $month      = (int) substr($check, 0, 2);
    $startMonth = (int) substr($start, 0, 2);
    $endMonth   = (int) substr($end, 0, 2); 
    if (in_array($month, getMonthArray($startMonth, $endMonth))) {
        $day        = (int) substr($check, 3, 2);       
        if ($month == $startMonth) {
            $startDay = (int) substr($start, 3, 2);
            return ($day >= $startDay);
        } elseif ($month == $endMonth) {
            $endDay = (int) substr($end, 3, 2);
            return ($day <= $endDay);
        } else {
            return TRUE;
        }
    }
    return FALSE;
}

$start  = '12-01';
$end    = '06-30';

$check  = '07-10';

if (isInSeason($start, $end, $check)) {
    echo 'In season';
} else {
    echo 'Not in season';
}
1

Вы можете нормализовать свои месяцы до начала сезона. Например, если начало вашего сезона - ноябрь (11-й месяц) и конец февраля (месяц 2), они нормализуются до 1-го и 4-го месяцев соответственно. Затем вы можете проверить каждый месяц против нормализованного года и посмотреть, попадает ли он в течение сезона.

$startMonth = 11; // November
$endMonth   = 2; // February

$futureFactor = $startMonth - 1;
$pastFactor   = 13 - $startMonth;

$months = [];

// Create a normalized year to the start month.
foreach (range(1,12) as $r) {

  if ($r == $startMonth) {
    $months[$r] = 1;
  }
  else {
    $months[$r] = $r < $startMonth ? $r + $pastFactor : $r - $futureFactor;
  }
}

// Check if December(12) is in season
if ($months[12] >= $months[$startMonth] && $months[12] <= $months[$endMonth]) {
  print "In season...\n";
}
else {
  print "Out of season...\n";
}

Пример нормализованного года:

Array
(
    [1] => 3
    [2] => 4
    [3] => 5
    [4] => 6
    [5] => 7
    [6] => 8
    [7] => 9
    [8] => 10
    [9] => 11
    [10] => 12
    [11] => 1
    [12] => 2
)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню