Skip to content

Commit b5d3378

Browse files
committed
Changes datetime.date to pandas.Timestamp
1 parent 77b76c4 commit b5d3378

File tree

2 files changed

+29
-26
lines changed

2 files changed

+29
-26
lines changed

climada/trajectories/snapshot.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import logging
2929
import warnings
3030

31+
import pandas as pd
32+
3133
from climada.entity.exposures import Exposures
3234
from climada.entity.impact_funcs import ImpactFuncSet
3335
from climada.entity.measures.base import Measure
@@ -47,10 +49,9 @@ class Snapshot:
4749
exposure : Exposures
4850
hazard : Hazard
4951
impfset : ImpactFuncSet
50-
date : int | datetime.date | str
52+
date : int | datetime.date | str | pd.Timestamp
5153
The date of the Snapshot, it can be an integer representing a year,
52-
a datetime object or a string representation of a datetime object
53-
with format "YYYY-MM-DD".
54+
a datetime object or a string representation of a datetime object.
5455
ref_only : bool, default False
5556
Should the `Snapshot` contain deep copies of the Exposures, Hazard and Impfset (False)
5657
or references only (True).
@@ -82,7 +83,7 @@ def __init__(
8283
hazard: Hazard,
8384
impfset: ImpactFuncSet,
8485
measure: Measure | None,
85-
date: int | datetime.date | str,
86+
date: int | datetime.date | str | pd.Timestamp,
8687
ref_only: bool = False,
8788
_from_factory: bool = False,
8889
) -> None:
@@ -97,7 +98,7 @@ def __init__(
9798
self._hazard = hazard if ref_only else copy.deepcopy(hazard)
9899
self._impfset = impfset if ref_only else copy.deepcopy(impfset)
99100
self._measure = measure if ref_only else copy.deepcopy(measure)
100-
self._date = self._convert_to_date(date)
101+
self._date = self._convert_to_timestamp(date)
101102

102103
@classmethod
103104
def from_triplet(
@@ -106,7 +107,7 @@ def from_triplet(
106107
exposure: Exposures,
107108
hazard: Hazard,
108109
impfset: ImpactFuncSet,
109-
date: int | datetime.date | str,
110+
date: int | datetime.date | str | pd.Timestamp,
110111
ref_only: bool = False,
111112
) -> "Snapshot":
112113
"""Create a Snapshot from exposure, hazard and impact functions set
@@ -121,7 +122,7 @@ def from_triplet(
121122
exposure : Exposures
122123
hazard : Hazard
123124
impfset : ImpactFuncSet
124-
date : int | datetime.date | str
125+
date : int | datetime.date | str | pd.Timestamp
125126
ref_only : bool
126127
If true, uses references to the exposure, hazard and impact
127128
function objects. Note that modifying the original objects after
@@ -170,7 +171,7 @@ def measure(self) -> Measure | None:
170171
return self._measure
171172

172173
@property
173-
def date(self) -> datetime.date:
174+
def date(self) -> pd.Timestamp:
174175
"""Date of the snapshot."""
175176
return self._date
176177

@@ -184,22 +185,25 @@ def impact_calc_data(self) -> dict:
184185
}
185186

186187
@staticmethod
187-
def _convert_to_date(date_arg) -> datetime.date:
188-
"""Convert date argument of type int or str to a datetime.date object."""
188+
def _convert_to_timestamp(date_arg) -> pd.Timestamp:
189+
"""Convert date argument of type int or str or datetime.date to pandas Timestamp object."""
189190
if isinstance(date_arg, int):
190191
# Assume the integer represents a year
191-
return datetime.date(date_arg, 1, 1)
192+
return pd.Timestamp(year=date_arg, month=1, day=1)
192193
if isinstance(date_arg, str):
193194
# Try to parse the string as a date
194195
try:
195-
return datetime.datetime.strptime(date_arg, "%Y-%m-%d").date()
196+
return pd.Timestamp(date_arg)
196197
except ValueError as exc:
197198
raise ValueError("String must be in the format 'YYYY-MM-DD'") from exc
198199
if isinstance(date_arg, datetime.date):
199-
# Already a date object
200+
return pd.Timestamp(date_arg)
201+
if isinstance(date_arg, pd.Timestamp):
200202
return date_arg
201203

202-
raise TypeError("date_arg must be an int, str, or datetime.date")
204+
raise TypeError(
205+
"date_arg must be an int, str, datetime.date or pandas.Timestamp"
206+
)
203207

204208
def apply_measure(self, measure: Measure) -> "Snapshot":
205209
"""Create a new snapshot by applying a Measure object.

climada/trajectories/test/test_snapshot.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def mock_context(shared_data):
5757
"mod_exp": modified_exp,
5858
"mod_haz": modified_haz,
5959
"mod_imp": modified_imp,
60+
"date": pd.Timestamp(2023),
6061
}
6162

6263

@@ -78,9 +79,9 @@ def test_not_from_factory_warning(mock_context):
7879
@pytest.mark.parametrize(
7980
"input_date,expected",
8081
[
81-
(2023, datetime.date(2023, 1, 1)),
82-
("2023-01-01", datetime.date(2023, 1, 1)),
83-
(datetime.date(2023, 1, 1), datetime.date(2023, 1, 1)),
82+
(2023, pd.Timestamp(2023, 1, 1)),
83+
("2023-01-01", pd.Timestamp(2023, 1, 1)),
84+
(datetime.date(2023, 1, 1), pd.Timestamp(2023, 1, 1)),
8485
],
8586
)
8687
def test_init_valid_dates(mock_context, input_date, expected):
@@ -106,7 +107,8 @@ def test_init_invalid_date_format(mock_context):
106107

107108
def test_init_invalid_date_type(mock_context):
108109
with pytest.raises(
109-
TypeError, match=r"date_arg must be an int, str, or datetime.date"
110+
TypeError,
111+
match=r"date_arg must be an int, str, datetime.date or pandas.Timestamp",
110112
):
111113
Snapshot.from_triplet(exposure=mock_context["exp"], hazard=mock_context["haz"], impfset=mock_context["imp"], date=2023.5) # type: ignore
112114

@@ -116,7 +118,7 @@ def test_properties(mock_context):
116118
exposure=mock_context["exp"],
117119
hazard=mock_context["haz"],
118120
impfset=mock_context["imp"],
119-
date=2023,
121+
date=mock_context["date"],
120122
)
121123

122124
# Check that it's a deep copy (new reference)
@@ -129,14 +131,15 @@ def test_properties(mock_context):
129131
pd.testing.assert_frame_equal(snapshot.exposure.gdf, mock_context["exp"].gdf)
130132
assert snapshot.hazard.haz_type == mock_context["haz"].haz_type
131133
assert snapshot.impfset == mock_context["imp"]
134+
assert snapshot.date == mock_context["date"]
132135

133136

134137
def test_reference(mock_context):
135138
snapshot = Snapshot.from_triplet(
136139
exposure=mock_context["exp"],
137140
hazard=mock_context["haz"],
138141
impfset=mock_context["imp"],
139-
date=2023,
142+
date=mock_context["date"],
140143
ref_only=True,
141144
)
142145

@@ -146,18 +149,13 @@ def test_reference(mock_context):
146149
assert snapshot.impfset is mock_context["imp"]
147150
assert snapshot.measure is None
148151

149-
# Check data equality
150-
pd.testing.assert_frame_equal(snapshot.exposure.gdf, mock_context["exp"].gdf)
151-
assert snapshot.hazard.haz_type == mock_context["haz"].haz_type
152-
assert snapshot.impfset == mock_context["imp"]
153-
154152

155153
def test_apply_measure(mock_context):
156154
snapshot = Snapshot.from_triplet(
157155
exposure=mock_context["exp"],
158156
hazard=mock_context["haz"],
159157
impfset=mock_context["imp"],
160-
date=2023,
158+
date=mock_context["date"],
161159
)
162160
new_snapshot = snapshot.apply_measure(mock_context["measure"])
163161

@@ -166,3 +164,4 @@ def test_apply_measure(mock_context):
166164
assert new_snapshot.exposure == mock_context["mod_exp"]
167165
assert new_snapshot.hazard == mock_context["mod_haz"]
168166
assert new_snapshot.impfset == mock_context["mod_imp"]
167+
assert new_snapshot.date == mock_context["date"]

0 commit comments

Comments
 (0)