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