MenoData / Time4J

Advanced date, time and interval library for Java with sun/moon-astronomy and calendars like Chinese, Coptic, Ethiopian, French Republican, Hebrew, Hijri, Historic Christian, Indian National, Japanese, Julian, Korean, Minguo, Persian, Thai, Vietnamese
GNU Lesser General Public License v2.1
424 stars 62 forks source link

Time4J - civil twilight times not available for some locations in Alaska #909

Closed avinash-zemoso closed 4 years ago

avinash-zemoso commented 4 years ago

Time4J base library version : 5.2. Also, observed the same issue in Time4J base 5.6. Java version : 12.

Description

SolarTime solarTime = SolarTime.ofLocation(64.90127423829784, -147.87481800058953);
LocalDate localDate = LocalDate.of(2020, 6, 18);
PlainDate plainDate = TemporalType.LOCAL_DATE.translate(locationDate);
plainDate.get(solarTime.sunrise(Twilight.CIVIL)); // this is returning Optional.empty()

The library is returning Optional.empty() for the above location and date. Also, observed that the library is returning Optional.empty() for all dates between 16th May 2020 and 26th July 2020.

Expected behaviour The library should provide civil twilight times for the above mentioned location and dates. https://www.timeanddate.com/sun/usa/fairbanks?month=6&year=2020 mentions that civil twilight is b/n 00:46 and 02:58 for 18th June.

Actual behaviour The library is returning Optional.empty()

Additional Questions

I've checked the SolarTime documentation, http://www.time4j.net/javadoc-en/net/time4j/calendar/astro/SolarTime.html#sunrise-net.time4j.calendar.astro.Twilight- and http://www.time4j.net/javadoc-en/net/time4j/calendar/astro/SolarTime.html#sunset-net.time4j.calendar.astro.Twilight- , there's no description of how to interpret the output returned on executing the ChronoFunction returned by sunrise and sunset APIs when the output is Optional.empty().

Does it mean the civil twilight data is not available? or Does it mean there is no civil twilight at that location and date? Can I please get an explanation of how to interpret the output when it is Optional.empty()

MenoData commented 4 years ago

IMHO all is fine for the data you had given. Fairbanks in Alaska is very near to the Arctic circle. And you have a date near start of astronomical summer so the sun is up almost the whole day and only goes down for about 2 hours under a very shallow angle.

In fact, the defining angle of 6 degrees under horizon for the civil twilight event is never reached by the sun on that day. And that is your misunderstanding. Time4J handles twilight events related to moments i.e. points in time. If the sun is never reaching -6° then no such event and moment exists, hence the result Optional.empty().

But I see what you want: Not the event of civil twilight but the interval from sunset to next sunrise. Let's study this in detail:

        SolarTime solarTime =
            SolarTime.ofLocation(64.90127423829784, -147.87481800058953);
        PlainDate plainDate = 
            PlainDate.of(2020, 6, 18); // no conversion from LocalDate needed!
        assertThat(
            plainDate.get(solarTime.sunrise(Twilight.CIVIL)).isPresent(),
            is(false)); // the angle of -6° never happens on that day

        TZID tzid = ()->"America/Anchorage"; // std offset = -09:00, daylight offset = +01:00

        System.out.println(
plainDate.minus(CalendarDays.ONE).get(solarTime.sunset()).get().toZonalTimestamp(tzid));
        System.out.println(plainDate.get(solarTime.sunrise()).get().toZonalTimestamp(tzid));
        System.out.println(plainDate.get(solarTime.sunset()).get().toZonalTimestamp(tzid));

Output:

2020-06-18T00:49:08 (sunset related to previous day)
2020-06-18T02:56:18 (sunrise)
2020-06-19T00:49:53 (sunset - on next day)

Finally, the deepest angle of sun elevation can be calculated this way:

    Moment nadir = plainDate.get(solarTime.transitAtMidnight());
    System.out.println(SunPosition.at(nadir, solarTime).getElevation()); // -1.68°

The only small difference compared with timeanddate-website is the first timestamp showing T00:49 instead of T00:46 for sunset. Maybe the website has not used a correction for atmospheric refraction for sunset in the context of civil twilight (but this is rather an academic debate about definitions). Maybe timeanddate has also used a slightly different algorithm which results in such deviations, and results in those polar or subpolar regions are generally not very precise so it is okay for me, too.

Finally I agree that the documentation of empty optional results should be more detailed. I will enhance the doc in next release.

avinash-zemoso commented 4 years ago

Time4J handles twilight events related to moments i.e. points in time. If the sun is never reaching -6° then no such event and moment exists, hence the result Optional.empty()

Thanks for the response @MenoData . By twilight events, do you mean the time(could be during rise or set) at which sun is at 6 degrees with the horizon?

Would it be reasonable to assume that if plainDate.get(solarTime.sunset(Twilight.CIVIL)).isPresent() comes out to be false, the civil twilight extends till sunrise of next day?

MenoData commented 4 years ago

Provided there was a sunset but no following civil twilight event, then the twilight phase reaches until next sunrise.

MenoData commented 4 years ago

Now I have again investigated the small difference between the Time4J-calculation and the website timeanddate.com. It is just caused by a small difference in geographical coordinates. While you had assumed SolarTime.ofLocation(64.90127423829784, -147.87481800058953) which resulted in a sunset at T00:49 (in Time4J), I have now used following location based on geo coordinates in Wikipedia:

    SolarTime fairbanks =
        SolarTime.ofLocation()
            .northernLatitude(64, 50, 0.0)
            .westernLongitude(147, 43, 0.0)
            .build();
    System.out.println(fairbanks.getLongitude()); // -147.717
    System.out.println(fairbanks.getLatitude()); // 64.833

Now the time of sunset is no longer T00:49 but T00:46, the same time as displayed by timeanddate.com-website. So we have really perfect agreement. By the way, NOAA website also shows the same data.

avinash-zemoso commented 4 years ago

thanks for the clarifications @MenoData