43

I need to check if the current time is in timerange. The most simple case time_end > time_start:

if time(6,0) <= now.time() <= time(12,00): print '1'

But troubles begin when user enters a time range when the end time is smaller than the start time, e.g. "23:00 - 06:00". A time like '00:00' will be in this range. About 5 years ago I wrote this PHP function:

function checkInterval($start, $end)
  {    
    $dt = date("H:i:s");    

    $tstart = explode(":", $start);
    $tend =   explode(":", $end);
    $tnow =   explode(":", $dt);

    if (!$tstart[2])
      $tstart[2] = 0;

    if (!$tend[2])
      $tend[2] = 0;  

    $tstart = $tstart[0]*60*60 + $tstart[1]*60 + $tstart[2];
    $tend   = $tend[0]*60*60   + $tend[1]*60   + $tend[2];
    $tnow   = $tnow[0]*60*60   + $tnow[1]*60   + $tnow[2];

    if ($tend < $tstart)
      {
        if ($tend - $tnow > 0 && $tnow > $tstart)
          return true;
        else if ($tnow - $tstart > 0 && $tnow > $tend)
          return true;
        else if ($tend > $tnow && $tend < $tstart && $tstart > $tnow)
          return true;
        else return false;
      } else
      {
        if ($tstart < $tnow && $tend > $tnow)
          return true;
        else
          return false;
      }

Now I need to do the same thing, but I want to make it good looking. So, what algorithm should I use to determine if the current time '00:00' is in reversed range e.g. ['23:00', '01:00']?

doubleDown
  • 8,048
  • 1
  • 32
  • 48
night-crawler
  • 1,409
  • 1
  • 26
  • 39

2 Answers2

67

The Python solution is going to be much, much shorter.

def time_in_range(start, end, x):
    """Return true if x is in the range [start, end]"""
    if start <= end:
        return start <= x <= end
    else:
        return start <= x or x <= end

Use the datetime.time class for start, end, and x.

>>> import datetime
>>> start = datetime.time(23, 0, 0)
>>> end = datetime.time(1, 0, 0)
>>> time_in_range(start, end, datetime.time(23, 30, 0))
True
>>> time_in_range(start, end, datetime.time(12, 30, 0))
False
Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • if start=today[10:00], end=tomorrow[10:00], and x = 11:00 then `start <= x <= end = False`!!! – Paulo Scardine May 25 '12 at 03:31
  • 1
    @PauloScardine: You have to choose how to interpret it: whether [10:00, 10:00] has length 0 or 24 hours. Either interpretation is fine. In other words, you say that `start < end`, but I chose `start <= end` and there is no obvious reason to choose one or the other. – Dietrich Epp May 25 '12 at 04:21
  • The whole concept of comparing times without dates is fragile if you are crossing the barrier between days. – Paulo Scardine May 25 '12 at 04:29
  • 6
    Not necessarily. For example, what if you run a store that is open 7 days a week from 7am - 1am? This is exactly the kind of function you'd need to figure out if the store is open. – Dietrich Epp May 25 '12 at 04:32
  • 2
    The question asked about current time, but it looks to me datetime.time(23, 30, 0) is not – Zhiyuan Chen Oct 29 '20 at 12:44
  • @ZhiyuanChen: That’s test code. If used the current time in test code, it would give different answers depending on what time you run the test, which is not what you want. – Dietrich Epp Oct 29 '20 at 17:23
  • 2
    @DietrichEpp Thanks for replying, but wouldn't it be easier if you just add datetime.datetime.now().time()? It tooks me a few minitus to find it at other places – Zhiyuan Chen Oct 30 '20 at 00:31
  • @ZhiyuanChen: I don’t think this is the right place to add that information. That information can be found on a different question: https://stackoverflow.com/questions/415511/how-to-get-the-current-time-in-python – Dietrich Epp Oct 30 '20 at 01:18
15

Date/time is trickier than you think

Calculations involving date/time can be very tricky because you must consider timezone, leap years, day-light-savings and lots of corner cases. There is an enlightening video from the talk by Taavi Burns at PyCon2012 entitled "What you need to know about datetimes":

What you need to know about datetimes:
time, datetime, and calendar from the standard library are a bit messy. Find out: what to use where and how (particularly when you have users in many timezones), and what extra modules you might want to look into.

Event: PyCon US 2012 / Speakers: Taavi Burns / Recorded: March 10, 2012

Use timezone-aware datetime for calculations

The concept of a datetime.time for tomorrow is void, because datetime.time lacks any date information. You probably want to convert everything to timezone-aware datetime.datetime before comparing:

def time_in_range(start, end, x):
    today = timezone.localtime().date()
    start = timezone.make_aware(datetime.datetime.combine(today, start))
    end = timezone.make_aware(datetime.datetime.combine(today, end))
    x = timezone.make_aware(datetime.datetime.combine(today, x))
    if end <= start:
        end += datetime.timedelta(days=1) # tomorrow!
    if x <= start
        x += datetime.timedelta(days=1) # tomorrow!
    return start <= x <= end
Paulo Scardine
  • 73,447
  • 11
  • 124
  • 153