diff --git a/pygmt/alias.py b/pygmt/alias.py index 89d8fb1c0f3..a0021c53b33 100644 --- a/pygmt/alias.py +++ b/pygmt/alias.py @@ -109,6 +109,21 @@ def _to_string( >>> _to_string([[1, 2], [3, 4]], sep="/", ndim=2) ['1/2', '3/4'] + + >>> import datetime + >>> import numpy as np + >>> import pandas as pd + >>> import xarray as xr + >>> _to_string( + ... [ + ... datetime.date(2010, 1, 1), + ... datetime.datetime(2010, 3, 1), + ... pd.Timestamp("2015-01-01T12:00:00.123456789"), + ... xr.DataArray(data=np.datetime64("2005-01-01T08:00:00", "ns")), + ... ], + ... sep="/", + ... ) + '2010-01-01/2010-03-01T00:00:00.000000/2015-01-01T12:00:00.123456/2005-01-01T08:00:00.000000000' """ # None and False are converted to None. if value is None or value is False: diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index 3d7fe694729..03c5ba73856 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -16,6 +16,7 @@ from pathlib import Path from typing import Any, Literal +import numpy as np import xarray as xr from pygmt._typing import PathLike from pygmt.encodings import charset @@ -816,6 +817,30 @@ def sequence_join( ['1/2', '3/4'] >>> sequence_join([1, 2, 3, 4], separator=",") '1,2,3,4' + + >>> # Join a sequence of datetime-like objects into a string. + >>> import datetime + >>> import numpy as np + >>> import pandas as pd + >>> import xarray as xr + >>> sequence_join( + ... [ + ... datetime.date(2010, 1, 1), + ... np.datetime64("2010-01-01T16:00:00"), + ... np.array("2010-03-01T00:00:00", dtype=np.datetime64), + ... ], + ... sep="/", + ... ) + '2010-01-01/2010-01-01T16:00:00/2010-03-01T00:00:00' + >>> sequence_join( + ... [ + ... datetime.datetime(2010, 3, 1), + ... pd.Timestamp("2015-01-01T12:00:00.123456789"), + ... xr.DataArray(data=np.datetime64("2005-01-01T08:00:00", "ns")), + ... ], + ... sep="/", + ... ) + '2010-03-01T00:00:00.000000/2015-01-01T12:00:00.123456/2005-01-01T08:00:00.000000000' """ # Return the original value if it is not a sequence (e.g., None, bool, or str). if not is_nonstr_iter(value): @@ -848,7 +873,17 @@ def sequence_join( f"but got {len(value)} values." ) raise GMTInvalidInput(msg) - return sep.join(str(v) for v in value) + # 'str(v)' produces a string like '2024-01-01 00:00:00' for some datetime-like + # objects (e.g., datetime.datetime, pandas.Timestamp), which contains a space. + # If so, use np.datetime_as_string to convert it to ISO 8601 string format + # YYYY-MM-DDThh:mm:ss.ffffff. + _values = [ + np.datetime_as_string(np.asarray(item, dtype="datetime64")) + if " " in (s := str(item)) + else s + for item in value + ] + return sep.join(_values) # type: ignore[arg-type] # Now it must be a 2-D sequence. if ndim == 1: