1"""times module
2
3This module provides some Date and Time classes for dealing with MySQL data.
4
5Use Python datetime module to handle date and time columns.
6"""
7from time import localtime
8from datetime import date, datetime, time, timedelta
9from MySQLdb._mysql import string_literal
10
11Date = date
12Time = time
13TimeDelta = timedelta
14Timestamp = datetime
15
16DateTimeDeltaType = timedelta
17DateTimeType = datetime
18
19
20def DateFromTicks(ticks):
21    """Convert UNIX ticks into a date instance."""
22    return date(*localtime(ticks)[:3])
23
24
25def TimeFromTicks(ticks):
26    """Convert UNIX ticks into a time instance."""
27    return time(*localtime(ticks)[3:6])
28
29
30def TimestampFromTicks(ticks):
31    """Convert UNIX ticks into a datetime instance."""
32    return datetime(*localtime(ticks)[:6])
33
34
35format_TIME = format_DATE = str
36
37
38def format_TIMEDELTA(v):
39    seconds = int(v.seconds) % 60
40    minutes = int(v.seconds // 60) % 60
41    hours = int(v.seconds // 3600) % 24
42    return "%d %d:%d:%d" % (v.days, hours, minutes, seconds)
43
44
45def format_TIMESTAMP(d):
46    """
47    :type d: datetime.datetime
48    """
49    if d.microsecond:
50        fmt = " ".join(
51            [
52                "{0.year:04}-{0.month:02}-{0.day:02}",
53                "{0.hour:02}:{0.minute:02}:{0.second:02}.{0.microsecond:06}",
54            ]
55        )
56    else:
57        fmt = " ".join(
58            [
59                "{0.year:04}-{0.month:02}-{0.day:02}",
60                "{0.hour:02}:{0.minute:02}:{0.second:02}",
61            ]
62        )
63    return fmt.format(d)
64
65
66def DateTime_or_None(s):
67    try:
68        if len(s) < 11:
69            return Date_or_None(s)
70
71        micros = s[20:]
72
73        if len(micros) == 0:
74            # 12:00:00
75            micros = 0
76        elif len(micros) < 7:
77            # 12:00:00.123456
78            micros = int(micros) * 10 ** (6 - len(micros))
79        else:
80            return None
81
82        return datetime(
83            int(s[:4]),  # year
84            int(s[5:7]),  # month
85            int(s[8:10]),  # day
86            int(s[11:13] or 0),  # hour
87            int(s[14:16] or 0),  # minute
88            int(s[17:19] or 0),  # second
89            micros,  # microsecond
90        )
91    except ValueError:
92        return None
93
94
95def TimeDelta_or_None(s):
96    try:
97        h, m, s = s.split(":")
98        if "." in s:
99            s, ms = s.split(".")
100            ms = ms.ljust(6, "0")
101        else:
102            ms = 0
103        if h[0] == "-":
104            negative = True
105        else:
106            negative = False
107        h, m, s, ms = abs(int(h)), int(m), int(s), int(ms)
108        td = timedelta(hours=h, minutes=m, seconds=s, microseconds=ms)
109        if negative:
110            return -td
111        else:
112            return td
113    except ValueError:
114        # unpacking or int/float conversion failed
115        return None
116
117
118def Time_or_None(s):
119    try:
120        h, m, s = s.split(":")
121        if "." in s:
122            s, ms = s.split(".")
123            ms = ms.ljust(6, "0")
124        else:
125            ms = 0
126        h, m, s, ms = int(h), int(m), int(s), int(ms)
127        return time(hour=h, minute=m, second=s, microsecond=ms)
128    except ValueError:
129        return None
130
131
132def Date_or_None(s):
133    try:
134        return date(
135            int(s[:4]),
136            int(s[5:7]),
137            int(s[8:10]),
138        )  # year  # month  # day
139    except ValueError:
140        return None
141
142
143def DateTime2literal(d, c):
144    """Format a DateTime object as an ISO timestamp."""
145    return string_literal(format_TIMESTAMP(d))
146
147
148def DateTimeDelta2literal(d, c):
149    """Format a DateTimeDelta object as a time."""
150    return string_literal(format_TIMEDELTA(d))
151