Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On only some days: ValueError: Unable to find a dusk time on the date specified #86

Open
BetterAutomations opened this issue Jan 19, 2023 · 8 comments

Comments

@BetterAutomations
Copy link

BetterAutomations commented Jan 19, 2023

For a particular location within the southeastern United States on some days, requesting an astral.sun generates a ValueError, but on previous and following days in the same location, the correct values are returned. This location always experiences dusk.

I only need sunrise and sunset so I attempted to use astral.sun.sunset alone, but this causes the same issue to appears on a different day, but warning that it is "Unable to find a sunset time". I do not recall exactly which day but it was within April.

Tested another library (suntime) and it handled this location with all days in 2023 without any issues.

Sample code:

from datetime import datetime
from astral.sun import sun
from astral import Observer

sun(Observer(30, -82), datetime(2023, 3, 10))
sun(Observer(30, -82), datetime(2023, 3, 11))
sun(Observer(30, -82), datetime(2023, 3, 12))
sun(Observer(30, -82), datetime(2023, 3, 13))
sun(Observer(30, -82), datetime(2023, 3, 14))
sun(Observer(30, -82), datetime(2023, 3, 15))
sun(Observer(30, -82), datetime(2023, 3, 16))
sun(Observer(30, -82), datetime(2023, 3, 17))
sun(Observer(30, -82), datetime(2023, 3, 18))
sun(Observer(30, -82), datetime(2023, 3, 19))
sun(Observer(30, -82), datetime(2023, 3, 20))

Output:

(SecureCoop) root@api02:/SecureCoop# python
Python 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from datetime import datetime
>>> from astral.sun import sun
>>> from astral import Observer
>>> sun(Observer(30, -82), datetime(2023, 3, 10))
{'dawn': datetime.datetime(2023, 3, 10, 11, 19, 49, 114342, tzinfo=datetime.timezone.utc), 'sunrise': datetime.datetime(2023, 3, 10, 11, 44, 9, 112599, tzinfo=datetime.timezone.utc), 'noon': datetime.datetime(2023, 3, 10, 17, 38, 26, tzinfo=datetime.timezone.utc), 'sunset': datetime.datetime(2023, 3, 10, 23, 32, 47, 795392, tzinfo=datetime.timezone.utc), 'dusk': datetime.datetime(2023, 3, 10, 23, 57, 9, 354083, tzinfo=datetime.timezone.utc)}
>>> sun(Observer(30, -82), datetime(2023, 3, 11))
{'dawn': datetime.datetime(2023, 3, 11, 11, 18, 39, 517805, tzinfo=datetime.timezone.utc), 'sunrise': datetime.datetime(2023, 3, 11, 11, 42, 58, 996090, tzinfo=datetime.timezone.utc), 'noon': datetime.datetime(2023, 3, 11, 17, 38, 10, tzinfo=datetime.timezone.utc), 'sunset': datetime.datetime(2023, 3, 11, 23, 33, 26, 601529, tzinfo=datetime.timezone.utc), 'dusk': datetime.datetime(2023, 3, 11, 23, 57, 47, 689061, tzinfo=datetime.timezone.utc)}
>>> sun(Observer(30, -82), datetime(2023, 3, 12))
{'dawn': datetime.datetime(2023, 3, 12, 11, 17, 29, 461424, tzinfo=datetime.timezone.utc), 'sunrise': datetime.datetime(2023, 3, 12, 11, 41, 48, 511143, tzinfo=datetime.timezone.utc), 'noon': datetime.datetime(2023, 3, 12, 17, 37, 55, tzinfo=datetime.timezone.utc), 'sunset': datetime.datetime(2023, 3, 12, 23, 34, 5, 165001, tzinfo=datetime.timezone.utc), 'dusk': datetime.datetime(2023, 3, 12, 23, 58, 25, 873095, tzinfo=datetime.timezone.utc)}
>>> sun(Observer(30, -82), datetime(2023, 3, 13))
{'dawn': datetime.datetime(2023, 3, 13, 11, 16, 18, 973837, tzinfo=datetime.timezone.utc), 'sunrise': datetime.datetime(2023, 3, 13, 11, 40, 37, 686887, tzinfo=datetime.timezone.utc), 'noon': datetime.datetime(2023, 3, 13, 17, 37, 39, tzinfo=datetime.timezone.utc), 'sunset': datetime.datetime(2023, 3, 13, 23, 34, 43, 497721, tzinfo=datetime.timezone.utc), 'dusk': datetime.datetime(2023, 3, 13, 23, 59, 3, 918562, tzinfo=datetime.timezone.utc)}
>>> sun(Observer(30, -82), datetime(2023, 3, 14))
{'dawn': datetime.datetime(2023, 3, 14, 11, 15, 8, 83636, tzinfo=datetime.timezone.utc), 'sunrise': datetime.datetime(2023, 3, 14, 11, 39, 26, 552340, tzinfo=datetime.timezone.utc), 'noon': datetime.datetime(2023, 3, 14, 17, 37, 22, tzinfo=datetime.timezone.utc), 'sunset': datetime.datetime(2023, 3, 14, 23, 35, 21, 611771, tzinfo=datetime.timezone.utc), 'dusk': datetime.datetime(2023, 3, 14, 23, 59, 41, 837950, tzinfo=datetime.timezone.utc)}
>>> sun(Observer(30, -82), datetime(2023, 3, 15))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/SecureCoop/lib/python3.10/site-packages/astral/sun.py", line 1267, in sun
    "dusk": dusk(observer, date, dawn_dusk_depression, tzinfo),
  File "/SecureCoop/lib/python3.10/site-packages/astral/sun.py", line 962, in dusk
    raise ValueError("Unable to find a dusk time on the date specified")
ValueError: Unable to find a dusk time on the date specified
>>> sun(Observer(30, -82), datetime(2023, 3, 16))
{'dawn': datetime.datetime(2023, 3, 16, 11, 12, 45, 209520, tzinfo=datetime.timezone.utc), 'sunrise': datetime.datetime(2023, 3, 16, 11, 37, 3, 467906, tzinfo=datetime.timezone.utc), 'noon': datetime.datetime(2023, 3, 16, 17, 36, 49, tzinfo=datetime.timezone.utc), 'sunset': datetime.datetime(2023, 3, 16, 23, 36, 37, 232881, tzinfo=datetime.timezone.utc), 'dusk': datetime.datetime(2023, 3, 16, 0, 0, 19, 643824, tzinfo=datetime.timezone.utc)}
>>> sun(Observer(30, -82), datetime(2023, 3, 17))
{'dawn': datetime.datetime(2023, 3, 17, 11, 11, 33, 282549, tzinfo=datetime.timezone.utc), 'sunrise': datetime.datetime(2023, 3, 17, 11, 35, 51, 575511, tzinfo=datetime.timezone.utc), 'noon': datetime.datetime(2023, 3, 17, 17, 36, 32, tzinfo=datetime.timezone.utc), 'sunset': datetime.datetime(2023, 3, 17, 23, 37, 14, 764700, tzinfo=datetime.timezone.utc), 'dusk': datetime.datetime(2023, 3, 17, 0, 0, 57, 348801, tzinfo=datetime.timezone.utc)}
>>> sun(Observer(30, -82), datetime(2023, 3, 18))
{'dawn': datetime.datetime(2023, 3, 18, 11, 10, 21, 66848, tzinfo=datetime.timezone.utc), 'sunrise': datetime.datetime(2023, 3, 18, 11, 34, 39, 487807, tzinfo=datetime.timezone.utc), 'noon': datetime.datetime(2023, 3, 18, 17, 36, 14, tzinfo=datetime.timezone.utc), 'sunset': datetime.datetime(2023, 3, 18, 23, 37, 52, 127314, tzinfo=datetime.timezone.utc), 'dusk': datetime.datetime(2023, 3, 18, 0, 1, 34, 965517, tzinfo=datetime.timezone.utc)}
>>> sun(Observer(30, -82), datetime(2023, 3, 19))
{'dawn': datetime.datetime(2023, 3, 19, 11, 9, 8, 590765, tzinfo=datetime.timezone.utc), 'sunrise': datetime.datetime(2023, 3, 19, 11, 33, 27, 233264, tzinfo=datetime.timezone.utc), 'noon': datetime.datetime(2023, 3, 19, 17, 35, 57, tzinfo=datetime.timezone.utc), 'sunset': datetime.datetime(2023, 3, 19, 23, 38, 29, 333225, tzinfo=datetime.timezone.utc), 'dusk': datetime.datetime(2023, 3, 19, 0, 2, 12, 506606, tzinfo=datetime.timezone.utc)}
>>> sun(Observer(30, -82), datetime(2023, 3, 20))
{'dawn': datetime.datetime(2023, 3, 20, 11, 7, 55, 882599, tzinfo=datetime.timezone.utc), 'sunrise': datetime.datetime(2023, 3, 20, 11, 32, 14, 840246, tzinfo=datetime.timezone.utc), 'noon': datetime.datetime(2023, 3, 20, 17, 35, 39, tzinfo=datetime.timezone.utc), 'sunset': datetime.datetime(2023, 3, 20, 23, 39, 6, 394940, tzinfo=datetime.timezone.utc), 'dusk': datetime.datetime(2023, 3, 20, 0, 2, 49, 984667, tzinfo=datetime.timezone.utc)}
>>>
@lwchkg
Copy link

lwchkg commented Jan 23, 2023

Looks like you should have Observer(-82, 30) instead of Observer(30, -82).

Anyway, still think that the library should not throw if the dusk time does not exist, because the input is valid. You should probably return None instead, or some custom values if you want to distinguish "the Sun is always up" and "the Sun is always down".

@BetterAutomations
Copy link
Author

No, I had it correctly. Observer() is latitude/longitude and the location is 30 latitude and -82 longitude.

@lwchkg
Copy link

lwchkg commented Jan 26, 2023

Oh... sorry for my mistake. Looks like I've written about another thing instead.

BTW, looks like the 'dusk' time is not on that day you enter acts funny. Either it return the dusk of the previous/next sun rise (on the specified day) or return an error if that of the previous/next day is also not on the day you specify.

To add to the injury the calculations appear to be in UTC instead of local time, so the library crashes even in normal conditions.

@mrherman
Copy link

mrherman commented Apr 8, 2023

Did anything ever get figured out on this issue. I recently started having the same issue, for a location that definitely experiences dusk. Seems to be an issue in >=3.0 versions (for me). Python 3.10

@BetterAutomations
Copy link
Author

Never found a fix. I switched to the suntime library instead.

@chipguyhere
Copy link

I got caught up on this as well. Proof of concept code that won't run:

from astral.sun import sun
from astral.geocoder import database, lookup
from astral import LocationInfo
from datetime import datetime, timezone

location = lookup("London", database()) # Use any city as a temporary placeholder
location.latitude = 31.1442757
location.longitude = -88.9690628
s=sun(location.observer, date=datetime(2023,3,10,4,5,2,tzinfo=timezone.utc))
print(s["dawn"])
print(s["dusk"])

@lwchkg
Copy link

lwchkg commented Apr 19, 2023

I've found a peculiarity in the code anyway: when it tries to find the sunrise/sunset time (or other times), it tries to find the sunrise/sunset at that exactly 24-hr window (in case of DST events, 23 or 25 hours).

Unfortunately, due to a range of factors (e.g. the longitude is not a multiple of 15°), the sunrise/sunset time can actually be in the previous day or the next day. I believe that we should simply use the out-of-day time right away, but astral tries to find the time of the previous or next sunrise/sunset to fit in that 24-hr window. If there is no such sunrise/sunset in the previous/next day, astral throws a ValueError.

The 24-hr window is calculated in the timezone you supplied, so unsurprisingly @chipguyhere 's code does not return the right result - his time zone supplied has almost 90° difference from the longitude, which translate to almost 6 hours.

@elierpf
Copy link

elierpf commented Jan 19, 2024

I had the same issue with version 3.2 of astral, definitively it raised the "no dusk error" when the civilian dusk's (the default one) time is 00:00 UTC or midnight in UTC timezone, doesn't matter the seconds after the midnight.
I tested with version 2.2 and it works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants