Skip to content

Commit 061f066

Browse files
committed
implement change_calendar
1 parent da66cce commit 061f066

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

cf_units/__init__.py

+25
Original file line numberDiff line numberDiff line change
@@ -1746,6 +1746,31 @@ def __ne__(self, other):
17461746
"""
17471747
return not self == other
17481748

1749+
def change_calendar(self, calendar):
1750+
"""
1751+
Returns a new unit with the requested calendar, modifying the reference
1752+
date if necessary. Only works with calenders that represent the real
1753+
world (standard, proleptic_gregorian, julian) and with short time
1754+
intervals (days or less).
1755+
1756+
For example:
1757+
1758+
>>> from cf_units import Unit
1759+
>>> u = Unit('days since 1500-01-01', calendar='proleptic_gregorian')
1760+
>>> u.change_calendar('standard')
1761+
Unit('days since 1499-12-23T00:00:00', calendar='standard')
1762+
1763+
"""
1764+
if not self.is_time_reference():
1765+
raise ValueError("unit is not a time reference")
1766+
1767+
ref_date = self.num2date(0)
1768+
new_ref_date = ref_date.change_calendar(calendar)
1769+
time_units = self.origin.split(_OP_SINCE)[0]
1770+
new_origin = _OP_SINCE.join([time_units, new_ref_date.isoformat()])
1771+
1772+
return Unit(new_origin, calendar=calendar)
1773+
17491774
def convert(self, value, other, ctype=FLOAT64, inplace=False):
17501775
"""
17511776
Converts a single value or NumPy array of values from the current unit

cf_units/tests/unit/unit/test_Unit.py

+45
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,51 @@ def test_hash_replacement(self):
3131
self.assertEqual(u, expected)
3232

3333

34+
class Test_change_calendar(unittest.TestCase):
35+
def test_modern_standard_to_proleptic_gregorian(self):
36+
u = Unit("hours since 1970-01-01 00:00:00", calendar="standard")
37+
expected = Unit(
38+
"hours since 1970-01-01 00:00:00", calendar="proleptic_gregorian"
39+
)
40+
result = u.change_calendar("proleptic_gregorian")
41+
self.assertEqual(result, expected)
42+
43+
def test_ancient_standard_to_proleptic_gregorian(self):
44+
u = Unit("hours since 1500-01-01 00:00:00", calendar="standard")
45+
expected = Unit(
46+
"hours since 1500-01-10 00:00:00", calendar="proleptic_gregorian"
47+
)
48+
result = u.change_calendar("proleptic_gregorian")
49+
self.assertEqual(result, expected)
50+
51+
def test_no_change(self):
52+
u = Unit("hours since 1500-01-01 00:00:00", calendar="standard")
53+
result = u.change_calendar("standard")
54+
self.assertEqual(result, u)
55+
# Docstring states that a new unit is returned, so check these are not
56+
# the same object.
57+
self.assertIsNot(result, u)
58+
59+
def test_long_time_interval(self):
60+
u = Unit("months since 1970-01-01", calendar="standard")
61+
with self.assertRaisesRegex(ValueError, "cannot be processed"):
62+
u.change_calendar("proleptic_gregorian")
63+
64+
def test_wrong_calendar(self):
65+
u = Unit("days since 1900-01-01", calendar="360_day")
66+
with self.assertRaisesRegex(
67+
ValueError, "change_calendar only works for real-world calendars"
68+
):
69+
u.change_calendar("standard")
70+
71+
def test_non_time_unit(self):
72+
u = Unit("m")
73+
with self.assertRaisesRegex(
74+
ValueError, "unit is not a time reference"
75+
):
76+
u.change_calendar("standard")
77+
78+
3479
class Test_convert__calendar(unittest.TestCase):
3580
class MyStr(str):
3681
pass

0 commit comments

Comments
 (0)