Home | History | Annotate | Download | only in webob
      1 import calendar
      2 
      3 from datetime import (
      4     date,
      5     datetime,
      6     timedelta,
      7     tzinfo,
      8     )
      9 
     10 from email.utils import (
     11     formatdate,
     12     mktime_tz,
     13     parsedate_tz,
     14     )
     15 
     16 import time
     17 
     18 from webob.compat import (
     19     integer_types,
     20     long,
     21     native_,
     22     text_type,
     23     )
     24 
     25 __all__ = [
     26     'UTC', 'timedelta_to_seconds',
     27     'year', 'month', 'week', 'day', 'hour', 'minute', 'second',
     28     'parse_date', 'serialize_date',
     29     'parse_date_delta', 'serialize_date_delta',
     30 ]
     31 
     32 _now = datetime.now # hook point for unit tests
     33 
     34 class _UTC(tzinfo):
     35     def dst(self, dt):
     36         return timedelta(0)
     37     def utcoffset(self, dt):
     38         return timedelta(0)
     39     def tzname(self, dt):
     40         return 'UTC'
     41     def __repr__(self):
     42         return 'UTC'
     43 
     44 UTC = _UTC()
     45 
     46 
     47 
     48 def timedelta_to_seconds(td):
     49     """
     50     Converts a timedelta instance to seconds.
     51     """
     52     return td.seconds + (td.days*24*60*60)
     53 
     54 day = timedelta(days=1)
     55 week = timedelta(weeks=1)
     56 hour = timedelta(hours=1)
     57 minute = timedelta(minutes=1)
     58 second = timedelta(seconds=1)
     59 # Estimate, I know; good enough for expirations
     60 month = timedelta(days=30)
     61 year = timedelta(days=365)
     62 
     63 
     64 def parse_date(value):
     65     if not value:
     66         return None
     67     try:
     68         value = native_(value)
     69     except:
     70         return None
     71     t = parsedate_tz(value)
     72     if t is None:
     73         # Could not parse
     74         return None
     75     if t[-1] is None:
     76         # No timezone given.  None would mean local time, but we'll force UTC
     77         t = t[:9] + (0,)
     78     t = mktime_tz(t)
     79     return datetime.fromtimestamp(t, UTC)
     80 
     81 def serialize_date(dt):
     82     if isinstance(dt, (bytes, text_type)):
     83         return native_(dt)
     84     if isinstance(dt, timedelta):
     85         dt = _now() + dt
     86     if isinstance(dt, (datetime, date)):
     87         dt = dt.timetuple()
     88     if isinstance(dt, (tuple, time.struct_time)):
     89         dt = calendar.timegm(dt)
     90     if not (isinstance(dt, float) or isinstance(dt, integer_types)):
     91         raise ValueError(
     92             "You must pass in a datetime, date, time tuple, or integer object, "
     93             "not %r" % dt)
     94     return formatdate(dt, usegmt=True)
     95 
     96 
     97 
     98 def parse_date_delta(value):
     99     """
    100     like parse_date, but also handle delta seconds
    101     """
    102     if not value:
    103         return None
    104     try:
    105         value = int(value)
    106     except ValueError:
    107         return parse_date(value)
    108     else:
    109         return _now() + timedelta(seconds=value)
    110 
    111 
    112 def serialize_date_delta(value):
    113     if isinstance(value, (float, int, long)):
    114         return str(int(value))
    115     else:
    116         return serialize_date(value)
    117