forked from wireservice/agate
-
Notifications
You must be signed in to change notification settings - Fork 1
/
date.py
92 lines (71 loc) · 2.59 KB
/
date.py
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
#!/usr/bin/env python
from datetime import date, datetime, time
import isodate
import parsedatetime
import six
from agate.data_types.base import DataType
from agate.exceptions import CastError
ZERO_DT = datetime.combine(date.min, time.min)
class Date(DataType):
"""
Data representing dates alone.
:param date_format:
A formatting string for :meth:`datetime.datetime.strptime` to use
instead of using regex-based parsing.
"""
def __init__(self, date_format=None, **kwargs):
super(Date, self).__init__(**kwargs)
self.date_format = date_format
self.parser = parsedatetime.Calendar(version=parsedatetime.VERSION_CONTEXT_STYLE)
def __getstate__(self):
"""
Return state values to be pickled. Exclude _parser because parsedatetime
cannot be pickled.
"""
odict = self.__dict__.copy()
del odict['parser']
return odict
def __setstate__(self, data):
"""
Restore state from the unpickled state values. Set _parser to an instance
of the parsedatetime Calendar class.
"""
self.__dict__.update(data)
self.parser = parsedatetime.Calendar(version=parsedatetime.VERSION_CONTEXT_STYLE)
def cast(self, d):
"""
Cast a single value to a :class:`datetime.date`.
:param date_format:
An optional :func:`datetime.strptime` format string for parsing
datetimes in this column.
:returns:
:class:`datetime.date` or :code:`None`.
"""
if type(d) is date or d is None:
return d
elif isinstance(d, six.string_types):
d = d.strip()
if d.lower() in self.null_values:
return None
else:
raise CastError('Can not parse value "%s" as date.' % d)
if self.date_format:
try:
dt = datetime.strptime(d, self.date_format)
except:
raise CastError('Value "%s" does not match date format.' % d)
return dt.date()
try:
(value, ctx, _, _, matched_text), = self.parser.nlp(d, sourceTime=ZERO_DT)
except (TypeError, ValueError):
raise CastError('Value "%s" does not match date format.' % d)
else:
if matched_text == d and ctx.hasDate and not ctx.hasTime:
return value.date()
raise CastError('Can not parse value "%s" as date.' % d)
def csvify(self, d):
if d is None:
return None
return d.isoformat()
def jsonify(self, d):
return self.csvify(d)