Viewed   78 times

If you have a $start_date and $end_date, how can you check if a date given by the user falls within that range?

e.g.

$start_date = '2009-06-17';

$end_date = '2009-09-05';

$date_from_user = '2009-08-28'; 

At the moment the dates are strings, would it help to convert them to timestamp integers?

 Answers

4

Converting them to timestamps is the way to go alright, using strtotime, e.g.

$start_date = '2009-06-17';

$end_date = '2009-09-05';

$date_from_user = '2009-08-28';

check_in_range($start_date, $end_date, $date_from_user);


function check_in_range($start_date, $end_date, $date_from_user)
{
  // Convert to timestamp
  $start_ts = strtotime($start_date);
  $end_ts = strtotime($end_date);
  $user_ts = strtotime($date_from_user);

  // Check that user date is between start & end
  return (($user_ts >= $start_ts) && ($user_ts <= $end_ts));
}
Thursday, September 29, 2022
4

DateTime, DatePeriod and DateInterval are your friends to do that quickly!

See online.

<?php
/**
 * @file
 * Awnser to http://.com/q/37224961/392725
 *
 * @link http://.com/a/37228497/392725
 */
date_default_timezone_set('Europe/Paris');

function getWeekDates(DateTimeInterface $date, $format = 'Y-m-d') {
  $dt        = DateTimeImmutable::createFromMutable($date);
  $first_day = $dt->modify('first day of this month');
  $last_day  = $dt->modify('last day of this month');
  $period    = new DatePeriod(
    $first_day,
    DateInterval::createFromDateString('sunday this week'),
    $last_day,
    DatePeriod::EXCLUDE_START_DATE
  );

  $weeks = [$first_day->format($format)];
  foreach ($period as $d) {
    $weeks[] = $d->modify('-1 day')->format($format);
    $weeks[] = $d->format($format);
  }
  $weeks[] = $last_day->format($format);

  return array_chunk($weeks, 2);
}

echo "Weeks of the current month:n";
$weeks = getWeekDates(new DateTime('now'));
array_walk($weeks, function ($week) {
  vprintf("%s to %sn", $week);
});

echo "nWeeks of the month may 2016:n";
$weeks = getWeekDates(new DateTime('2016-05'));
array_walk($weeks, function ($week) {
  vprintf("%s to %sn", $week);
});

echo "nWeeks of the month june 2016:n";
$weeks = getWeekDates(new DateTime('2016-06'));
array_walk($weeks, function ($week) {
  vprintf("%s to %sn", $week);
});

echo "nWeeks of the month october 2016:n";
$weeks = getWeekDates(new DateTime('2016-10'));
array_walk($weeks, function ($week) {
  vprintf("%s to %sn", $week);
});

Result:

Weeks of the current month:
2016-05-01 to 2016-05-07
2016-05-08 to 2016-05-14
2016-05-15 to 2016-05-21
2016-05-22 to 2016-05-28
2016-05-29 to 2016-05-31

Weeks of the month may 2016:
2016-05-01 to 2016-05-07
2016-05-08 to 2016-05-14
2016-05-15 to 2016-05-21
2016-05-22 to 2016-05-28
2016-05-29 to 2016-05-31

Weeks of the month june 2016:
2016-06-01 to 2016-06-04
2016-06-05 to 2016-06-11
2016-06-12 to 2016-06-18
2016-06-19 to 2016-06-25
2016-06-26 to 2016-06-30

Weeks of the month october 2016:
2016-10-01 to 2016-10-01
2016-10-02 to 2016-10-08
2016-10-09 to 2016-10-15
2016-10-16 to 2016-10-22
2016-10-23 to 2016-10-29
2016-10-30 to 2016-10-31
Sunday, August 7, 2022
2

Usage : $output = mergeRanges($input);

This method is originally designed to merge any kind on numeric ranges, timestamps included and supports any kind of overlaps. It takes an array of objects in input, containing "from" and "to" keys which is customizable.


/**
 * @param        $ranges
 * @param string $keyFrom
 * @param string $keyTo
 *
 * @return array
 */
function mergeRanges($ranges, $keyFrom = 'from', $keyTo = 'to')
{
    // Split from / to values.
    $arrayFrom = [];
    $arrayTo   = [];
    foreach ($ranges as $date)
    {
        $arrayFrom[] = $date->$keyFrom;
        $arrayTo[]   = $date->$keyTo;
    }

    // Sort ASC.
    natsort($arrayFrom);
    natsort($arrayTo);

    $ranges = [];
    // Iterate over start dates.
    foreach ($arrayFrom as $indexFrom => $from)
    {
        // Get previous entry.
        $previousEntry = end($ranges);
        // Find associated default "to" value to "from" one.
        $to = $arrayTo[$indexFrom];

        // If we have a previous entry and "to" is greater than
        // current "from" value.
        if (isset($previousEntry->to) && $from < $previousEntry->to + 1)
        {
            // Do nothing if this range is completely covered
            // by the previous one.
            if ($to > $previousEntry->to)
            {
                // We just change te "to" value of previous range,
                // so we don't create a new entry.
                $previousEntry->to = $to;
            }
        }
        else
        {
            // Create a new range entry.
            $ranges[] = (object) [
                $keyFrom => $from,
                $keyTo   => $to,
            ];
        }
    }

    return $ranges;
}

Example :

$input = [
    // One day.
    (object) [
        'title' => 'One day.',
        'from'  => 1560816000,
        'to'    => 1560902399,
    ],
    // Same day, inner period
    (object) [
        'title' => 'Same day, inner period',
        'from'  => 1560816000 + 1000,
        'to'    => 1560902399 - 1000,
    ],
    // Just before midnight
    (object) [
        'title' => 'Just before midnight',
        'from'  => 1560816000 - 1000,
        'to'    => 1560816000 + 1000,
    ],
    // Just after midnight
    (object) [
        'title' => 'Just after midnight',
        'from'  => 1560902399 - 1000,
        'to'    => 1560902399 + 1000,
    ],
    // Other period before
    (object) [
        'title' => 'Other period before',
        'from'  => 1560902399 - 100000,
        'to'    => 1560902399 - 100000 + 5000,
    ],
    // Other period after
    (object) [
        'title' => 'Other period after',
        'from'  => 1560816000 + 100000,
        'to'    => 1560902399 + 100000 + 5000,
    ],
];

Result :

Array
(
    [0] => Array
        (
            [from] => 2019-06-17 22:13:19
            [to] => 2019-06-17 23:36:39
        )

    [1] => Array
        (
            [from] => 2019-06-18 01:43:20
            [to] => 2019-06-19 02:16:39
        )

    [2] => Array
        (
            [from] => 2019-06-19 05:46:40
            [to] => 2019-06-20 07:09:59
        )

)

Wednesday, October 26, 2022
3
boolean isWithinRange(Date testDate) {
   return !(testDate.before(startDate) || testDate.after(endDate));
}

Doesn't seem that awkward to me. Note that I wrote it that way instead of

return testDate.after(startDate) && testDate.before(endDate);

so it would work even if testDate was exactly equal to one of the end cases.

Tuesday, November 22, 2022
 
erwan
 
5
SELECT * FROM events 
  WHERE date1<='2012-01-18'
  AND date2>='2012-01-18'
Friday, October 14, 2022
 
shob-z
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :