Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

executable file 143 lines (120 sloc) 5.666 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
#! /usr/bin/env python

# Does a day of week or month fall between two dates?
# Copyright 2012 by Akkana Peck: share and enjoy under the GPLv2 or later.

import time

def falls_between(when, time1, time2) :
    """Does a given day-of-week or day-of-month fall between
the two given times? It is presumed that time1 <= time2.
If when == "Tue", did we cross a tuesday getting from time1 to time2?
If when == 15, did we cross the 15th of a month?
If when == none, return True.
If when matches time2, return True.
"""

    if not when or type(when) is str and len(when) <= 0 :
        return True

    # We need both times both in seconds since epoch and in struct_time:
    def both_time_types(t) :
        """Given a time that might be either seconds since epoch or struct_time,
return a tuple of (seconds, struct_time).
"""
        if type(t) is time.struct_time :
            return time.mktime(t), t
        elif type(t) is int or type(t) is float :
            return t, time.localtime(t)
        else : raise ValueError("%s not int or struct_time" % str(t))

    (t1, st1) = both_time_types(time1)
    (t2, st2) = both_time_types(time2)

    daysdiff = (t2 - t1) / 60. / 60. / 24.

    # Is it a day of the month?
    try :
        day_of_month = int(when)

        # It is a day of the month! How many days in between the two dates?
        if daysdiff > 31 :
            return True

        # Now we know the two dates differ by less than a month.
        # Are time1 and time2 both in the same month? Then it's easy.
        if st1.tm_mon == st2.tm_mon :
            return st1.tm_mday <= day_of_month and st2.tm_mday >= day_of_month

        # Else time1 is the month prior to time2, so:
        return st1.tm_mday < day_of_month or day_of_month <= st2.tm_mday

    except ValueError : # Not an integer, probably a string.
        pass

    if type(when) is not str :
        raise ValueError("%s must be a string or integer" % when)

    # Okay, not a day of the month. Is it a day of the week?
    # We have to start with Monday because struct_time.tm_wday does.
    weekdays = [ 'mo', 'tu', 'we', 'th', 'fr', 'sa', 'su' ]
    if len(when) < 2 :
        raise ValueError("%s too short: days must have at least 2 chars" % when)

    when = when[0:2].lower()
    if when not in weekdays :
        raise ValueError("%s is a string but not a day" % when)

    # Whew -- we know it's a day of the week.

    # Has more than a week passed? Then it encompasses all weekdays.
    if daysdiff > 7 :
        return True

    day_of_week = weekdays.index(when)
    return (st2.tm_wday - day_of_week) % 7 < daysdiff

# Unit tests:
if __name__ == "__main__" :
    #
    # Day of week tests:
    #
    assert falls_between('Mon',
                         time.strptime('Sun Aug 12 16:00:00 2012'),
                         time.strptime('Wed Aug 15 16:00:00 2012'))
    assert falls_between('we',
                         time.strptime('Sun Aug 12 16:00:00 2012'),
                         time.strptime('Wed Aug 15 16:00:00 2012'))
    assert falls_between('monday',
                         time.strptime('Wed Aug 01 16:00:00 2012'),
                         time.strptime('Wed Aug 15 16:00:00 2012'))
    assert falls_between('Mon',
                         time.strptime('Fri Aug 12 16:00:00 2011'),
                         time.strptime('Sun Aug 12 16:00:00 2012'))
    assert not falls_between('Tuesday',
                             time.strptime('Wed Aug 01 16:00:00 2012'),
                             time.strptime('Sat Aug 04 16:00:00 2012'))
    assert not falls_between('fri',
                             time.strptime('Mon Aug 06 16:00:00 2012'),
                             time.strptime('Thu Aug 09 16:00:00 2012'))

    #
    # Day of month tests:
    #
    assert falls_between(15,
                         time.strptime('Sun Aug 12 16:00:00 2012'),
                         time.strptime('Wed Aug 15 16:00:00 2012'))
    assert falls_between(13,
                         time.strptime('Sun Aug 12 16:00:00 2012'),
                         time.strptime('Wed Aug 15 16:00:00 2012'))
    assert falls_between(13,
                         time.strptime('Sun Jul 22 16:00:00 2012'),
                         time.strptime('Wed Aug 15 16:00:00 2012'))
    assert falls_between(28,
                         time.strptime('Sun Jul 22 16:00:00 2012'),
                         time.strptime('Wed Aug 15 16:00:00 2012'))
    assert not falls_between(20,
                         time.strptime('Sun Jul 22 16:00:00 2012'),
                         time.strptime('Wed Aug 15 16:00:00 2012'))
    assert not falls_between(17,
                             time.strptime('Sun Aug 12 16:00:00 2012'),
                             time.strptime('Wed Aug 15 16:00:00 2012'))
    assert not falls_between(17,
                             time.strptime('Tue Aug 07 16:00:00 2012'),
                             time.strptime('Wed Aug 15 16:00:00 2012'))

    #
    # Make sure ints and floats both work:
    #
    assert falls_between(15,
                         time.strptime('Sun Aug 12 16:00:00 2012'),
                         1345074924)
    assert falls_between(15,
                         time.strptime('Sun Aug 12 16:00:00 2012'),
                         1345074924.2)
    assert not falls_between(17,
                             time.strptime('Tue Aug 07 16:00:00 2012'),
                             1345074924)
    assert not falls_between(17,
                             time.strptime('Tue Aug 07 16:00:00 2012'),
                             1345074924.53)

    print "All tests passed!"
Something went wrong with that request. Please try again.