Skip to content

Commit 9b8d5ae

Browse files
seismanweiji14
andauthored
sequence_join: Correctly join datetime-like values in pd.DataFrame/xr.DataArray objects (#4097)
Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com>
1 parent 631f09c commit 9b8d5ae

File tree

2 files changed

+51
-1
lines changed

2 files changed

+51
-1
lines changed

pygmt/alias.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,21 @@ def _to_string(
109109
110110
>>> _to_string([[1, 2], [3, 4]], sep="/", ndim=2)
111111
['1/2', '3/4']
112+
113+
>>> import datetime
114+
>>> import numpy as np
115+
>>> import pandas as pd
116+
>>> import xarray as xr
117+
>>> _to_string(
118+
... [
119+
... datetime.date(2010, 1, 1),
120+
... datetime.datetime(2010, 3, 1),
121+
... pd.Timestamp("2015-01-01T12:00:00.123456789"),
122+
... xr.DataArray(data=np.datetime64("2005-01-01T08:00:00", "ns")),
123+
... ],
124+
... sep="/",
125+
... )
126+
'2010-01-01/2010-03-01T00:00:00.000000/2015-01-01T12:00:00.123456/2005-01-01T08:00:00.000000000'
112127
"""
113128
# None and False are converted to None.
114129
if value is None or value is False:

pygmt/helpers/utils.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from pathlib import Path
1717
from typing import Any, Literal
1818

19+
import numpy as np
1920
import xarray as xr
2021
from pygmt._typing import PathLike
2122
from pygmt.encodings import charset
@@ -816,6 +817,30 @@ def sequence_join(
816817
['1/2', '3/4']
817818
>>> sequence_join([1, 2, 3, 4], separator=",")
818819
'1,2,3,4'
820+
821+
>>> # Join a sequence of datetime-like objects into a string.
822+
>>> import datetime
823+
>>> import numpy as np
824+
>>> import pandas as pd
825+
>>> import xarray as xr
826+
>>> sequence_join(
827+
... [
828+
... datetime.date(2010, 1, 1),
829+
... np.datetime64("2010-01-01T16:00:00"),
830+
... np.array("2010-03-01T00:00:00", dtype=np.datetime64),
831+
... ],
832+
... sep="/",
833+
... )
834+
'2010-01-01/2010-01-01T16:00:00/2010-03-01T00:00:00'
835+
>>> sequence_join(
836+
... [
837+
... datetime.datetime(2010, 3, 1),
838+
... pd.Timestamp("2015-01-01T12:00:00.123456789"),
839+
... xr.DataArray(data=np.datetime64("2005-01-01T08:00:00", "ns")),
840+
... ],
841+
... sep="/",
842+
... )
843+
'2010-03-01T00:00:00.000000/2015-01-01T12:00:00.123456/2005-01-01T08:00:00.000000000'
819844
"""
820845
# Return the original value if it is not a sequence (e.g., None, bool, or str).
821846
if not is_nonstr_iter(value):
@@ -848,7 +873,17 @@ def sequence_join(
848873
f"but got {len(value)} values."
849874
)
850875
raise GMTInvalidInput(msg)
851-
return sep.join(str(v) for v in value)
876+
# 'str(v)' produces a string like '2024-01-01 00:00:00' for some datetime-like
877+
# objects (e.g., datetime.datetime, pandas.Timestamp), which contains a space.
878+
# If so, use np.datetime_as_string to convert it to ISO 8601 string format
879+
# YYYY-MM-DDThh:mm:ss.ffffff.
880+
_values = [
881+
np.datetime_as_string(np.asarray(item, dtype="datetime64"))
882+
if " " in (s := str(item))
883+
else s
884+
for item in value
885+
]
886+
return sep.join(_values) # type: ignore[arg-type]
852887

853888
# Now it must be a 2-D sequence.
854889
if ndim == 1:

0 commit comments

Comments
 (0)