Skip to content

Commit d7aad0f

Browse files
author
Daniel da Silva
committed
Make netcdftime.datetime immutable and hashable. Fixes #255.
1 parent 96c074b commit d7aad0f

File tree

2 files changed

+63
-11
lines changed

2 files changed

+63
-11
lines changed

netcdftime.py

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
_units = ['days','hours','minutes','seconds','day','hour','minute','second']
1111
_calendars = ['standard','gregorian','proleptic_gregorian','noleap','julian','all_leap','365_day','366_day','360_day']
1212

13-
__version__ = '1.1'
13+
__version__ = '1.2'
1414

1515
# Adapted from http://delete.me.uk/2005/03/iso8601.html
1616
ISO8601_REGEX = re.compile(r"(?P<year>[0-9]{1,4})(-(?P<month>[0-9]{1,2})(-(?P<day>[0-9]{1,2})"
@@ -19,7 +19,7 @@
1919
)
2020
TIMEZONE_REGEX = re.compile("(?P<prefix>[+-])(?P<hours>[0-9]{1,2}):(?P<minutes>[0-9]{1,2})")
2121

22-
class datetime:
22+
class datetime(object):
2323
"""
2424
Phony datetime object which mimics the python datetime object,
2525
but allows for dates that don't exist in the proleptic gregorian calendar.
@@ -35,24 +35,47 @@ class datetime:
3535
"""
3636
def __init__(self,year,month,day,hour=0,minute=0,second=0,dayofwk=-1,dayofyr=1):
3737
"""dayofyr set to 1 by default - otherwise time.strftime will complain"""
38-
self.year=year
39-
self.month=month
40-
self.day=day
41-
self.hour=hour
42-
self.minute=minute
43-
self.dayofwk=dayofwk
44-
self.dayofyr=dayofyr
45-
self.second=second
46-
self.format='%Y-%m-%d %H:%M:%S'
38+
self._year=year
39+
self._month=month
40+
self._day=day
41+
self._hour=hour
42+
self._minute=minute
43+
self._dayofwk=dayofwk
44+
self._dayofyr=dayofyr
45+
self._second=second
46+
self._format='%Y-%m-%d %H:%M:%S'
47+
48+
year = property(lambda self: self._year)
49+
month = property(lambda self: self._month)
50+
day = property(lambda self: self._day)
51+
hour = property(lambda self: self._hour)
52+
minute = property(lambda self: self._minute)
53+
dayofwk = property(lambda self: self._dayofwk)
54+
dayofyr = property(lambda self: self._dayofyr)
55+
second = property(lambda self: self._second)
56+
format = property(lambda self: self._format)
57+
4758
def strftime(self,format=None):
4859
if format is None:
4960
format = self.format
5061
return _strftime(self,format)
62+
5163
def timetuple(self):
5264
return (self.year,self.month,self.day,self.hour,self.minute,self.second,self.dayofwk,self.dayofyr,-1)
65+
66+
def _to_real_datetime(self):
67+
return real_datetime(self._year, self._month, self._day, self._hour, self._minute, self._second)
68+
5369
def __repr__(self):
5470
return self.strftime(self.format)
5571

72+
def __hash__(self):
73+
try:
74+
d = self._to_real_datetime()
75+
except ValueError:
76+
return hash(tuple(sorted(self.__dict__.items())))
77+
return hash(d)
78+
5679
def _compare(self, comparison_op, other):
5780
if hasattr(other, 'strftime'):
5881
return comparison_op(self.strftime('%Y-%m-%d %H:%M:%S'),

test/tst_netcdftime.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,35 @@ def runTest(self):
198198
assert d2 > d1
199199
assert d2 >= d1
200200

201+
# check datetime hash
202+
d1 = datetimex(1995, 1, 1)
203+
d2 = datetime(1995, 1, 1)
204+
d3 = datetimex(2001, 2, 30)
205+
assert hash(d1) == hash(d1)
206+
assert hash(d1) == hash(d2)
207+
assert hash(d1) != hash(d3)
208+
assert hash(d3) == hash(d3)
209+
210+
# check datetime immutability
211+
with self.assertRaises(AttributeError):
212+
d1.year = 1999
213+
with self.assertRaises(AttributeError):
214+
d1.month = 6
215+
with self.assertRaises(AttributeError):
216+
d1.day = 5
217+
with self.assertRaises(AttributeError):
218+
d1.hour = 10
219+
with self.assertRaises(AttributeError):
220+
d1.minute = 33
221+
with self.assertRaises(AttributeError):
222+
d1.second = 45
223+
with self.assertRaises(AttributeError):
224+
d1.dayofwk = 1
225+
with self.assertRaises(AttributeError):
226+
d1.dayofyr = 52
227+
with self.assertRaises(AttributeError):
228+
d1.format = '%Y'
229+
201230

202231
class TestDate2index(unittest.TestCase):
203232

0 commit comments

Comments
 (0)