From 9ec7ecab8fa97ea2f5d9adef7756e01cdae7febc Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 23 Sep 2026 19:14:40 +0800 Subject: [PATCH 1/4] Figure.solar: Fix the bug that terminator datetime doesn't support fractional timezone offsets --- pygmt/src/solar.py | 20 ++++++++----------- ...est_solar_terminator_datetime_timezone.png | 4 ++-- pygmt/tests/test_solar.py | 1 + 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/pygmt/src/solar.py b/pygmt/src/solar.py index dc2f902099e..87f26e115f1 100644 --- a/pygmt/src/solar.py +++ b/pygmt/src/solar.py @@ -71,10 +71,8 @@ def solar( terminator_datetime : str or datetime object Set the date and time for the terminator calculation. It can be provided as a string or any datetime-like object recognized by :func:`pandas.to_datetime`. The - time can be specified in UTC or using a UTC offset. The offset must be an - integer number of hours (e.g., -8 or +5); fractional hours are truncated - towards zero (e.g., -8.5 becomes -8 and +5.5 becomes +5). [Default is the - current UTC date and time]. + time can be specified in UTC or with a UTC offset of any precision [Default is + thencurrent UTC date and time]. fill Set color or pattern for filling terminators [Default is no fill]. pen @@ -113,18 +111,17 @@ def solar( >>> # show the plot >>> fig.show() """ - datetime_string, datetime_timezone = None, None + datetime_string = None if terminator_datetime: try: _datetime = pd.to_datetime(terminator_datetime) - datetime_string = _datetime.strftime("%Y-%m-%dT%H:%M:%S.%f") - # GMT's solar module uses the C 'atoi' function to parse the timezone - # offset. Ensure the offset is an integer number of hours (e.g., -8 or +5). - # Fractional hours (e.g., -8.5 or +5.5) are truncated towards zero. - if utcoffset := _datetime.utcoffset(): - datetime_timezone = int(utcoffset.total_seconds() / 3600) except ValueError as verr: raise GMTValueError(terminator_datetime, description="datetime") from verr + # Convert a timezone-aware datetime to UTC as a workaround for GMT's upstream + # bug at https://github.com/GenericMappingTools/gmt/issues/9220. + if _datetime.tzinfo is not None: + _datetime = _datetime.tz_convert("UTC") + datetime_string = _datetime.strftime("%Y-%m-%dT%H:%M:%S.%f") aliasdict = AliasSystem( G=Alias(fill, name="fill"), @@ -140,7 +137,6 @@ def solar( }, ), Alias(datetime_string, name="terminator_datetime", prefix="+d"), - Alias(datetime_timezone, name="terminator_timezone", prefix="+z"), ], W=Alias(pen, name="pen"), ).add_common( diff --git a/pygmt/tests/baseline/test_solar_terminator_datetime_timezone.png b/pygmt/tests/baseline/test_solar_terminator_datetime_timezone.png index 05b7fb95404..43cc4d631d8 100644 --- a/pygmt/tests/baseline/test_solar_terminator_datetime_timezone.png +++ b/pygmt/tests/baseline/test_solar_terminator_datetime_timezone.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:465b6e30a0a391a9256a6f3eb82bce9fe7d878fe7c1fe1720d1f7b155bd158a8 -size 48753 +oid sha256:774d1ef710f6f6f08ae322d4ee16b34e664b6ccebcec9ddf4437590dc7aab5e4 +size 53256 diff --git a/pygmt/tests/test_solar.py b/pygmt/tests/test_solar.py index 29d031a947a..1d3cadfca0c 100644 --- a/pygmt/tests/test_solar.py +++ b/pygmt/tests/test_solar.py @@ -101,6 +101,7 @@ def test_solar_terminator_datetime_timezone(): fig.basemap(region="d", projection="W0/15c", frame=True) fig.solar(terminator_datetime="2020-01-01T01:02:03", pen="1p,black") fig.solar(terminator_datetime="2020-01-01T01:02:03+01:00", pen="1p,red") + fig.solar(terminator_datetime="2020-01-01T01:02:03+00:30", pen="1p,yellow,-") fig.solar(terminator_datetime="2020-01-01T01:02:03-01:00", pen="1p,blue") fig.solar( terminator_datetime=datetime.datetime( From 924b7315771abf2f3ac5d3239981d7a085fc7ab6 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 23 Sep 2026 19:22:21 +0800 Subject: [PATCH 2/4] Fix a typo and improve tests --- pygmt/src/solar.py | 2 +- pygmt/tests/test_solar.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/src/solar.py b/pygmt/src/solar.py index 87f26e115f1..b2ac92c3c22 100644 --- a/pygmt/src/solar.py +++ b/pygmt/src/solar.py @@ -72,7 +72,7 @@ def solar( Set the date and time for the terminator calculation. It can be provided as a string or any datetime-like object recognized by :func:`pandas.to_datetime`. The time can be specified in UTC or with a UTC offset of any precision [Default is - thencurrent UTC date and time]. + the current UTC date and time]. fill Set color or pattern for filling terminators [Default is no fill]. pen diff --git a/pygmt/tests/test_solar.py b/pygmt/tests/test_solar.py index 1d3cadfca0c..697c59fc57a 100644 --- a/pygmt/tests/test_solar.py +++ b/pygmt/tests/test_solar.py @@ -100,8 +100,8 @@ def test_solar_terminator_datetime_timezone(): fig = Figure() fig.basemap(region="d", projection="W0/15c", frame=True) fig.solar(terminator_datetime="2020-01-01T01:02:03", pen="1p,black") - fig.solar(terminator_datetime="2020-01-01T01:02:03+01:00", pen="1p,red") fig.solar(terminator_datetime="2020-01-01T01:02:03+00:30", pen="1p,yellow,-") + fig.solar(terminator_datetime="2020-01-01T01:02:03+01:00", pen="1p,red") fig.solar(terminator_datetime="2020-01-01T01:02:03-01:00", pen="1p,blue") fig.solar( terminator_datetime=datetime.datetime( From 7811d32bf6b110ad5f6e6f0bb2ca7e938961ae7d Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 24 Sep 2026 11:38:12 +0800 Subject: [PATCH 3/4] No need to mention the upstream bug --- pygmt/src/solar.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pygmt/src/solar.py b/pygmt/src/solar.py index b2ac92c3c22..87ff481945d 100644 --- a/pygmt/src/solar.py +++ b/pygmt/src/solar.py @@ -117,8 +117,7 @@ def solar( _datetime = pd.to_datetime(terminator_datetime) except ValueError as verr: raise GMTValueError(terminator_datetime, description="datetime") from verr - # Convert a timezone-aware datetime to UTC as a workaround for GMT's upstream - # bug at https://github.com/GenericMappingTools/gmt/issues/9220. + # Convert a timezone-aware datetime to UTC, before passing to GMT. if _datetime.tzinfo is not None: _datetime = _datetime.tz_convert("UTC") datetime_string = _datetime.strftime("%Y-%m-%dT%H:%M:%S.%f") From 419e59dce077ef8f9a7661acc0dd74cf9491c1cb Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 24 Sep 2026 20:19:47 +0800 Subject: [PATCH 4/4] Use orange color for the newly added line --- .../baseline/test_solar_terminator_datetime_timezone.png | 4 ++-- pygmt/tests/test_solar.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pygmt/tests/baseline/test_solar_terminator_datetime_timezone.png b/pygmt/tests/baseline/test_solar_terminator_datetime_timezone.png index 43cc4d631d8..5d862829c67 100644 --- a/pygmt/tests/baseline/test_solar_terminator_datetime_timezone.png +++ b/pygmt/tests/baseline/test_solar_terminator_datetime_timezone.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:774d1ef710f6f6f08ae322d4ee16b34e664b6ccebcec9ddf4437590dc7aab5e4 -size 53256 +oid sha256:911c881bbe7261d5c7a0ecce6f78f63674a8e3f26341cb48de485be77d7d0682 +size 54054 diff --git a/pygmt/tests/test_solar.py b/pygmt/tests/test_solar.py index 697c59fc57a..447f7b12b76 100644 --- a/pygmt/tests/test_solar.py +++ b/pygmt/tests/test_solar.py @@ -100,7 +100,7 @@ def test_solar_terminator_datetime_timezone(): fig = Figure() fig.basemap(region="d", projection="W0/15c", frame=True) fig.solar(terminator_datetime="2020-01-01T01:02:03", pen="1p,black") - fig.solar(terminator_datetime="2020-01-01T01:02:03+00:30", pen="1p,yellow,-") + fig.solar(terminator_datetime="2020-01-01T01:02:03+00:30", pen="1p,orange,-") fig.solar(terminator_datetime="2020-01-01T01:02:03+01:00", pen="1p,red") fig.solar(terminator_datetime="2020-01-01T01:02:03-01:00", pen="1p,blue") fig.solar(