Reputation: 6560
To display farm produce that is available in "current season", I can ask:
Is ('Y-m-d',strtotime('today'))
greater than $start_of_season
and less than $end_of_season
, and as long as start date is before end date, the logic is easy.
$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
But what if I want to ignore the year and measure between November and February? If today is December 1st it's greater than November, but it's also greater than February.
My first attempt is to say,
if end_date is greater than start_date
This is the code:
$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)))):
Which seems to "work" for most cases.
But if there's an item who's season is December through July and the current date is July 1st, then there will be a $start_of_season > $end_of_season
, but since it's after June 1st $end_of_season
will have been set to December 31st, putting us outside of the "in_season" display window.
I'm sure there are reasonable, eloquent ways to do this, and could use some enlightenment.
Upvotes: 1
Views: 128
Reputation: 56
Personally I would encapsulate this logic and use date objects. Here is the simplest way that I could think of at the moment. Class properties are public for the sake of brevity.
<?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());
}
}
Define a season:
$season = new Season();
$season->setStart(11, 1);
$season->setEnd(7, 1);
And test the outcome:
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
Upvotes: 1
Reputation: 1987
You could normalize your months to the start of the season. For example, if the start of your season is November (month 11) and end in February (month 2), those would normalize to month 1 and month 4, respectively. Then you could check any month against the normalized year and see if it falls within the season.
$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";
}
Normalized year example:
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
)
Upvotes: 1
Reputation: 11
You can build an array of allowed months. Then check if the month is in the allowed month array. If yes you just have to check if you are in the first or last month of the season. If in the first month you have to check if the day is greater or equal than the start day. If in the last month you have to check if the day is less or equal than the end day.
Here is a code example:
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';
}
Upvotes: 1