summaryrefslogtreecommitdiff
path: root/src/webob/datetime_utils.py
blob: b9bbb4375db24c88fb3304641c8a975aed734dbf (plain)
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
import calendar
from datetime import date, datetime, timedelta, tzinfo
from email.utils import formatdate, mktime_tz, parsedate_tz
import time

from webob.util import text_

__all__ = [
    "UTC",
    "timedelta_to_seconds",
    "year",
    "month",
    "week",
    "day",
    "hour",
    "minute",
    "second",
    "parse_date",
    "serialize_date",
    "parse_date_delta",
    "serialize_date_delta",
]

_now = datetime.now  # hook point for unit tests


class _UTC(tzinfo):
    def dst(self, dt):
        return timedelta(0)

    def utcoffset(self, dt):
        return timedelta(0)

    def tzname(self, dt):
        return "UTC"

    def __repr__(self):
        return "UTC"


UTC = _UTC()


def timedelta_to_seconds(td):
    """
    Converts a timedelta instance to seconds.
    """

    return td.seconds + (td.days * 24 * 60 * 60)


day = timedelta(days=1)
week = timedelta(weeks=1)
hour = timedelta(hours=1)
minute = timedelta(minutes=1)
second = timedelta(seconds=1)
# Estimate, I know; good enough for expirations
month = timedelta(days=30)
year = timedelta(days=365)


def parse_date(value):
    if not value:
        return None
    try:
        if not isinstance(value, str):
            value = str(value, "latin-1")
    except Exception:
        return None
    t = parsedate_tz(value)

    if t is None:
        # Could not parse

        return None

    t = mktime_tz(t)

    return datetime.fromtimestamp(t, UTC)


def serialize_date(dt):
    if isinstance(dt, (bytes, str)):
        return text_(dt)

    if isinstance(dt, timedelta):
        dt = _now() + dt

    if isinstance(dt, (datetime, date)):
        dt = dt.timetuple()

    if isinstance(dt, (tuple, time.struct_time)):
        dt = calendar.timegm(dt)

    if not (isinstance(dt, float) or isinstance(dt, int)):
        raise ValueError(
            "You must pass in a datetime, date, time tuple, or integer object, "
            "not %r" % dt
        )

    return formatdate(dt, usegmt=True)


def parse_date_delta(value):
    """
    like parse_date, but also handle delta seconds
    """

    if not value:
        return None
    try:
        value = int(value)
    except ValueError:
        return parse_date(value)
    else:
        return _now() + timedelta(seconds=value)


def serialize_date_delta(value):
    if isinstance(value, (float, int, int)):
        return str(int(value))
    else:
        return serialize_date(value)