chronotope / chrono

Date and time library for Rust
Other
3.34k stars 533 forks source link

0.5: Add a `LocalOffset` type #1563

Open pitdicker opened 7 months ago

pitdicker commented 7 months ago

Currently the type returned for DateTimes with a Local time zone is a FixedOffset. This makes it impossible to add information to the DateTime such as the time zone name, abbreviation, or DST status.

For 0.5 we should instead return a LocalOffset type. That will allow us to expose more information in the future.

pitdicker commented 7 months ago

(Not a reply, just some things I'm thinking about.)

Summer and winter time

The concepts of 'daylight saving time', 'standard time', 'summer time' and 'winter time' are related but not the same. The IANA time zone database mostly concerns itself with the 'standard time' within a time zone, and encodes any deviations of that as 'saving'.

What is called 'summer time' often matches 'daylight saving time', with 'winter time' being the standard time. But countries may just as well define their 'summer time' the be the 'standard time', in which case 'winter time' will be encoded as 'saving'. Then there are many time zones that don't make a distinction between either, or only made the distinction for a couple of years. And of course Utc, FixedOffset and possibly others have no way to tell.

There can be reasons other than the seasons to switch to/from the standard offset within a time zone. In the US during World War II there has been 'war time', with a three year long DST. Or summer time (to make optimal use of daylight) may temporary revert to standard time during ramadan (where you eat beyond daylight). Contries may also move away from DST, and declare their daylight saving time to last the whole year. At this point it becomes the 'standard time' and is encoded as such in the database.

From only the DST info with Standard, Saving and Unknown it is not possible to say anything about 'summer time' and 'winter time' that is always correct.

However in a TimeZone implementation there is enough info to tell. For example it is 'summer time' or 'winter time' if the time zone alternates between standard time and DST around this date and the period covers a good part of the summer or winter for the hemispere of that time zone. Whether it alternates is something you can't tell from the offset of a single date (unless we encode that info in the offset). And if summer is around july or january is also not hard to tell with the continents already giving a good basis (which is not difficult info but implementation-dependend).

Because users may expect 'daylight saving time' to be the same thing as 'summer time', we should consider this difference instead of only naively exposing the basic data.


The time zone database contains a treasure trove of documentation around DST weirdness. Before suggesting a definitive API I'd like to read all the documentation the database has around it. That seems doable.

Some parts from the database:

Greenland

  • The bill to move America/Nuuk from UTC-03 to UTC-02 passed.
  • The bill to stop observing DST did not (Greenland will stop observing DST when EU does).

Details on the implementation are here (section 6): https://ina.gl/dvd/EM%202022/pdf/media/2553529/pkt17_em2022_tidens_bestemmelse_bem_da.pdf This is how the change will be implemented:

  1. The shift to DST in 2023 happens as normal.
  2. The shift from DST in 2023 happens as normal, but coincides with the shift to UTC-02 normaltime (people will not change their clocks here).
  3. After this, DST is still observed, but as -02/-01 instead of -03/-02.

Ireland

… Ireland's Standard Time (Amendment) Act, 1971 states that standard time in Ireland remains at UT +01 and is observed in summer, and that Greenwich mean time is observed in winter. That is, when Ireland amended the 1968 act that established UT +01 as Irish Standard Time, it left standard time unchanged and established GMT as a negative daylight saving time in winter. … See: http://www.irishstatutebook.ie/eli/1971/act/17/enacted/en/print

Czech Republic and Slovakia (Europe/Prague)

From 1947 to 1979 Czechoslovakia had a standard time and a winter time where the winter time differed by -1:00 hour from standard time.

Marocco

Marocco has a super complex story when it comes to DST. It has a summer time, to make more use of the available daylight, but switches back to standard time during the ramadan (to eat after dark). This caused four DST changes per year in 2012 to 2016. And in 2018 it switched its definition of standard time, causing the 'saving' time to have a -1:00 hour offset to the standard time.

Namibia

Namibia is going to change their time zone to what is now their DST: https://www.newera.com.na/2017/02/23/namibias-winter-time-might-be-repealed/ … We have made the assumption so far that they will change their time zone at the same time they would normally start DST, the first Sunday in September.

Before the change, summer and winter time were both standard time legally. However in common parlance, winter time was considered to be DST. See, e.g.: http://www.nbc.na/news/namibias-winter-time-could-be-scrapped.2706 https://zone.my.na/news/times-are-changing-in-namibia https://www.newera.com.na/2017/02/23/namibias-winter-time-might-be-repealed/

Moscow

Russia observed DST until it switched to permanent 'summer time' all year long in 2011. In October 2014 it witched to permanent standard time.The time zone database does not encode a permanent 'summer time', but considers this a change to the standard time.

pitdicker commented 7 months ago

Can you link to the requests you've seen for this so we can get the full detail of the use cases (to the extent provided)?

:+1: After searching for it again I can only find two... https://github.com/chronotope/chrono/issues/235 and https://github.com/chronotope/chrono-tz/issues/130. https://github.com/chronotope/chrono/issues/10#issuecomment-252369486 and https://github.com/chronotope/chrono/issues/120 are not clear.

I would be inclined to make this method return just Option<FixedOffset>. This seems a lot simpler and it's not obvious to me what the benefit is for distinguishing between unknown and "standard" time.

I like returning an Option but am not sure yet if we shouldn't even return more variants or another type.

The story for chrono seems similar to std::string, which not always has the simple methods of other languages in order to be correct with UTF-8. Our first concern should be to return info that allows code to be written correctly, including for less common time zones (such as summer or winter time outside the US and Europe).

Also I think it is good to have one method on a trait that returns all info that is available. Other methods can be added to the Offset trait with default implementation or to DateTime if we want to give a simpler result.

djc commented 7 months ago

Appreciate all the research into this!

At the same time, I'm wary of adding substantial complexity to chrono on account of a tiny majority of use cases. Correctness and precision are not exactly the same thing, and it feels to me like you're chasing a level of precision here the requirement for which might be extremely rare, and, as such, not a great fit for a general purpose library such as chrono.

The only blocker here for 0.5 seems to be that we have a separate type LocalOffset which can expose more information. We could also seal the Offset trait so that we can more easily add functions to it later.

pitdicker commented 7 months ago

Sorry, replied in the wrong issue. Yes, I would only like to see a LocalOffset with nothing else for 0.5. The rest would not be a breaking change.