mirror of
https://github.com/BurntSushi/jiff.git
synced 2025-12-23 08:47:45 +00:00
repository state before leap second removal
This commit is contained in:
parent
e4dfabe415
commit
ee0cced9c0
83 changed files with 40572 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
|||
/Cargo.lock
|
||||
/target
|
||||
/tmp
|
||||
/ecma-test262
|
||||
|
|
|
|||
42
Cargo.toml
42
Cargo.toml
|
|
@ -6,3 +6,45 @@ description = "WIP"
|
|||
license = "Unlicense OR MIT"
|
||||
edition = "2021"
|
||||
exclude = ["/.github", "/tmp"]
|
||||
autotests = false
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = ["alloc"]
|
||||
alloc = []
|
||||
logging = ["dep:log"]
|
||||
|
||||
[dependencies]
|
||||
log = { version = "0.4.21", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
anyhow = "1.0.81"
|
||||
env_logger = "0.11.3"
|
||||
insta = "1.38.0"
|
||||
quickcheck = { version = "1.0.3", default-features = false }
|
||||
tabwriter = "1.4.0"
|
||||
walkdir = "2.5.0"
|
||||
|
||||
[[test]]
|
||||
path = "tests/lib.rs"
|
||||
name = "integration"
|
||||
|
||||
[profile.test]
|
||||
opt-level = 3
|
||||
|
||||
[profile.testrelease]
|
||||
inherits = "test"
|
||||
debug-assertions = false
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
# We want to document all features.
|
||||
all-features = true
|
||||
# Since this crate's feature setup is pretty complicated, it is worth opting
|
||||
# into a nightly unstable option to show the features that need to be enabled
|
||||
# for public API items. To do that, we set 'docsrs', and when that's enabled,
|
||||
# we enable the 'doc_auto_cfg' feature.
|
||||
#
|
||||
# To test this locally, run:
|
||||
#
|
||||
# RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
|
|
|||
663
NOTES.md
Normal file
663
NOTES.md
Normal file
|
|
@ -0,0 +1,663 @@
|
|||
Links:
|
||||
|
||||
* [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html)
|
||||
* [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339)
|
||||
* [Syntax extensions to RFC 3339](https://ryzokuken.dev/draft-ryzokuken-datetime-extended/documents/rfc-3339.html)
|
||||
* [RFC 8536](https://datatracker.ietf.org/doc/html/rfc8536)
|
||||
* [New RFC 8536](https://datatracker.ietf.org/doc/draft-murchison-rfc8536bis/)
|
||||
* [RFC 9557](https://www.rfc-editor.org/rfc/rfc9557.html)
|
||||
* [RFC 2822 datetimes](https://datatracker.ietf.org/doc/html/rfc2822#section-3.3)
|
||||
* [FreeDesktop.org on localtime](https://www.freedesktop.org/software/systemd/man/latest/localtime.html)
|
||||
* [About the IANA Time Zone Database](https://data.iana.org/time-zones/tz-link.html)
|
||||
* [Lisp code for *Calendrical calculations*](https://github.com/EdReingold/calendar-code2)
|
||||
* [SOFA](https://www.iausofa.org/)
|
||||
* [MUSL `tzset`](https://git.musl-libc.org/cgit/musl/tree/src/time/__tz.c#n127)
|
||||
* [Talk about leap seconds](https://www.youtube.com/watch?v=meK8dY9l_gE&t=9s)
|
||||
* [Toward a Standard C++ ’Date’ Class](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3344.pdf)
|
||||
* [2023-02 - Calendrical C++: std::chrono, History, Mathematics and the Computus - Ben Deane](https://www.youtube.com/watch?v=fIWDQclgUEE)
|
||||
* [Local Time Disambiguation (PEP 495)](https://peps.python.org/pep-0495/)
|
||||
* [Temporal tests](https://github.com/tc39/test262/tree/main/test/built-ins/Temporal)
|
||||
* [Modeling Time - Eric Evans (Joda Time?)](https://www.youtube.com/watch?v=T29WzvaPNc8&t=657s)
|
||||
* [Fixing JavaScript Date – Getting Started](https://maggiepint.com/2017/04/09/fixing-javascript-date-getting-started/)
|
||||
* [PEP-4095](https://peps.python.org/pep-0495/)
|
||||
* [Temporal API blog](https://2ality.com/2021/06/temporal-api.html)
|
||||
|
||||
|
||||
Other Rust crates:
|
||||
|
||||
* [chrono](https://github.com/chronotope/chrono)
|
||||
* [chrono-tz](https://github.com/chronotope/chrono-tz)
|
||||
* [time](https://github.com/time-rs/time)
|
||||
* [icu_calendar](https://docs.rs/icu_calendar/latest/icu_calendar/)
|
||||
* [hifitime](https://docs.rs/hifitime/latest/hifitime/index.html)
|
||||
* [hifitime model checking](https://model-checking.github.io/kani-verifier-blog/2023/03/31/how-kani-helped-find-bugs-in-hifitime.html)
|
||||
* [kine](https://crates.io/crates/kine)
|
||||
* [Flexible datetime parsing](https://crates.io/crates/parse_datetime)
|
||||
* [eos](https://github.com/Rapptz/eos) (unfinished/unpublished)
|
||||
* [temporal_rs](https://github.com/boa-dev/temporal)
|
||||
* [tz-rs](https://github.com/x-hgg-x/tz-rs)
|
||||
* [iana-time-zone](https://github.com/strawlab/iana-time-zone)
|
||||
* [parse-zoneinfo](https://github.com/chronotope/parse-zoneinfo)
|
||||
* [tzfile](https://github.com/kennytm/tzfile)
|
||||
|
||||
Other datetime libraries:
|
||||
|
||||
* [ThreeTen](https://www.threeten.org/threeten-extra/). Seems to have good
|
||||
support for leap seconds. See https://github.com/robinst/java-threeten-test.
|
||||
|
||||
Read/perused:
|
||||
|
||||
* [Time Standards Reference](https://geometrian.com/programming/reference/timestds/index.php)
|
||||
* [Actual leap seconds](https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list)
|
||||
* [Even more leap seconds](https://maia.usno.navy.mil/ser7/tai-utc.dat)
|
||||
* [ISO 8601 summary](https://www.cl.cam.ac.uk/~mgk25/iso-time.html)
|
||||
* [POSIX `TZ` environment variable](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html)
|
||||
* [Joda Time User Guide](https://www.joda.org/joda-time/userguide.html)
|
||||
* [JSR 310](https://jcp.org/aboutJava/communityprocess/pfd/jsr310/JSR-310-guide.html)
|
||||
* [`java.time` API](https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html)
|
||||
* [Leap seconds](https://en.wikipedia.org/wiki/Leap_second)
|
||||
* [Koka's standard `time` library](https://koka-lang.github.io/koka/doc/std_time.html)
|
||||
* ["Seconds Since the Epoch"](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16)
|
||||
* [Storing UTC is not a silver bullet](https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a-silver-bullet/)
|
||||
* [Unix time and leap seconds](https://en.wikipedia.org/wiki/Unix_time#Leap_seconds)
|
||||
* [UTC-SLS](https://www.cl.cam.ac.uk/~mgk25/time/utc-sls/)
|
||||
* [`time` crate's issue on `localtime_r` unsoundness](https://github.com/time-rs/time/issues/293)
|
||||
* [Pure Rust implementation of `localtime_r`](https://github.com/x-hgg-x/tz-rs)
|
||||
* [Interesting issue about TAI support in Chrono](https://github.com/chronotope/chrono/issues/21)
|
||||
* [NIST leap seconds via FTP](ftp://ftp.boulder.nist.gov/pub/time/leap-seconds.list)
|
||||
* [Interesting use case from dtolnay for `Date` type](https://github.com/chronotope/chrono/issues/820)
|
||||
* [Desirable characteristics of time systems](https://www.ucolick.org/~sla/leapsecs/picktwo.html)
|
||||
* [TC39 rejecting leap second handling](https://github.com/tc39/proposal-temporal/issues/54)
|
||||
* [cctz philosophy](https://github.com/google/cctz#fundamental-concepts)
|
||||
* [Russ Cox on "absolute" vs "civil" time](https://github.com/golang/go/issues/19700#issuecomment-559250634)
|
||||
* [Javascript code for converting between TAI and Unix](https://github.com/qntm/t-a-i)
|
||||
* [TC39 "Temporal"](https://tc39.es/proposal-temporal/docs/)
|
||||
* [TC39 Polyfill](https://github.com/js-temporal/temporal-polyfill)
|
||||
* [TC39 on non-standard IANA time zone suffix](https://tc39.es/proposal-temporal/docs/strings.html#iana-time-zone-names)
|
||||
* [Java's description of the same thing](https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_ZONED_DATE_TIME)
|
||||
* [Proposed RFC3339 Update](https://datatracker.ietf.org/wg/sedate/about/)
|
||||
* [RFC 5545 (iCalendar) on date arithmetic](https://datatracker.ietf.org/doc/html/rfc5545#section-3.3.6)
|
||||
* [Previous section on datetime](https://datatracker.ietf.org/doc/html/rfc5545#section-3.3.5)
|
||||
* [C++ Chrono Extension](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0355r7.html)
|
||||
* [How gcc's libstdc++'s chrono library deals with leap seconds](https://github.com/gcc-mirror/gcc/blob/c1d1571329b4e0923a104b6139cd7db2f0aa1c1d/libstdc%2B%2B-v3/include/std/chrono#L3207)
|
||||
* [Some nice insight into C++ chrono's handling of leap seconds](https://stackoverflow.com/a/56620657)
|
||||
* [Proleptic Gregorian Calendar](https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar)
|
||||
* ["A Brief History of Leap Seconds"](https://www.youtube.com/watch?v=meK8dY9l_gE&t=9s)
|
||||
* ["The Long, Painful History of Time"](https://naggum.no/lugm-time.html)
|
||||
* This has an interesting idea to use 2000-03-01 as the epoch.
|
||||
* [TC39 "Temporal"](https://tc39.es/proposal-temporal/docs/)
|
||||
* [Time zones](https://en.wikipedia.org/wiki/Time_zone)
|
||||
* [TAI timezone with TC39 for leap seconds](https://github.com/ryzokuken/temporal-tai)
|
||||
* [On missing leap second support in Luxon](https://github.com/moment/luxon/issues/1176)
|
||||
* [JSR-310 and leap seconds](https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html)
|
||||
* [`Clock` explicitly says leap seconds are usually ignored](https://docs.oracle.com/javase/8/docs/api/java/time/Clock.html)
|
||||
* [More on JDK not supporting leap seconds](https://stackoverflow.com/questions/30984599/how-does-the-oracle-java-jvm-know-a-leap-second-is-occurring)
|
||||
* [Time4J apparently handles leap seconds](https://github.com/MenoData/Time4J)
|
||||
* [`time` Rust crate and leap seconds](https://github.com/time-rs/time/discussions/413)
|
||||
* [ICU timezone detection](https://github.com/nodejs/node/blob/5d0a770c129c00e3942263b429f8efa4c42efba9/deps/icu-small/source/common/putil.cpp#L1065)
|
||||
* [Low level date algorithms](http://howardhinnant.github.io/date_algorithms.html)
|
||||
* [Howard Hinnat's C++ `date` library](https://github.com/howardhinnant/date)
|
||||
* [CppCon 2015: Howard Hinnant “A C++14 approach to dates and times"](https://www.youtube.com/watch?v=tzyGjOm8AKo)
|
||||
* ["Date Algorithms" by Peter Baum](https://www.researchgate.net/publication/316558298_Date_Algorithms)
|
||||
* [A discussion about ranged integers in Rust](https://github.com/rust-lang/rfcs/issues/671)
|
||||
* [A possibly simpler implementation of Temporal's rounding](https://github.com/fullcalendar/temporal-polyfill/blob/main/packages/temporal-polyfill/src/internal/round.ts)
|
||||
* [On the naming of types in Temporal](https://github.com/unicode-org/icu4x/issues/2583#issuecomment-1251846194)
|
||||
* [On time zone abbreviations](https://github.com/tc39/proposal-temporal/issues/1694)
|
||||
* [Commit adding `chrono` to `libstdc++ in `gcc`](https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=9fc61d45fa15fdd3b084d30998ecda164af33e95)
|
||||
* This also explains why only `tzdata.zi` is used.
|
||||
* [Interesting case of (I think?) UB for a simple use of C++/Chrono](https://old.reddit.com/r/cpp/comments/l755me/stdchrono_question_of_the_day_whats_the_result_of/)
|
||||
* [See also Howard Hinnant's response about Chrono's ability to use different representations for different units.](https://old.reddit.com/r/cpp/comments/l755me/stdchrono_question_of_the_day_whats_the_result_of/hul90k4/)
|
||||
* Interestingly Hinnant does not seem to comment on the UB...
|
||||
* Oh, he does comment [here](https://old.reddit.com/r/cpp/comments/l755me/stdchrono_question_of_the_day_whats_the_result_of/gl6y9cg/).
|
||||
* And [here](https://old.reddit.com/r/cpp/comments/l755me/stdchrono_question_of_the_day_whats_the_result_of/gl8hmph/).
|
||||
* Yes yes, "henny penny" and chicken little, har har har. But I thought
|
||||
modern C++ was getting safer? LOL. Like I get what Howard is saying. It's
|
||||
hard to do any better given what C++ is today. But man, the self reflection
|
||||
(for C++ as a whole) is just missing from a lot (not all) discourse.
|
||||
* [A Foundation to Sleep On](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm)
|
||||
* [StackOverflow info on `timezone` tag](https://stackoverflow.com/tags/timezone/info)
|
||||
* This is (to me) surprisingly practical and useful.
|
||||
* [Nice description of `TZ` env var](https://www.gnu.org/software/libc/manual/2.25/html_node/TZ-Variable.html)
|
||||
* [Tricky handling of `GetDynamicTimeZoneInformation` on Windows](https://github.com/unicode-org/icu/blob/943b0ca31b38f5c7ba8d58c5f3d88d34c4ebff8d/icu4c/source/common/wintz.cpp#L63-L88)
|
||||
* [SPICE on UTC/TAI/etc](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/FORTRAN/req/time.html#SPICE%20Time%20Representations)
|
||||
* [Getting TAI time on Linux requires configuration](https://www.bortzmeyer.org/tai-on-debian.html)
|
||||
|
||||
Links with specific targeted info that might be useful:
|
||||
|
||||
* [`TZ` can be ambiguous](https://github.com/chronotope/chrono/issues/1153)
|
||||
* [OpenWRT support in Chrono](https://github.com/chronotope/chrono/issues/1129)
|
||||
* [Support for Android in Hinnant's C++ `date` library](https://github.com/HowardHinnant/date/pull/628)
|
||||
* [`TZ` can be ambiguous](https://github.com/chronotope/chrono/issues/1153)
|
||||
* [`tzdb` git repo](https://github.com/eggert/tz)
|
||||
* [Interesting case for datetime difference with timezone](https://github.com/tc39/proposal-temporal/pull/2760#issuecomment-1965355111)
|
||||
* [Finding 25-hour leap days. Do this with `jiff`!](https://typesandtimes.net/2024/02/kazakhstan-25-hour-leap-years)
|
||||
* [Curious rounding bug.](https://github.com/tc39/proposal-temporal/issues/2790#issuecomment-1971250440)
|
||||
* [Nice date arithmetic/rounding test cases](https://github.com/tc39/proposal-temporal/issues/998#issuecomment-716764012)
|
||||
* [Specific use cases for duration rounding](https://github.com/tc39/proposal-temporal/issues/856)
|
||||
* [Good test case for subtracting zoned times](https://github.com/tc39/proposal-temporal/pull/2760#issue-2103137194)
|
||||
* Rounding:
|
||||
* [Proposal: Rounding method (and rounding for difference and toString) for non-Duration types](https://github.com/tc39/proposal-temporal/issues/827)
|
||||
* [Proposal: rounding and balancing for Duration type (replaces #789)](https://github.com/tc39/proposal-temporal/issues/856)
|
||||
* [Interesting case of rounding to months](https://github.com/tc39/proposal-temporal/issues/2535)
|
||||
* [difference should always return a "top-heavy balanced" duration with largest-first order of operations](https://github.com/tc39/proposal-temporal/issues/993#issuecomment-709711892)
|
||||
* [Inconsistent results in DifferenceISODate?](https://github.com/tc39/proposal-temporal/issues/2535)
|
||||
* [Discussion thread for resolution of weeks rounding bug](https://github.com/tc39/proposal-temporal/issues/2728)
|
||||
* [Android's support for time zones appears weak](https://github.com/chronotope/chrono/pull/1018#issuecomment-1536311725)
|
||||
* [Detecting system time zone (Rust/Chrono)](https://github.com/chronotope/chrono-tz/issues/13)
|
||||
* [timestamp() doesn't match Display (Rust/Chrono)](https://github.com/chronotope/chrono/issues/318)
|
||||
* [add/sub days (Rust/Chrono)](https://github.com/chronotope/chrono/pull/784)
|
||||
* [Provide docs that do an audit of calendrical fallacies](https://yourcalendricalfallacyis.com/)
|
||||
* [Relative duration rounding](https://github.com/tc39/proposal-temporal/issues/2792#issuecomment-2058186806)
|
||||
|
||||
Commentary on Rust datetime libraries
|
||||
-------------------------------------
|
||||
* [A comment thread on Chrono's API being complex.](https://old.reddit.com/r/rust/comments/18i8y39/learning_rust_my_experience_so_far_has_been_mixed/)
|
||||
* [Chrono and locales](https://old.reddit.com/r/rust/comments/19cup9v/how_to_parse_datetime_in_locale_other_than_english/)
|
||||
|
||||
How to deal with the environment
|
||||
--------------------------------
|
||||
It seems there are at least 3 relevant environment variables? `TZ`, defined by
|
||||
POSIX. Then there's [`TZDIR`](https://github.com/chronotope/chrono/issues/1265)
|
||||
which is used by glibc. And then I think `ZONEINFO` is used by Go.
|
||||
|
||||
`TZ` is fine. I know how to deal with that. But what happens if both `TZDIR`
|
||||
and `ZONEINFO` are defined?
|
||||
|
||||
It seems like [`TZDIR` is more broadly supported](https://man7.org/linux/man-pages/man8/tzselect.8.html).
|
||||
|
||||
I'm unsure of the origins of the `ZONEINFO` environment variable. Is this just
|
||||
Go being a special snowflake?
|
||||
|
||||
It seems like we should ignore `ZONEINFO` but respect `TZDIR`. If users demand
|
||||
it, we could fallback to `ZONEINFO`, but only if `TZDIR` is unset/empty.
|
||||
|
||||
How weeks are handled in rounding
|
||||
---------------------------------
|
||||
From: https://github.com/tc39/proposal-temporal/issues/827
|
||||
|
||||
Specifically: if largestUnit is 'month' or 'year' and smallestUnit is 'day' or
|
||||
smaller, then weeks will always be zero and only days and/or months will be
|
||||
included in the result. Edge cases that are NOT ambiguous are noted below.
|
||||
|
||||
7.7.1 If smallestUnit is 'week', then there is no ambiguity and any remainder
|
||||
will go into week.
|
||||
7.7.2 If largestUnit is 'day', then there is no ambiguity because weeks are
|
||||
excluded and week will be zero.
|
||||
7.7.3 In the degenerate case of { largestUnit: 'week', smallestUnit: 'day' }
|
||||
then there is also no ambiguity so both fields will be populated.
|
||||
|
||||
Names
|
||||
-----
|
||||
|
||||
* `wheel`
|
||||
* `gigawatt`
|
||||
* `pend`
|
||||
* `planck`
|
||||
* `jiff`, `jiffy`
|
||||
|
||||
|
||||
2024-02-28
|
||||
----------
|
||||
* I really don't like the name `jiff::Time`. I don't mind the name
|
||||
`jiff::ZonedTime` (not yet defined), but `jiff::Time` and `jiff::civil::Time`
|
||||
having the same type name is just super annoying. At first I thought it would
|
||||
be fine since a `civil::Time` is basically never used, so who cares what it's
|
||||
called since it's stuffed away in its own module. But a `civil::DateTime` will
|
||||
very likely be used occasionally, and if we renamed `civil::Time` to, say,
|
||||
`civil::Clock`, then the `civil::DateTime` name would no longer make much
|
||||
sense. `civil::DateTime` is pretty much the canonical name for what it is,
|
||||
so... we should leave it. And that means `civil::Time` stays. Which in turn
|
||||
means we probably need a different name for `jiff::Time`. The most obvious
|
||||
alternative is `jiff::Instant`, but this would be too confusing of a conflict
|
||||
with `std::time::Instant`. *sigh* Other ideas: `TimePoint`, `AbsoluteTime`,
|
||||
`TimeInstant`, `Point`, `Moment`. Bah. I want one word. And that word should
|
||||
combine nicely with a `Zoned` prefix. UPDATE(2024-03-16): I ended up going with
|
||||
`jiff::Instant` and `jiff::Zoned`. I'm still not 100% solid on those names,
|
||||
but I haven't found an alternative that I like better.
|
||||
|
||||
* We should probably balance `Span` values before returning them. See what the
|
||||
`civil::Time` type currently returns for example. Just sticking to nanoseconds
|
||||
and requiring users to explicitly round/balance is very likely to confuse them.
|
||||
UPDATE(2024-03-16): Unfortunately, balancing by default means that sometimes
|
||||
the ops won't be commutative, particularly for dates. We can balance times, but
|
||||
nothing above the unit of "day."
|
||||
|
||||
* Add a cutesy API for easily building `Span` values. For example, perhaps
|
||||
via a `ToSpan` trait, `2.hours() + 10.minutes()`. UPDATE(2024-03-16): Done, but
|
||||
I'm still not 100% happy with it.
|
||||
|
||||
* We still need to figure out rounding in `Span` and how to deal with the
|
||||
`relative-to` nonsense. I want to store it on the `Span`, but this could be
|
||||
confusing at points. The alternative is to do what Temporal does and ask for
|
||||
`relative-to` whenever rounding occurs. But this just... seems like overkill?
|
||||
Temporal also allows one to pass the rounding options to most/all of the
|
||||
date arithmetic methods, which is also something I really don't want to do.
|
||||
UPDATE(2024-03-16): `relative-to` is only needed when rounding durations, so
|
||||
we'll just allow users to provide it at that point. We also will not do any
|
||||
rounding as part of computing spans in the first place, so we side-step needing
|
||||
to deal with duration rounding complexity everywhere. This does mean users will
|
||||
need to do duration rounding explicitly if they want it though, so this case
|
||||
will be a bit more verbose/annoying than Temporal proper.
|
||||
|
||||
* We are otherwise getting pretty close to a point where we have most of the
|
||||
fundamental pieces built. And now we just need to kind of put everything
|
||||
together and start layering the timezone, parsing and formatting bullshit on
|
||||
top of it. I had expected the base layers to require more code. Am I missing
|
||||
anything? The rounding is potentially one big one, but it doesn't seem awful.
|
||||
UPDATE(2024-03-16): No, rounding is awful. Saving that for when timezone stuff
|
||||
is implemented.
|
||||
|
||||
* What about things like, "find the 4th Thursday in March 2024?" I think this
|
||||
is just a matter of knowing what day a year began with. UPDATE(2024-03-16):
|
||||
This is done. Along with "find the next Nth weekday."
|
||||
|
||||
* Do we need explicit millisecond and microsecond fields on `Span`? The
|
||||
icky part is that they will be two additional `i64` values, which seems
|
||||
very non-ideal. But if we don't have them, then do we still support
|
||||
rounding/balancing them? I don't think we can, because then, e.g, milliseconds
|
||||
and microseconds can't be "more." We have no real way to distinguish them
|
||||
from one another. Sigh... UPDATE(2024-03-16): Yeah I just bit the bullet and
|
||||
added them. If size of `Span` truly ends up being an issue, we could consider
|
||||
limiting some fields to `i32` instead of `i64`, but ultimately it will be
|
||||
pretty marginal. I generally don't think we can do much about `Span` being a
|
||||
big type. Probably the work-around for this if it is a problem is to provide
|
||||
alternative lower level APIs that operate on smaller types but aren't as
|
||||
ergonomic.
|
||||
|
||||
* Add panicking variants of arithmetic via Add/Sub. UPDATE(2024-03-16): Done.
|
||||
|
||||
* Flush out the error types a bit more? UPDATE(2024-03-16): I've made
|
||||
incremental progress here, but still not totally happy. The main issue at
|
||||
present is that probably a lot of error messages aren't directly connected
|
||||
to values given by callers. I'm not sure if we can do much better here
|
||||
unfortunately.
|
||||
|
||||
* Settle on a TimeZone design. I've been thinking of having a TimeZoneDatabase
|
||||
trait that `ZonedTime` is generic over (with a default type). The trait would
|
||||
let you add timezones to it, and query it, and you would get `Copy` handles
|
||||
back. The main complication is avoiding the need for time values to hold the
|
||||
database itself. I want to keep times `Copy`. But this really constrains
|
||||
the design of the time zone database and likely means every database has to
|
||||
be a global that can never be freed. e.g., What happens when a `ZonedTime`
|
||||
looks up a timezone handle that no longer exists? So we might just need to
|
||||
accept that a `ZonedTime` is not `Copy`. We could make the timezone itself
|
||||
a type parameter, and some timezones will be `Copy`, but this is a big
|
||||
complication IMO and makes the API harder to understand. But note also that if
|
||||
a `ZonedTime` is not `Copy`, and a `Span` will potentially hold a `ZonedTime`
|
||||
via `relative_to`, then `Span` won't implement `Copy` either. No, `Span` will
|
||||
not hold a `ZonedTime`, so the non-`Copy`ness of `Zoned` won't infect `Span`.
|
||||
|
||||
2024-03-16
|
||||
----------
|
||||
I'm thinking mostly about the timezone database design. At present, I think
|
||||
making all timezones `Copy` is not in the cards. Specifically, a real timezone
|
||||
has potentially lots of data associated with corresponding to DST transitions
|
||||
(among potentially other kinds of transitions, but DST transitions are the
|
||||
common case). That data is variable sized and cannot be `Copy`. Therefore, the
|
||||
only real way to make it `Copy` is to stuff the data into a global database (or
|
||||
one that is passed around) and put a handle in `Zoned` where the handle is just
|
||||
an index into the database. But there are significant problems to this
|
||||
approach:
|
||||
|
||||
* There's no real way to invalidate handles if the user wants to drop the
|
||||
time zone database. So this design effectively requires that any time zone
|
||||
database is global and can never be dropped.
|
||||
* While we can likely button things up for the default case, this design also
|
||||
means that if users use custom time zone databases, then they'll likely be
|
||||
required to make sure they're passing in the right database when the handle
|
||||
needs to be resolved. We could potentially work around this by pushing the
|
||||
database into a type parameter on `Zoned`.
|
||||
* In order to get information about a timezone for a handle, one has to go
|
||||
to the database. We could potentially cache things like offsets in the high
|
||||
bits of a handle, but whenever one needs to consult the timezone transitions
|
||||
(which I think is needed for pretty much everything), we'd have to go to the
|
||||
database. This is likely to be a problem because the database probably wants to
|
||||
be mutable, so that we can update timezone data. This in turn means there could
|
||||
be some gnarly synchronization involved here.
|
||||
|
||||
I overall felt like this was too much complication, particularly without
|
||||
more user feedback. In theory, we could still make *some* values of `Zoned`
|
||||
implement `Copy` by making it generic over a `TimeZone` trait. Then *some*
|
||||
implementations of that trait (say, timezones that are just offsets) could
|
||||
be `Copy`. The problem with this approach IMO is that it pushes folks toward
|
||||
doing the wrong thing because using just the offset is likely to lead to
|
||||
incorrect results because it doesn't deal with DST transitions. So then you
|
||||
wind up in a situation where you have a "fast"-probably-wrong approach and a
|
||||
"slow"-but-correct approach. This is especially quarrelsome because it can
|
||||
impact code architecture where the former is more flexible given its `Copy`
|
||||
impl while the latter is not.
|
||||
|
||||
So I think ultimately what we should do is define a concrete `TimeZone` type,
|
||||
and a `Zoned` has an `Instant` and a `TimeZone`. And that's it. A `TimeZone`
|
||||
type will be reference counted internally so that at least cloning is cheap.
|
||||
The other possible advantage compared to the handle approach is that once a
|
||||
`TimeZone` is constructed, it will never be mutated. Where as with the handle
|
||||
approach, subsequent reads of the database could return different results if
|
||||
the tzdata has changed on disk. The bummer here is using an `Arc` in the first
|
||||
place, since cloning it could become a bottleneck when the `TimeZone` is shared
|
||||
across multiple threads. But I'm not sure I really see a better approach here
|
||||
that doesn't leak memory.
|
||||
|
||||
So if `TimeZone` is just an immutable reference counted type, that means more
|
||||
of the interesting bits are off-loaded to the `TimeZoneDatabase`. Here's what
|
||||
I'm thinking, with the docs here being more of an implementation sketch than
|
||||
user-facing public docs.
|
||||
|
||||
```rust
|
||||
/// Upon construction, the database may do some up-front work.
|
||||
///
|
||||
/// In the case of the binary IANA database commonly found in Unix
|
||||
/// environments, this will traverse the directory structure to load
|
||||
/// all available names of timezones. This is necessary in order to support
|
||||
/// case insensitive timezone lookups. For example, in Go, time.LoadLocation
|
||||
/// for `america/new_york` fails while `America/New_York` succeeds. Internally,
|
||||
/// this will have a `RwLock<Map<Name, Result<TimeZone, Error>>>`.
|
||||
///
|
||||
/// In the case of a plain text IANA database, then the entire set of data
|
||||
/// (hopefully one file via `tzdata.zi`) are loaded into memory since it
|
||||
/// doesn't appear straight-forward to load timezones in an incremental
|
||||
/// fashion. So in this case, we'd use a `Map<Name, TimeZone>`.
|
||||
///
|
||||
/// I think Android also uses a slightly different format here, so we might
|
||||
/// need a third type of IANA, although I think it still ultimately uses the
|
||||
/// same binary format but just compacted into one file.
|
||||
///
|
||||
/// We might implement a third option which uses Windows time zone data, but
|
||||
/// from what I can tell, it's bunk. So I think we'll skip this one initially.
|
||||
///
|
||||
/// And I think this should also be "unavailable" with perhaps a message
|
||||
/// indicating why.
|
||||
pub struct TimeZoneDatabse;
|
||||
|
||||
impl TimeZoneDatabase {
|
||||
/// This tries to load a time zone database from the environmnet in a way
|
||||
/// that is likely to be correct. Here is what I'm thinking:
|
||||
///
|
||||
/// 1. Respect `ZONEINFO` environment variable.
|
||||
/// 2. Use platform to look for binary iana database.
|
||||
/// ~~3. Use platform to look for plain text database.~~
|
||||
/// 4. Fall back to bundled tzdb if available.
|
||||
fn from_env() -> TimeZoneDatabase {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Creates a time zone database that reads a directory of binary IANA
|
||||
/// time zone files.
|
||||
fn from_iana_binary_path(
|
||||
dir: impl AsRef<Path>,
|
||||
) -> Result<TimeZoneDatabase, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Creates a time zone database that reads from a single file containing
|
||||
/// the plain text IANA database. (e.g., `tzdata.zi`.)
|
||||
///
|
||||
/// NOTE: I've scratched the text database support from initial release.
|
||||
fn from_iana_text_path(
|
||||
file: impl AsRef<Path>,
|
||||
) -> Result<TimeZoneDatabase, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Creates a time zone database that reads from zero or more files
|
||||
/// containing the plain text IANA database. (e.g., `[northamerica,
|
||||
/// southamerica]`.)
|
||||
///
|
||||
/// NOTE: I've scratched the text database support from initial release.
|
||||
fn from_iana_text_paths(
|
||||
files: impl IntoIterator<Item = impl AsRef<Path>>,
|
||||
) -> Result<TimeZoneDatabase, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Creates a time zone database that reads from a single stream containing
|
||||
/// the plain text IANA database. (e.g., `tzdata.zi`.)
|
||||
///
|
||||
/// NOTE: I've scratched the text database support from initial release.
|
||||
fn from_iana_text_reader(
|
||||
rdr: impl std::io::Read,
|
||||
) -> Result<TimeZoneDatabase, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns a timezone corresponding to the given name. If one doesn't
|
||||
/// exist or if there was a problem loading it, then an error is returned.
|
||||
///
|
||||
/// Depending on cache settings, this may reuse a previously loaded
|
||||
/// timezone for the given name. If caching is disabled or the previously
|
||||
/// loaded timezone has expired, then the timezone will be re-loaded.
|
||||
fn timezone(&self, name: &str) -> Result<TimeZone, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Sets the cache behavior of this timezone database.
|
||||
///
|
||||
/// When the duration is zero, then no caching will be performed. Timezone
|
||||
/// lookups will always reload data from the underlying source.
|
||||
///
|
||||
/// For the IANA binary database, "no caching" is straight-forward: we just
|
||||
/// always reload from disk.
|
||||
///
|
||||
/// But for the plain text database, does this mean we read and parse the
|
||||
/// entire textual data every time? And when the cache is busted, is that
|
||||
/// what we do? There are pretty extreme differences here, which is why we
|
||||
/// have options to ensure one kind of database or the other.
|
||||
///
|
||||
/// I think we should set a long default (1 day?) here since timezone data
|
||||
/// rarely changes. I'm thinking like one day? I suppose the problem is
|
||||
/// that when you update the timezone data, you'd ideally like for it to
|
||||
/// refreshed somewhat immediately. I suppose we can support that with
|
||||
/// `clear_cache`, although I could imagine that being annyoing. Maybe a
|
||||
/// shorter default TTL like 1 hour would be better?
|
||||
fn time_to_live(&self, duration: Span) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// This clears any cached timezones in this database.
|
||||
///
|
||||
/// This guarantees that any subsequent lookups for a timezone will reload
|
||||
/// the data.
|
||||
fn clear_cache(&self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
tzdb bundling
|
||||
-------------
|
||||
Bundling tzdb within Jiff isn't a good idea because the database changes. And
|
||||
it would be best if such changes didn't require re-compiling the library.
|
||||
|
||||
But, Windows doesn't have a system copy of tzdb. So it's worth bundling in
|
||||
that case.
|
||||
|
||||
We'd therefore like to express a default feature of "bundle tzdb, but only on
|
||||
platforms that probably need it." And also, "you shouldn't need to pay for
|
||||
downloading or compiling this bundled copy if you don't need it." I believe
|
||||
this requires the following setup:
|
||||
|
||||
```toml
|
||||
[features]
|
||||
default = ["tzdb-bundle-platform"]
|
||||
tzdb-bundle-platform = ["dep:jiff-tzdb-platform"]
|
||||
tzdb-bundle-always = ["dep:jiff-tzdb"]
|
||||
|
||||
[dependencies]
|
||||
jiff-tzdb = { version = "0.1", path = "jiff-tzdb", optional = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
jiff-tzdb-platform = { version = "0.1", path = "jiff-tzdb-windows", optional = true }
|
||||
```
|
||||
|
||||
And then make `jiff-tzdb-windows` a crate that literally just re-exports
|
||||
`jiff-tzdb`. This is a bit odd, but I don't think I can accomplish the above
|
||||
setup with just `jiff-tzdb`. The issue is that we need a platform-only
|
||||
dependency to be enabled when `tzdb-bundle-platform` is enabled. That way, for
|
||||
platforms that don't need it, enabling `tzdb-bundle-platform` is a no-op.
|
||||
|
||||
TAI support
|
||||
-----------
|
||||
I think I should add a `Tai` implementation of the `TimeScale` trait. I think
|
||||
that it shouldn't be a simple "marker" type like `Unix` and should instead
|
||||
carry the leap-second table with it. We can provide different ways of
|
||||
constructing the leap-second table, e.g., from a `TimeZoneDatabase` or perhaps
|
||||
a built-in copy or perhaps even from the text-file source itself. Once we have
|
||||
the table and the `Tai` scale, then conversions can be done between `Unix` and
|
||||
`Tai`. Once we have that, differences can be computed between `Instant`s that
|
||||
are accurate.
|
||||
|
||||
Note though that the conversion is necessarily non-lossy. That is, some Unix
|
||||
times can map to two distinct TAI times, and some Unix times might not even
|
||||
exist for a given TAI time. (Although that latter case can only happen when a
|
||||
negative leap second occurs, which has never happened yet.) So we'll need to
|
||||
figure out how to handle those cases. I especially want to make them infallible
|
||||
because these conversions happen in APIs that I otherwise want to be infallible
|
||||
(like `Instant::to_datetime`). We could expose special fallible conversion
|
||||
routines and otherwise do infallible conversions everywhere else. It's probably
|
||||
fine?
|
||||
|
||||
In the case of a fold (positive leap second), we should pick the first, since
|
||||
that's what things like RFC 5545 require and what Temporal does by clamping
|
||||
`23:59:60` to `23:59:59`.
|
||||
|
||||
In the case of a gap (negative leap second), I think there is an unambiguous
|
||||
mapping. That is, the straight-forward thing should just work? Either way, we
|
||||
should be able to pretty easily write a test for it.
|
||||
|
||||
One other complication here is that we probably need to provide a way to build
|
||||
an `Instant` straight from a `TAI` timestamp value. For example, from a
|
||||
`clock_gettime(CLOCK_TAI, ...)` call.
|
||||
|
||||
Feedback from tweets
|
||||
--------------------
|
||||
See: https://twitter.com/burntsushi5/status/1763284928970572112
|
||||
See: https://bsky.app/profile/burntsushi.net/post/3kmld45nj722o
|
||||
|
||||
> 1. want to be able to get a list of timestamps while specifying 3 out of 4 of
|
||||
> these:
|
||||
> - initial timestamp
|
||||
> - final timestamp
|
||||
> - dt
|
||||
> - number of timestamps
|
||||
>
|
||||
> 2. want different options for "rounding" timestamps to different levels of
|
||||
> precision (e.g. ceil/floor/round to month/year/etc)
|
||||
>
|
||||
> I am not a js user but I do a lot of time data processing in python. wrote
|
||||
> this tooltime for the functionality I mention
|
||||
> https://github.com/sslivkoff/tooltime?tab=readme-ov-file#create-standardized-timeperiods
|
||||
>
|
||||
> the get_standard_timeperiod() and get_standard_intervals() are the two
|
||||
> functions that I havent been able to easily find in other libs
|
||||
> (impl here
|
||||
> https://github.com/sslivkoff/tooltime/blob/main/tooltime/timeperiod_utils/timeperiod_standard.py)
|
||||
>
|
||||
> basically making it easy to 1) put messy realworld timestamps into regular
|
||||
> intervals, and 2) being able to easily generate regular intervals under
|
||||
> different parameterizations
|
||||
>
|
||||
> oh thats awesome!!!
|
||||
>
|
||||
> love the modes. probably more than I would ever need with all those half-X
|
||||
> roudingMode's. and not sure the use of largestUnit
|
||||
>
|
||||
> roundingIncrement would be very nice
|
||||
|
||||
> Mostly just easy integration. My biggest pain point was trying to get them to
|
||||
> work with Serde. It's been a while, but it ended up being easier to just make
|
||||
> my own Date type rather than dealing with the errors. Having one DateTime
|
||||
> across crates (Serde, Polars etc.) would be nice.
|
||||
|
||||
> Don't panic. Use rust's error handling. We've fought chrono panics for a
|
||||
> while on @nu_shell, mostly because of cross-platform oddball file system or
|
||||
> file corruption but also things like Windows named pipe dates of 1/1/1601,
|
||||
> IIRC.
|
||||
>
|
||||
> Here's another one while I'm dreaming. :) Precise datetime math that includes
|
||||
> leap calculations but take it a step further and allow the result to be
|
||||
> expressed in a human readable duration that includes decades, years, months,
|
||||
> weeks, days, hours, minutes, seconds, etc.
|
||||
|
||||
> Here's a real answer that I had a professional need for a few years ago: a
|
||||
> natural language-agnostic syntax tree for complicated date/time expressions,
|
||||
> e.g. "the day after next Friday" => DayDelta(NextWeekday(Now, Friday), 1)
|
||||
|
||||
> Clear documentation which representation is used for what. datetime libraries
|
||||
> naturally have to deal with different representations of similar things, that
|
||||
> is just essential complexity. 1/2
|
||||
>
|
||||
> If you add a ton of similar things that are are either just marginally useful
|
||||
> or legacy you end up in chaos. I'm looking at you Java.
|
||||
>
|
||||
> Yes, java.time is good and I realize that what I want is kind of a xkcd/927
|
||||
> problem that cannot be solved by a library alone. What I wish for a library
|
||||
> is that it does not pretend to be the only datetime library in existence, but
|
||||
> acknowledges the fact that there are others.
|
||||
>
|
||||
> To stay with the Java example: Clearly say in the documentation, why
|
||||
> http://java.date.Instance is always better than http://java.util.Date and
|
||||
> what to do if you have to deal with http://java.util.Date for legacy reasons.
|
||||
>
|
||||
> (In my opinion http://java.util.Date should be deprecated completely, but it
|
||||
> isn't. That would send a clear message and prevent a lot of confusion. With
|
||||
> java.time being part of the standard we could have done it. Not in the power
|
||||
> of a new library, though.)
|
||||
>
|
||||
> Also, java.time can keep its API surface minimal by strictly committing to
|
||||
> immutable and thread-safe while completely disregarding performance. Not sure
|
||||
> if we could get away with this in Rust.
|
||||
|
||||
> Consistent use of enums for weekdays / months without needing to use u8
|
||||
|
||||
> Date, DateTime, DateTimeMs to represent different resolutions. I wrote my
|
||||
> own code for this (internal to a project) to keep the complexity down and
|
||||
> make the API coder friendly. I only needed UNIX GMT time. A date-time crate
|
||||
> doesn't have to be hard, but they seem to make it hard
|
||||
>
|
||||
> Yes, UNIX time in seconds, plus milliseconds. Really I'm just improvising
|
||||
> these types as I need them. I needed "round up" and "round down" calls
|
||||
> for N years, quarters, months, weeks, days, hours etc. I found chrono
|
||||
> overcomplicated, overengineered and awkward. Life is short
|
||||
|
||||
> Doing the simple things seems unreasonably hard with Chrono. I shouldn't have
|
||||
> to constantly look up the syntax for getting the current timestamp
|
||||
|
||||
> Strict definition of the output of the Display trait and it being trivial
|
||||
> to parse.
|
||||
|
||||
> Julian/ordinal dates and easy conversion from SAS date, time, and datetime
|
||||
> types, please
|
||||
|
||||
> Configurable precision to reduce on memory consumption in no_std/embedded
|
||||
> devices. Chrono's Duration is i64 + u32. Cc @thibautvandv
|
||||
|
||||
> I would say TC39 Temporal but in Rust. But it seems you are already aware of
|
||||
> it.
|
||||
|
||||
> Currently, calculating the difference in days between two
|
||||
> dates (e.g., implementing the std::ops::Sub trait for
|
||||
> chrono::NaiveDate) requires borrowing the special date calculation
|
||||
> algorithm from the C++20 extension to the std::chrono library
|
||||
> (https://howardhinnant.github.io/date_algorithms.html#days_from_civil).
|
||||
|
||||
> Easier formatting and parsing. It always takes google to solve.
|
||||
|
||||
> I think something such as thread time recorder, meaning that can record the
|
||||
> execution time of a thread and maybe only of that thread, so that we may not
|
||||
> need to use threadlocal types directly.
|
||||
>
|
||||
> I believe that would be a great addition, but just said that felt maybe
|
||||
> relevant here.
|
||||
>
|
||||
> The reason I said that here is because recording time atomically from a time
|
||||
> object itself can be highly convenient wrapper if given.
|
||||
|
||||
> I don't have a use case, but I watched a talk related to Joda time that made
|
||||
> me excited about the challenge of domain modelling durations and periods with
|
||||
> variable resolution as to work well for fuzzy human time like "in about 5
|
||||
> minutes" is encoded as specific date with error
|
||||
|
||||
> Not be terribly over-engineered and make common use-cases available in
|
||||
> <1 minute of reading doc. Reuse std::time::Duration instead of rolling a
|
||||
> separate type. Make working with unix-timestamps comfy: they are everywhere
|
||||
> and expecting to change that is unrealistic.
|
||||
55
scripts/jiff-debug
Executable file
55
scripts/jiff-debug
Executable file
|
|
@ -0,0 +1,55 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This is a script for printing the debug representation of some Jiff types.
|
||||
# Principally, this is for internal types. Ideally we might have a proper
|
||||
# jiff-cli for this, but doing so would require exporting internal types, which
|
||||
# I really don't want to do. Instead, we use unit tests as a sort of CLI target
|
||||
# and pass arguments via environment variables.
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $(basename "$0") (posix-tz | iana-tz | tzif) ..." >&2
|
||||
exit 1
|
||||
fi
|
||||
case "$1" in
|
||||
posix-tz)
|
||||
if [ -z "$2" ]; then
|
||||
echo "Usage: $(basename "$0") posix-tz <time-zone-string>" >&2
|
||||
exit 1
|
||||
fi
|
||||
JIFF_DEBUG_POSIX_TZ="$2" cargo test --quiet --lib --features logging \
|
||||
tz::posix::tests::debug_posix_tz -- --nocapture \
|
||||
> /dev/null
|
||||
;;
|
||||
iana-tz)
|
||||
if [ -z "$2" ]; then
|
||||
echo "Usage: $(basename "$0") iana-tz <time-zone-string>" >&2
|
||||
exit 1
|
||||
fi
|
||||
JIFF_DEBUG_IANA_TZ="$2" cargo test --quiet --lib --features logging \
|
||||
tz::posix::tests::debug_iana_tz -- --nocapture \
|
||||
2>&1 > /dev/null
|
||||
;;
|
||||
tzif)
|
||||
if [ -z "$2" ]; then
|
||||
echo "Usage: $(basename "$0") tzif <path/to/tzif/file>" >&2
|
||||
exit 1
|
||||
fi
|
||||
JIFF_DEBUG_TZIF_PATH="$2" cargo test --quiet --lib --features logging \
|
||||
tz::tzif::tests::debug_tzif -- --nocapture \
|
||||
2>&1 > /dev/null
|
||||
;;
|
||||
zoneinfo-walk)
|
||||
if [ -z "$2" ]; then
|
||||
echo "Usage: $(basename "$0") zoneinfo-walk <path/to/zoneinfo/dir>" >&2
|
||||
exit 1
|
||||
fi
|
||||
JIFF_DEBUG_ZONEINFO_DIR="$2" cargo test --quiet --lib --features logging \
|
||||
tz::db::zoneinfo::tests::debug_zoneinfo_walk -- --nocapture \
|
||||
2>&1 > /dev/null
|
||||
;;
|
||||
*)
|
||||
echo "unrecognized sub-command '$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
2743
src/civil/date.rs
Normal file
2743
src/civil/date.rs
Normal file
File diff suppressed because it is too large
Load diff
1360
src/civil/datetime.rs
Normal file
1360
src/civil/datetime.rs
Normal file
File diff suppressed because it is too large
Load diff
518
src/civil/iso_week_date.rs
Normal file
518
src/civil/iso_week_date.rs
Normal file
|
|
@ -0,0 +1,518 @@
|
|||
use crate::{
|
||||
civil::{Date, Weekday},
|
||||
error::Error,
|
||||
util::{
|
||||
common::is_leap_year_unranged,
|
||||
rangeint::{RFrom, RInto},
|
||||
t::{self, ISOWeek, ISOYear, C},
|
||||
},
|
||||
};
|
||||
|
||||
/// A type representing an [ISO 8601 week date].
|
||||
///
|
||||
/// The ISO 8601 week date scheme devises a calendar where days are identified
|
||||
/// by their year, week number and weekday. All years have either precisely
|
||||
/// 52 or 53 weeks.
|
||||
///
|
||||
/// The first week of an ISO 8601 year corresponds to the week containing the
|
||||
/// first Thursday of the year. For this reason, an ISO 8601 week year can be
|
||||
/// mismatched with the day's corresponding Gregorian year. For example, the
|
||||
/// ISO 8601 week date for `1995-01-01` is `1994-W52-7` (with `7` corresponding
|
||||
/// to Sunday).
|
||||
///
|
||||
/// ISO 8601 also considers Monday to be the start of the week, and uses
|
||||
/// a 1-based numbering system. That is, Monday corresponds to `1` while
|
||||
/// Sunday corresponds to `7` and is the last day of the week. Weekdays are
|
||||
/// encapsulated by the [`Weekday`] type, which provides routines for easily
|
||||
/// converting between different schemes (such as weeks where Sunday is the
|
||||
/// beginning).
|
||||
///
|
||||
/// [ISO 8601 week date]: https://en.wikipedia.org/wiki/ISO_week_date
|
||||
///
|
||||
/// # Use case
|
||||
///
|
||||
/// Some domains use this method of timekeeping. Otherwise, unless you
|
||||
/// specifically want a week oriented calendar, it's likely that you'll never
|
||||
/// need to care about this type.
|
||||
///
|
||||
/// # Default value
|
||||
///
|
||||
/// For convenience, this type implements the `Default` trait. Its default
|
||||
/// value is the first day of the zeroth year. i.e., `0000-W1-1`.
|
||||
///
|
||||
/// # Example: sample dates
|
||||
///
|
||||
/// This example shows a couple ISO 8601 week dates and their corresponding
|
||||
/// Gregorian equivalents:
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::{Date, ISOWeekDate, Weekday};
|
||||
///
|
||||
/// let date = Date::constant(2019, 12, 30);
|
||||
/// let weekdate = ISOWeekDate::new(2020, 1, Weekday::Monday).unwrap();
|
||||
/// assert_eq!(date.to_iso_week_date(), weekdate);
|
||||
///
|
||||
/// let date = Date::constant(2024, 3, 9);
|
||||
/// let weekdate = ISOWeekDate::new(2024, 10, Weekday::Saturday).unwrap();
|
||||
/// assert_eq!(date.to_iso_week_date(), weekdate);
|
||||
/// ```
|
||||
///
|
||||
/// # Example: overlapping leap and long years
|
||||
///
|
||||
/// A "long" ISO 8601 week year is a year with 53 weeks. That is, it is a year
|
||||
/// that includes a leap week. This example shows all years in the 20th
|
||||
/// century that are both Gregorian leap years and long years.
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Date;
|
||||
///
|
||||
/// let mut overlapping = vec![];
|
||||
/// for year in 1900..=1999 {
|
||||
/// let date = Date::constant(year, 1, 1);
|
||||
/// if date.in_leap_year() && date.to_iso_week_date().in_long_year() {
|
||||
/// overlapping.push(year);
|
||||
/// }
|
||||
/// }
|
||||
/// assert_eq!(overlapping, vec![
|
||||
/// 1904, 1908, 1920, 1932, 1936, 1948, 1960, 1964, 1976, 1988, 1992,
|
||||
/// ]);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Hash)]
|
||||
pub struct ISOWeekDate {
|
||||
year: ISOYear,
|
||||
week: ISOWeek,
|
||||
weekday: Weekday,
|
||||
}
|
||||
|
||||
impl ISOWeekDate {
|
||||
/// The maximum representable ISO week date.
|
||||
///
|
||||
/// The maximum corresponds to the ISO week date of the maximum [`Date`]
|
||||
/// value. That is, `-9999-01-01`.
|
||||
pub const MIN: ISOWeekDate = ISOWeekDate {
|
||||
year: ISOYear::new_unchecked(-9999),
|
||||
week: ISOWeek::new_unchecked(1),
|
||||
weekday: Weekday::Monday,
|
||||
};
|
||||
|
||||
/// The minimum representable ISO week date.
|
||||
///
|
||||
/// The minimum corresponds to the ISO week date of the minimum [`Date`]
|
||||
/// value. That is, `9999-12-31`.
|
||||
pub const MAX: ISOWeekDate = ISOWeekDate {
|
||||
year: ISOYear::new_unchecked(9999),
|
||||
week: ISOWeek::new_unchecked(52),
|
||||
weekday: Weekday::Friday,
|
||||
};
|
||||
|
||||
/// The first day of the zeroth year.
|
||||
///
|
||||
/// This is guaranteed to be equivalent to `ISOWeekDate::default()`. Note
|
||||
/// that this is not equivalent to `Date::default()`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::{Date, ISOWeekDate};
|
||||
///
|
||||
/// assert_eq!(ISOWeekDate::ZERO, ISOWeekDate::default());
|
||||
/// // The first day of the 0th year in the ISO week calendar is actually
|
||||
/// // the third day of the 0th year in the proleptic Gregorian calendar!
|
||||
/// assert_eq!(ISOWeekDate::default().to_date(), Date::constant(0, 1, 3));
|
||||
/// ```
|
||||
pub const ZERO: ISOWeekDate = ISOWeekDate {
|
||||
year: ISOYear::new_unchecked(0),
|
||||
week: ISOWeek::new_unchecked(1),
|
||||
weekday: Weekday::Monday,
|
||||
};
|
||||
|
||||
/// Create a new ISO week date from it constituent parts.
|
||||
///
|
||||
/// If the given values are out of range (based on what is representable
|
||||
/// as a [`Date`]), then this returns an error. This will also return an
|
||||
/// error if a leap week is given (week number `53`) for a year that does
|
||||
/// not contain a leap week.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// This example shows some the boundary conditions involving minimum
|
||||
/// and maximum dates:
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::{Date, ISOWeekDate, Weekday};
|
||||
///
|
||||
/// // The year 1949 does not contain a leap week.
|
||||
/// assert!(ISOWeekDate::new(1949, 53, Weekday::Monday).is_err());
|
||||
///
|
||||
/// // Examples of dates at or exceeding the maximum.
|
||||
/// let max = ISOWeekDate::new(9999, 52, Weekday::Friday).unwrap();
|
||||
/// assert_eq!(max, ISOWeekDate::MAX);
|
||||
/// assert_eq!(max.to_date(), Date::constant(9999, 12, 31));
|
||||
/// assert!(ISOWeekDate::new(9999, 52, Weekday::Saturday).is_err());
|
||||
/// assert!(ISOWeekDate::new(9999, 53, Weekday::Monday).is_err());
|
||||
///
|
||||
/// // Examples of dates at or exceeding the minimum.
|
||||
/// let min = ISOWeekDate::new(-9999, 1, Weekday::Monday).unwrap();
|
||||
/// assert_eq!(min, ISOWeekDate::MIN);
|
||||
/// assert_eq!(min.to_date(), Date::constant(-9999, 1, 1));
|
||||
/// assert!(ISOWeekDate::new(-10000, 52, Weekday::Sunday).is_err());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn new(
|
||||
year: i16,
|
||||
week: i8,
|
||||
weekday: Weekday,
|
||||
) -> Result<ISOWeekDate, Error> {
|
||||
let year = ISOYear::try_new("year", year)?;
|
||||
let week = ISOWeek::try_new("week", week)?;
|
||||
ISOWeekDate::new_ranged(year, week, weekday)
|
||||
}
|
||||
|
||||
/// Converts a Gregorian date to an ISO week date.
|
||||
///
|
||||
/// The minimum and maximum allowed values of an ISO week date are
|
||||
/// set based on the minimum and maximum values of a `Date`. Therefore,
|
||||
/// converting to and from `Date` values is non-lossy and infallible.
|
||||
///
|
||||
/// This routine is equivalent to [`Date::to_iso_week_date`]. This
|
||||
/// routine is also available via a `From<Date>` trait implementation for
|
||||
/// `ISOWeekDate`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::{Date, ISOWeekDate, Weekday};
|
||||
///
|
||||
/// let date = Date::constant(1948, 2, 10);
|
||||
/// let weekdate = ISOWeekDate::from_date(date);
|
||||
/// assert_eq!(
|
||||
/// weekdate,
|
||||
/// ISOWeekDate::new(1948, 7, Weekday::Tuesday).unwrap(),
|
||||
/// );
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn from_date(date: Date) -> ISOWeekDate {
|
||||
date.to_iso_week_date()
|
||||
}
|
||||
|
||||
// N.B. I tried defining a `ISOWeekDate::constant` for defining ISO week
|
||||
// dates as constants, but it was too annoying to do. We could do it if
|
||||
// there was a compelling reason for it though.
|
||||
|
||||
/// Returns the year component of this ISO 8601 week date.
|
||||
///
|
||||
/// The value returned is guaranteed to be in the range `-9999..=9999`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Date;
|
||||
///
|
||||
/// let weekdate = Date::constant(2019, 12, 30).to_iso_week_date();
|
||||
/// assert_eq!(weekdate.year(), 2020);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn year(self) -> i16 {
|
||||
self.year_ranged().get()
|
||||
}
|
||||
|
||||
/// Returns the week component of this ISO 8601 week date.
|
||||
///
|
||||
/// The value returned is guaranteed to be in the range `1..=53`. A
|
||||
/// value of `53` can only occur for "long" years. That is, years
|
||||
/// with a leap week. This occurs precisely in cases for which
|
||||
/// [`ISOWeekDate::in_long_year`] returns `true`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Date;
|
||||
///
|
||||
/// let weekdate = Date::constant(2019, 12, 30).to_iso_week_date();
|
||||
/// assert_eq!(weekdate.year(), 2020);
|
||||
/// assert_eq!(weekdate.week(), 1);
|
||||
///
|
||||
/// let weekdate = Date::constant(1948, 12, 31).to_iso_week_date();
|
||||
/// assert_eq!(weekdate.year(), 1948);
|
||||
/// assert_eq!(weekdate.week(), 53);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn week(self) -> i8 {
|
||||
self.week_ranged().get()
|
||||
}
|
||||
|
||||
/// Returns the day component of this ISO 8601 week date.
|
||||
///
|
||||
/// One can use methods on `Weekday` such as
|
||||
/// [`Weekday::to_sunday_zero_offset`] to convert the weekday to a number.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::{Date, Weekday};
|
||||
///
|
||||
/// let weekdate = Date::constant(1948, 12, 31).to_iso_week_date();
|
||||
/// assert_eq!(weekdate.year(), 1948);
|
||||
/// assert_eq!(weekdate.week(), 53);
|
||||
/// assert_eq!(weekdate.weekday(), Weekday::Friday);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn weekday(self) -> Weekday {
|
||||
self.weekday
|
||||
}
|
||||
|
||||
/// Returns true if and only if the year of this week date is a "long"
|
||||
/// year.
|
||||
///
|
||||
/// A long year is one that contains precisely 53 weeks. All other years
|
||||
/// contain precisely 52 weeks.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::{ISOWeekDate, Weekday};
|
||||
///
|
||||
/// let weekdate = ISOWeekDate::new(1948, 7, Weekday::Monday).unwrap();
|
||||
/// assert!(weekdate.in_long_year());
|
||||
/// let weekdate = ISOWeekDate::new(1949, 7, Weekday::Monday).unwrap();
|
||||
/// assert!(!weekdate.in_long_year());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn in_long_year(self) -> bool {
|
||||
is_long_year(self.year_ranged())
|
||||
}
|
||||
|
||||
/// Converts this ISO week date to a Gregorian [`Date`].
|
||||
///
|
||||
/// The minimum and maximum allowed values of an ISO week date are
|
||||
/// set based on the minimum and maximum values of a `Date`. Therefore,
|
||||
/// converting to and from `Date` values is non-lossy and infallible.
|
||||
///
|
||||
/// This routine is equivalent to [`Date::from_iso_week_date`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::{Date, ISOWeekDate, Weekday};
|
||||
///
|
||||
/// let weekdate = ISOWeekDate::new(1948, 7, Weekday::Tuesday).unwrap();
|
||||
/// assert_eq!(weekdate.to_date(), Date::constant(1948, 2, 10));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn to_date(self) -> Date {
|
||||
Date::from_iso_week_date(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ISOWeekDate {
|
||||
/// Creates a new ISO week date from ranged values.
|
||||
///
|
||||
/// While the ranged values given eliminate some error cases, not all
|
||||
/// combinations of year/week/weekday values are valid ISO week dates
|
||||
/// supported by this crate. For example, a week of `53` for short years,
|
||||
/// or more niche, a week date that would be bigger than what is supported
|
||||
/// by our `Date` type.
|
||||
#[inline]
|
||||
pub(crate) fn new_ranged(
|
||||
year: impl RInto<ISOYear>,
|
||||
week: impl RInto<ISOWeek>,
|
||||
weekday: Weekday,
|
||||
) -> Result<ISOWeekDate, Error> {
|
||||
let year = year.rinto();
|
||||
let week = week.rinto();
|
||||
// All combinations of years, weeks and weekdays allowed by our
|
||||
// range types are valid ISO week dates with one exception: a week
|
||||
// number of 53 is only valid for "long" years. Or years with an ISO
|
||||
// leap week. It turns out this only happens when the last day of the
|
||||
// year is a Thursday.
|
||||
//
|
||||
// Note that if the ranges in this crate are changed, this could be
|
||||
// a little trickier if the range of ISOYear is different from Year.
|
||||
debug_assert_eq!(t::Year::MIN, ISOYear::MIN);
|
||||
debug_assert_eq!(t::Year::MAX, ISOYear::MAX);
|
||||
if week == 53 && !is_long_year(year) {
|
||||
return Err(Error::specific("ISO week number", week));
|
||||
}
|
||||
// And also, the maximum Date constrains what we can utter with
|
||||
// ISOWeekDate so that we can preserve infallible conversions between
|
||||
// them. So since 9999-12-31 maps to 9999 W52 Friday, it follows that
|
||||
// Saturday and Sunday are not allowed. So reject them.
|
||||
//
|
||||
// We don't need to worry about the minimum because the minimum date
|
||||
// (-9999-01-01) corresponds also to the minimum possible combination
|
||||
// of an ISO week date's fields: -9999 W01 Monday. Nice.
|
||||
if year == ISOYear::MAX_SELF
|
||||
&& week == 52
|
||||
&& weekday.to_monday_zero_offset()
|
||||
> Weekday::Friday.to_monday_zero_offset()
|
||||
{
|
||||
return Err(Error::signed(
|
||||
"weekday",
|
||||
weekday.to_monday_zero_offset(),
|
||||
Weekday::Monday.to_monday_one_offset(),
|
||||
Weekday::Friday.to_monday_one_offset(),
|
||||
));
|
||||
}
|
||||
Ok(ISOWeekDate { year, week, weekday })
|
||||
}
|
||||
|
||||
/// Like `ISOWeekDate::new_ranged`, but constrains out-of-bounds values
|
||||
/// to their closest valid equivalent.
|
||||
///
|
||||
/// For example, given 9999 W52 Saturday, this will return 9999 W52 Friday.
|
||||
#[inline]
|
||||
pub(crate) fn new_ranged_constrain(
|
||||
year: impl RInto<ISOYear>,
|
||||
week: impl RInto<ISOWeek>,
|
||||
mut weekday: Weekday,
|
||||
) -> ISOWeekDate {
|
||||
let year = year.rinto();
|
||||
let mut week = week.rinto();
|
||||
debug_assert_eq!(t::Year::MIN, ISOYear::MIN);
|
||||
debug_assert_eq!(t::Year::MAX, ISOYear::MAX);
|
||||
if week == 53 && !is_long_year(year) {
|
||||
week = ISOWeek::new(52).unwrap();
|
||||
}
|
||||
if year == ISOYear::MAX_SELF
|
||||
&& week == 52
|
||||
&& weekday.to_monday_zero_offset()
|
||||
> Weekday::Friday.to_monday_zero_offset()
|
||||
{
|
||||
weekday = Weekday::Friday;
|
||||
}
|
||||
ISOWeekDate { year, week, weekday }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn year_ranged(self) -> ISOYear {
|
||||
self.year
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn week_ranged(self) -> ISOWeek {
|
||||
self.week
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ISOWeekDate {
|
||||
fn default() -> ISOWeekDate {
|
||||
ISOWeekDate::ZERO
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for ISOWeekDate {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
f.debug_struct("ISOWeekDate")
|
||||
.field("year", &self.year_ranged().debug())
|
||||
.field("week", &self.week_ranged().debug())
|
||||
.field("weekday", &self.weekday)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ISOWeekDate {}
|
||||
|
||||
impl PartialEq for ISOWeekDate {
|
||||
#[inline]
|
||||
fn eq(&self, other: &ISOWeekDate) -> bool {
|
||||
// We roll our own so that we can call 'get' on our ranged integers
|
||||
// in order to provoke panics for bugs in dealing with boundary
|
||||
// conditions.
|
||||
self.weekday == other.weekday
|
||||
&& self.week.get() == other.week.get()
|
||||
&& self.year.get() == other.year.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for ISOWeekDate {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &ISOWeekDate) -> core::cmp::Ordering {
|
||||
(self.year.get(), self.week.get(), self.weekday.to_monday_one_offset())
|
||||
.cmp(&(
|
||||
other.year.get(),
|
||||
other.week.get(),
|
||||
other.weekday.to_monday_one_offset(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for ISOWeekDate {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &ISOWeekDate) -> Option<core::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Date> for ISOWeekDate {
|
||||
#[inline]
|
||||
fn from(date: Date) -> ISOWeekDate {
|
||||
ISOWeekDate::from_date(date)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl quickcheck::Arbitrary for ISOWeekDate {
|
||||
fn arbitrary(g: &mut quickcheck::Gen) -> ISOWeekDate {
|
||||
let year = ISOYear::arbitrary(g);
|
||||
let week = ISOWeek::arbitrary(g);
|
||||
let weekday = Weekday::arbitrary(g);
|
||||
ISOWeekDate::new_ranged_constrain(year, week, weekday)
|
||||
}
|
||||
|
||||
fn shrink(&self) -> alloc::boxed::Box<dyn Iterator<Item = ISOWeekDate>> {
|
||||
alloc::boxed::Box::new(
|
||||
(self.year_ranged(), self.week_ranged(), self.weekday())
|
||||
.shrink()
|
||||
.map(|(year, week, weekday)| {
|
||||
ISOWeekDate::new_ranged_constrain(year, week, weekday)
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the given ISO year is a "long" year or not.
|
||||
///
|
||||
/// A "long" year is a year with 53 weeks. Otherwise, it's a "short" year
|
||||
/// with 52 weeks.
|
||||
fn is_long_year(year: ISOYear) -> bool {
|
||||
// Inspired by: https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year
|
||||
let last = Date::new_ranged(year, C(12), C(31))
|
||||
.expect("last day of year is always valid");
|
||||
let weekday = last.weekday();
|
||||
let expected_weekday =
|
||||
if last.in_leap_year() { Weekday::Friday } else { Weekday::Thursday };
|
||||
weekday == Weekday::Thursday
|
||||
|| (last.in_leap_year() && weekday == Weekday::Friday)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
quickcheck::quickcheck! {
|
||||
fn prop_all_long_years_have_53rd_week(year: ISOYear) -> bool {
|
||||
!is_long_year(year)
|
||||
|| ISOWeekDate::new(year.get(), 53, Weekday::Sunday).is_ok()
|
||||
}
|
||||
|
||||
fn prop_prev_day_is_less(wd: ISOWeekDate) -> quickcheck::TestResult {
|
||||
use crate::ToSpan;
|
||||
|
||||
if wd == ISOWeekDate::MIN {
|
||||
return quickcheck::TestResult::discard();
|
||||
}
|
||||
let prev_date = wd.to_date().checked_add(-1.days()).unwrap();
|
||||
quickcheck::TestResult::from_bool(prev_date.to_iso_week_date() < wd)
|
||||
}
|
||||
|
||||
fn prop_next_day_is_greater(wd: ISOWeekDate) -> quickcheck::TestResult {
|
||||
use crate::ToSpan;
|
||||
|
||||
if wd == ISOWeekDate::MAX {
|
||||
return quickcheck::TestResult::discard();
|
||||
}
|
||||
let next_date = wd.to_date().checked_add(1.days()).unwrap();
|
||||
quickcheck::TestResult::from_bool(wd < next_date.to_iso_week_date())
|
||||
}
|
||||
}
|
||||
}
|
||||
43
src/civil/mod.rs
Normal file
43
src/civil/mod.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
pub use self::{
|
||||
date::{Date, DateSeries},
|
||||
datetime::{DateTime, DateTimeSeries},
|
||||
iso_week_date::ISOWeekDate,
|
||||
time::{Time, TimeSeries},
|
||||
weekday::{Weekday, WeekdaysForward, WeekdaysReverse},
|
||||
};
|
||||
|
||||
mod date;
|
||||
mod datetime;
|
||||
mod iso_week_date;
|
||||
mod time;
|
||||
mod weekday;
|
||||
|
||||
/// The era corresponding to a particular year.
|
||||
///
|
||||
/// The BCE era corresponds to years less than or equal to `0`, while the CE
|
||||
/// era corresponds to years greater than `0`.
|
||||
///
|
||||
/// In particular, this crate allows years to be negative and also to be `0`,
|
||||
/// which is contrary to the common practice of excluding the year `0` when
|
||||
/// writing dates for the Gregorian calendar. Moreover, common practice eschews
|
||||
/// negative years in favor of labeling a year with an era notation. That is,
|
||||
/// the year `1 BCE` is year `0` in this crate. The year `2 BCE` is the year
|
||||
/// `-1` in this crate.
|
||||
///
|
||||
/// To get the year in its era format, use [`Date::era_year`].
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum Era {
|
||||
/// The "before common era" era.
|
||||
///
|
||||
/// This corresponds to all years less than or equal to `0`.
|
||||
///
|
||||
/// This is precisely equivalent to the "BC" or "before Christ" era.
|
||||
BCE,
|
||||
/// The "common era" era.
|
||||
///
|
||||
/// This corresponds to all years greater than `0`.
|
||||
///
|
||||
/// This is precisely equivalent to the "AD" or "anno Domini" or "in the
|
||||
/// year of the Lord" era.
|
||||
CE,
|
||||
}
|
||||
2080
src/civil/time.rs
Normal file
2080
src/civil/time.rs
Normal file
File diff suppressed because it is too large
Load diff
838
src/civil/weekday.rs
Normal file
838
src/civil/weekday.rs
Normal file
|
|
@ -0,0 +1,838 @@
|
|||
use crate::{
|
||||
error::Error,
|
||||
span::Span,
|
||||
util::{
|
||||
rangeint::{RFrom, RInto},
|
||||
t::{self, C},
|
||||
},
|
||||
};
|
||||
|
||||
/// A representation for the day of the week.
|
||||
///
|
||||
/// The default representation follows ISO 8601. That is, the week starts with
|
||||
/// Monday and numbering starts at `1`. However, the various constructors and
|
||||
/// accessors support using other schemes in wide use:
|
||||
///
|
||||
/// * [`Weekday::from_monday_zero_offset`] builds a weekday from
|
||||
/// a scheme that starts the week on Monday at offset `0`, while
|
||||
/// [`Weekday::to_monday_zero_offset`] converts to it.
|
||||
/// * [`Weekday::from_monday_one_offset`] builds a weekday from a scheme
|
||||
/// that starts the week on Monday at offset `1` (the default representation),
|
||||
/// while [`Weekday::to_monday_one_offset`] converts to it.
|
||||
/// * [`Weekday::from_sunday_zero_offset`] builds a weekday from
|
||||
/// a scheme that starts the week on Sunday at offset `0`, while
|
||||
/// [`Weekday::to_sunday_zero_offset`] converts to it.
|
||||
/// * [`Weekday::from_sunday_one_offset`] builds a weekday from
|
||||
/// a scheme that starts the week on Sunday at offset `1`, while
|
||||
/// [`Weekday::to_sunday_one_offset`] converts to it.
|
||||
///
|
||||
/// # Arithmetic
|
||||
///
|
||||
/// This type provides [`Weekday::wrapping_add`] and [`Weekday::wrapping_sub`]
|
||||
/// for performing wrapping arithmetic on weekdays. These are also available
|
||||
/// via operator overloading:
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Monday + 1, Weekday::Tuesday);
|
||||
/// assert_eq!(Weekday::Sunday - 1, Weekday::Saturday);
|
||||
/// ```
|
||||
///
|
||||
/// # Comparisons
|
||||
///
|
||||
/// This type provides `Eq` and `PartialEq` trait implementations for easy
|
||||
/// comparison:
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Wednesday, Weekday::Wednesday + 7);
|
||||
/// assert_ne!(Weekday::Thursday, Weekday::Friday);
|
||||
/// ```
|
||||
///
|
||||
/// But this type specifically does not provide `Ord` or `PartialOrd` trait
|
||||
/// implementations. Such an implementation would require deciding whether
|
||||
/// Sunday is less than Monday or greater than Monday. The former case
|
||||
/// corresponds to a week scheme where Sunday is the first day in the week,
|
||||
/// where as the latter corresponds to a scheme where Monday is the first day.
|
||||
/// Since both schemes are in widespread use, it would be inappropriate to bake
|
||||
/// in an assumption of one or the other. Instead, one can convert a weekday
|
||||
/// into the desired offset scheme, and then compare the offsets:
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// let (sun, mon) = (Weekday::Sunday, Weekday::Monday);
|
||||
/// assert!(sun.to_sunday_zero_offset() < mon.to_sunday_zero_offset());
|
||||
/// assert!(sun.to_monday_zero_offset() > mon.to_monday_zero_offset());
|
||||
/// ```
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// This example shows the result of converting to and from different schemes:
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// // The different representations of Monday.
|
||||
/// assert_eq!(Weekday::Monday.to_monday_zero_offset(), 0);
|
||||
/// assert_eq!(Weekday::Monday.to_monday_one_offset(), 1);
|
||||
/// assert_eq!(Weekday::Monday.to_sunday_zero_offset(), 1);
|
||||
/// assert_eq!(Weekday::Monday.to_sunday_one_offset(), 2);
|
||||
///
|
||||
/// // The different representations of Sunday.
|
||||
/// assert_eq!(Weekday::Sunday.to_monday_zero_offset(), 6);
|
||||
/// assert_eq!(Weekday::Sunday.to_monday_one_offset(), 7);
|
||||
/// assert_eq!(Weekday::Sunday.to_sunday_zero_offset(), 0);
|
||||
/// assert_eq!(Weekday::Sunday.to_sunday_one_offset(), 1);
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum Weekday {
|
||||
Monday = 1,
|
||||
Tuesday = 2,
|
||||
Wednesday = 3,
|
||||
Thursday = 4,
|
||||
Friday = 5,
|
||||
Saturday = 6,
|
||||
Sunday = 7,
|
||||
}
|
||||
|
||||
impl Weekday {
|
||||
/// Convert an offset to a structured `Weekday`.
|
||||
///
|
||||
/// The offset should be from a scheme where the first day of the week
|
||||
/// is Monday and starts numbering at `0`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This returns an error when the given offset is not in the range
|
||||
/// `0..=6`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// let weekday = Weekday::from_monday_zero_offset(3)?;
|
||||
/// assert_eq!(weekday, Weekday::Thursday);
|
||||
///
|
||||
/// assert!(Weekday::from_monday_zero_offset(7).is_err());
|
||||
/// assert!(Weekday::from_monday_zero_offset(-1).is_err());
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn from_monday_zero_offset(offset: i8) -> Result<Weekday, Error> {
|
||||
let offset = t::WeekdayZero::try_new("weekday", offset)?;
|
||||
Ok(Weekday::from_monday_zero_offset_ranged(offset))
|
||||
}
|
||||
|
||||
/// Convert an offset to a structured `Weekday`.
|
||||
///
|
||||
/// The offset should be from a scheme where the first day of the week
|
||||
/// is Monday and starts numbering at `1`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This returns an error when the given offset is not in the range
|
||||
/// `1..=7`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// let weekday = Weekday::from_monday_one_offset(4)?;
|
||||
/// assert_eq!(weekday, Weekday::Thursday);
|
||||
///
|
||||
/// assert!(Weekday::from_monday_one_offset(8).is_err());
|
||||
/// assert!(Weekday::from_monday_one_offset(0).is_err());
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn from_monday_one_offset(offset: i8) -> Result<Weekday, Error> {
|
||||
let offset = t::WeekdayOne::try_new("weekday", offset)?;
|
||||
Ok(Weekday::from_monday_one_offset_ranged(offset))
|
||||
}
|
||||
|
||||
/// Convert an offset to a structured `Weekday`.
|
||||
///
|
||||
/// The offset should be from a scheme where the first day of the week
|
||||
/// is Sunday and starts numbering at `0`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This returns an error when the given offset is not in the range
|
||||
/// `0..=6`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// let weekday = Weekday::from_sunday_zero_offset(4)?;
|
||||
/// assert_eq!(weekday, Weekday::Thursday);
|
||||
///
|
||||
/// assert!(Weekday::from_sunday_zero_offset(7).is_err());
|
||||
/// assert!(Weekday::from_sunday_zero_offset(-1).is_err());
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn from_sunday_zero_offset(offset: i8) -> Result<Weekday, Error> {
|
||||
let offset = t::WeekdayZero::try_new("weekday", offset)?;
|
||||
Ok(Weekday::from_sunday_zero_offset_ranged(offset))
|
||||
}
|
||||
|
||||
/// Convert an offset to a structured `Weekday`.
|
||||
///
|
||||
/// The offset should be from a scheme where the first day of the week
|
||||
/// is Sunday and starts numbering at `1`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This returns an error when the given offset is not in the range
|
||||
/// `1..=7`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// let weekday = Weekday::from_sunday_one_offset(5)?;
|
||||
/// assert_eq!(weekday, Weekday::Thursday);
|
||||
///
|
||||
/// assert!(Weekday::from_sunday_one_offset(8).is_err());
|
||||
/// assert!(Weekday::from_sunday_one_offset(0).is_err());
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn from_sunday_one_offset(offset: i8) -> Result<Weekday, Error> {
|
||||
let offset = t::WeekdayOne::try_new("weekday", offset)?;
|
||||
Ok(Weekday::from_sunday_one_offset_ranged(offset))
|
||||
}
|
||||
|
||||
/// Returns this weekday as an offset.
|
||||
///
|
||||
/// The offset returned is computed based on a week that starts with Monday
|
||||
/// and begins numbering at `0`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Thursday.to_monday_zero_offset(), 3);
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn to_monday_zero_offset(self) -> i8 {
|
||||
self.to_monday_zero_offset_ranged().get()
|
||||
}
|
||||
|
||||
/// Returns this weekday as an offset.
|
||||
///
|
||||
/// The offset returned is computed based on a week that starts with Monday
|
||||
/// and begins numbering at `1`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Thursday.to_monday_one_offset(), 4);
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn to_monday_one_offset(self) -> i8 {
|
||||
self.to_monday_one_offset_ranged().get()
|
||||
}
|
||||
|
||||
/// Returns this weekday as an offset.
|
||||
///
|
||||
/// The offset returned is computed based on a week that starts with Sunday
|
||||
/// and begins numbering at `0`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Thursday.to_sunday_zero_offset(), 4);
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn to_sunday_zero_offset(self) -> i8 {
|
||||
self.to_sunday_zero_offset_ranged().get()
|
||||
}
|
||||
|
||||
/// Returns this weekday as an offset.
|
||||
///
|
||||
/// The offset returned is computed based on a week that starts with Sunday
|
||||
/// and begins numbering at `1`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Thursday.to_sunday_one_offset(), 5);
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn to_sunday_one_offset(self) -> i8 {
|
||||
self.to_sunday_one_offset_ranged().get()
|
||||
}
|
||||
|
||||
/// Returns the next weekday, wrapping around at the end of week to the
|
||||
/// beginning of the week.
|
||||
///
|
||||
/// This is a convenience routing for calling [`Weekday::wrapping_add`]
|
||||
/// with a value of `1`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Wednesday.next(), Weekday::Thursday);
|
||||
/// assert_eq!(Weekday::Sunday.next(), Weekday::Monday);
|
||||
/// assert_eq!(Weekday::Saturday.next(), Weekday::Sunday);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn next(self) -> Weekday {
|
||||
self.wrapping_add(1)
|
||||
}
|
||||
|
||||
/// Returns the previous weekday, wrapping around at the beginning of week
|
||||
/// to the end of the week.
|
||||
///
|
||||
/// This is a convenience routing for calling [`Weekday::wrapping_sub`]
|
||||
/// with a value of `1`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Wednesday.previous(), Weekday::Tuesday);
|
||||
/// assert_eq!(Weekday::Sunday.previous(), Weekday::Saturday);
|
||||
/// assert_eq!(Weekday::Saturday.previous(), Weekday::Friday);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn previous(self) -> Weekday {
|
||||
self.wrapping_sub(1)
|
||||
}
|
||||
|
||||
/// Returns the number of days from `other` to this weekday.
|
||||
///
|
||||
/// Adding the returned number of days to `other` is guaranteed to sum to
|
||||
/// this weekday. The number of days returned is guaranteed to be in the
|
||||
/// range `0..=6`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Friday.since(Weekday::Tuesday), 3);
|
||||
/// assert_eq!(Weekday::Tuesday.since(Weekday::Tuesday), 0);
|
||||
/// assert_eq!(Weekday::Monday.since(Weekday::Sunday), 1);
|
||||
/// assert_eq!(Weekday::Sunday.since(Weekday::Monday), 6);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn since(self, other: Weekday) -> i8 {
|
||||
self.since_ranged(other).get()
|
||||
}
|
||||
|
||||
/// Returns the number of days until `other` from this weekday.
|
||||
///
|
||||
/// Adding the returned number of days to this weekday is guaranteed to sum
|
||||
/// to `other` weekday. The number of days returned is guaranteed to be in
|
||||
/// the range `0..=6`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Friday.until(Weekday::Tuesday), 4);
|
||||
/// assert_eq!(Weekday::Tuesday.until(Weekday::Tuesday), 0);
|
||||
/// assert_eq!(Weekday::Monday.until(Weekday::Sunday), 6);
|
||||
/// assert_eq!(Weekday::Sunday.until(Weekday::Monday), 1);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn until(self, other: Weekday) -> i8 {
|
||||
self.until_ranged(other).get()
|
||||
}
|
||||
|
||||
/// Add the given number of days to this weekday, using wrapping arithmetic,
|
||||
/// and return the resulting weekday.
|
||||
///
|
||||
/// Adding a multiple of `7` (including `0`) is guaranteed to produce the
|
||||
/// same weekday as this one.
|
||||
///
|
||||
/// Note that this routine is also available via the `+` operator.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Sunday.wrapping_add(1), Weekday::Monday);
|
||||
/// assert_eq!(Weekday::Sunday.wrapping_add(2), Weekday::Tuesday);
|
||||
/// assert_eq!(Weekday::Saturday.wrapping_add(1), Weekday::Sunday);
|
||||
/// assert_eq!(Weekday::Saturday.wrapping_add(7), Weekday::Saturday);
|
||||
/// assert_eq!(Weekday::Sunday.wrapping_add(-1), Weekday::Saturday);
|
||||
/// ```
|
||||
///
|
||||
/// Wrapping arithmetic is also performed by the `+` operator:
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Sunday + 1, Weekday::Monday);
|
||||
/// assert_eq!(Weekday::Sunday + 2, Weekday::Tuesday);
|
||||
/// assert_eq!(Weekday::Saturday + 1, Weekday::Sunday);
|
||||
/// assert_eq!(Weekday::Saturday + 7, Weekday::Saturday);
|
||||
/// assert_eq!(Weekday::Sunday + -1, Weekday::Saturday);
|
||||
/// // The weekday can also be on the right hand side of addition:
|
||||
/// assert_eq!(1 + Weekday::Sunday, Weekday::Monday);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn wrapping_add(self, days: impl Into<i64>) -> Weekday {
|
||||
let start = t::NoUnits::rfrom(self.to_monday_zero_offset_ranged());
|
||||
// OK because all i64 values fit in a NoUnits.
|
||||
let rhs = t::NoUnits::new(days.into()).unwrap();
|
||||
let end = start.wrapping_add(rhs) % C(7);
|
||||
Weekday::from_monday_zero_offset_ranged(end)
|
||||
}
|
||||
|
||||
/// Subtract the given number of days from this weekday, using wrapping
|
||||
/// arithmetic, and return the resulting weekday.
|
||||
///
|
||||
/// Subtracting a multiple of `7` (including `0`) is guaranteed to produce
|
||||
/// the same weekday as this one.
|
||||
///
|
||||
/// Note that this routine is also available via the `-` operator.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Sunday.wrapping_sub(1), Weekday::Saturday);
|
||||
/// assert_eq!(Weekday::Sunday.wrapping_sub(2), Weekday::Friday);
|
||||
/// assert_eq!(Weekday::Saturday.wrapping_sub(1), Weekday::Friday);
|
||||
/// assert_eq!(Weekday::Saturday.wrapping_sub(7), Weekday::Saturday);
|
||||
/// assert_eq!(Weekday::Sunday.wrapping_sub(-1), Weekday::Monday);
|
||||
/// ```
|
||||
///
|
||||
/// Wrapping arithmetic is also performed by the `-` operator:
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// assert_eq!(Weekday::Sunday - 1, Weekday::Saturday);
|
||||
/// assert_eq!(Weekday::Sunday - 2, Weekday::Friday);
|
||||
/// assert_eq!(Weekday::Saturday - 1, Weekday::Friday);
|
||||
/// assert_eq!(Weekday::Saturday - 7, Weekday::Saturday);
|
||||
/// assert_eq!(Weekday::Sunday - -1, Weekday::Monday);
|
||||
/// ```
|
||||
///
|
||||
/// Unlike addition, since subtraction is not commutative and negating a
|
||||
/// weekday has no semantic meaning, the weekday cannot be on the right
|
||||
/// hand side of the `-` operator.
|
||||
#[inline]
|
||||
pub fn wrapping_sub(self, days: impl Into<i64>) -> Weekday {
|
||||
self.wrapping_add(-days.into())
|
||||
}
|
||||
|
||||
/// Starting with this weekday, this returns an unending iterator that
|
||||
/// cycles forward through the days of the week.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// let mut it = Weekday::Tuesday.cycle_forward();
|
||||
/// assert_eq!(it.next(), Some(Weekday::Tuesday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Wednesday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Thursday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Friday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Saturday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Sunday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Monday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Tuesday));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn cycle_forward(self) -> WeekdaysForward {
|
||||
let nexts = [
|
||||
self,
|
||||
self.wrapping_add(1),
|
||||
self.wrapping_add(2),
|
||||
self.wrapping_add(3),
|
||||
self.wrapping_add(4),
|
||||
self.wrapping_add(5),
|
||||
self.wrapping_add(6),
|
||||
];
|
||||
WeekdaysForward { it: nexts.into_iter().cycle() }
|
||||
}
|
||||
|
||||
/// Starting with this weekday, this returns an unending iterator that
|
||||
/// cycles backward through the days of the week.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::civil::Weekday;
|
||||
///
|
||||
/// let mut it = Weekday::Tuesday.cycle_reverse();
|
||||
/// assert_eq!(it.next(), Some(Weekday::Tuesday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Monday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Sunday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Saturday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Friday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Thursday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Wednesday));
|
||||
/// assert_eq!(it.next(), Some(Weekday::Tuesday));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn cycle_reverse(self) -> WeekdaysReverse {
|
||||
let nexts = [
|
||||
self,
|
||||
self.wrapping_sub(1),
|
||||
self.wrapping_sub(2),
|
||||
self.wrapping_sub(3),
|
||||
self.wrapping_sub(4),
|
||||
self.wrapping_sub(5),
|
||||
self.wrapping_sub(6),
|
||||
];
|
||||
WeekdaysReverse { it: nexts.into_iter().cycle() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Weekday {
|
||||
#[inline]
|
||||
pub(crate) fn from_monday_zero_offset_ranged(
|
||||
offset: impl RInto<t::WeekdayZero>,
|
||||
) -> Weekday {
|
||||
match offset.rinto().get() {
|
||||
0 => Weekday::Monday,
|
||||
1 => Weekday::Tuesday,
|
||||
2 => Weekday::Wednesday,
|
||||
3 => Weekday::Thursday,
|
||||
4 => Weekday::Friday,
|
||||
5 => Weekday::Saturday,
|
||||
6 => Weekday::Sunday,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from_monday_one_offset_ranged(
|
||||
offset: impl RInto<t::WeekdayOne>,
|
||||
) -> Weekday {
|
||||
let offset_zero = offset.rinto() - C(1);
|
||||
Weekday::from_monday_zero_offset_ranged(offset_zero)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from_sunday_zero_offset_ranged(
|
||||
offset: impl RInto<t::WeekdayZero>,
|
||||
) -> Weekday {
|
||||
let offset_sunday = (offset.rinto() - C(1)) % C(7);
|
||||
Weekday::from_monday_zero_offset_ranged(offset_sunday)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from_sunday_one_offset_ranged(
|
||||
offset: impl RInto<t::WeekdayOne>,
|
||||
) -> Weekday {
|
||||
let offset_zero = offset.rinto() - C(1);
|
||||
Weekday::from_sunday_zero_offset_ranged(offset_zero)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_monday_zero_offset_ranged(self) -> t::WeekdayZero {
|
||||
(self.to_monday_one_offset_ranged() - C(1)).rinto()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_monday_one_offset_ranged(self) -> t::WeekdayOne {
|
||||
t::WeekdayOne::new_unchecked(self as i8)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_sunday_zero_offset_ranged(self) -> t::WeekdayZero {
|
||||
(self.to_monday_zero_offset_ranged() + C(1)) % C(7)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_sunday_one_offset_ranged(self) -> t::WeekdayOne {
|
||||
(self.to_sunday_zero_offset_ranged() + C(1)).rinto()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn since_ranged(self, other: Weekday) -> t::WeekdayZero {
|
||||
(self.to_monday_zero_offset_ranged()
|
||||
- other.to_monday_zero_offset_ranged())
|
||||
% C(7)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn until_ranged(self, other: Weekday) -> t::WeekdayZero {
|
||||
other.since_ranged(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Add<i8> for Weekday {
|
||||
type Output = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: i8) -> Weekday {
|
||||
self.wrapping_add(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Add<i16> for Weekday {
|
||||
type Output = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: i16) -> Weekday {
|
||||
self.wrapping_add(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Add<i32> for Weekday {
|
||||
type Output = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: i32) -> Weekday {
|
||||
self.wrapping_add(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Add<i64> for Weekday {
|
||||
type Output = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: i64) -> Weekday {
|
||||
self.wrapping_add(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
// Since addition is commutative, we don't might if users write `n + weekday`
|
||||
// or `weekday + n`.
|
||||
|
||||
impl core::ops::Add<Weekday> for i8 {
|
||||
type Output = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: Weekday) -> Weekday {
|
||||
rhs.wrapping_add(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Add<Weekday> for i16 {
|
||||
type Output = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: Weekday) -> Weekday {
|
||||
rhs.wrapping_add(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Add<Weekday> for i32 {
|
||||
type Output = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: Weekday) -> Weekday {
|
||||
rhs.wrapping_add(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Add<Weekday> for i64 {
|
||||
type Output = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: Weekday) -> Weekday {
|
||||
rhs.wrapping_add(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::AddAssign<i8> for Weekday {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: i8) {
|
||||
*self = *self + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::AddAssign<i16> for Weekday {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: i16) {
|
||||
*self = *self + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::AddAssign<i32> for Weekday {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: i32) {
|
||||
*self = *self + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::AddAssign<i64> for Weekday {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: i64) {
|
||||
*self = *self + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
// Subtraction isn't commutative, so we only define it when the right hand
|
||||
// side is an integer. Otherwise we'd need a concept of what it means to
|
||||
// "negate" a weekday, which doesn't really make sense?
|
||||
|
||||
impl core::ops::Sub<i8> for Weekday {
|
||||
type Output = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: i8) -> Weekday {
|
||||
self.wrapping_sub(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Sub<i16> for Weekday {
|
||||
type Output = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: i16) -> Weekday {
|
||||
self.wrapping_sub(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Sub<i32> for Weekday {
|
||||
type Output = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: i32) -> Weekday {
|
||||
self.wrapping_sub(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Sub<i64> for Weekday {
|
||||
type Output = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: i64) -> Weekday {
|
||||
self.wrapping_sub(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::SubAssign<i8> for Weekday {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: i8) {
|
||||
*self = *self - rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::SubAssign<i16> for Weekday {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: i16) {
|
||||
*self = *self - rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::SubAssign<i32> for Weekday {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: i32) {
|
||||
*self = *self - rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::SubAssign<i64> for Weekday {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: i64) {
|
||||
*self = *self - rhs;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl quickcheck::Arbitrary for Weekday {
|
||||
fn arbitrary(g: &mut quickcheck::Gen) -> Weekday {
|
||||
let offset = t::WeekdayZero::arbitrary(g);
|
||||
Weekday::from_monday_zero_offset_ranged(offset)
|
||||
}
|
||||
|
||||
fn shrink(&self) -> alloc::boxed::Box<dyn Iterator<Item = Weekday>> {
|
||||
alloc::boxed::Box::new(
|
||||
self.to_monday_zero_offset_ranged()
|
||||
.shrink()
|
||||
.map(Weekday::from_monday_zero_offset_ranged),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// An unending iterator of the days of the week.
|
||||
///
|
||||
/// This iterator is created by calling [`Weekday::cycle_forward`].
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WeekdaysForward {
|
||||
it: core::iter::Cycle<core::array::IntoIter<Weekday, 7>>,
|
||||
}
|
||||
|
||||
impl Iterator for WeekdaysForward {
|
||||
type Item = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Weekday> {
|
||||
self.it.next()
|
||||
}
|
||||
}
|
||||
|
||||
impl core::iter::FusedIterator for WeekdaysForward {}
|
||||
|
||||
/// An unending iterator of the days of the week in reverse.
|
||||
///
|
||||
/// This iterator is created by calling [`Weekday::cycle_reverse`].
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WeekdaysReverse {
|
||||
it: core::iter::Cycle<core::array::IntoIter<Weekday, 7>>,
|
||||
}
|
||||
|
||||
impl Iterator for WeekdaysReverse {
|
||||
type Item = Weekday;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Weekday> {
|
||||
self.it.next()
|
||||
}
|
||||
}
|
||||
|
||||
impl core::iter::FusedIterator for WeekdaysReverse {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
quickcheck::quickcheck! {
|
||||
fn prop_since_add_equals_self(wd1: Weekday, wd2: Weekday) -> bool {
|
||||
let days = wd1.since(wd2);
|
||||
wd2.wrapping_add(days) == wd1
|
||||
}
|
||||
|
||||
fn prop_until_add_equals_other(wd1: Weekday, wd2: Weekday) -> bool {
|
||||
let days = wd1.until(wd2);
|
||||
wd1.wrapping_add(days) == wd2
|
||||
}
|
||||
}
|
||||
}
|
||||
255
src/data/leap-seconds.list
Normal file
255
src/data/leap-seconds.list
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
#
|
||||
# In the following text, the symbol '#' introduces
|
||||
# a comment, which continues from that symbol until
|
||||
# the end of the line. A plain comment line has a
|
||||
# whitespace character following the comment indicator.
|
||||
# There are also special comment lines defined below.
|
||||
# A special comment will always have a non-whitespace
|
||||
# character in column 2.
|
||||
#
|
||||
# A blank line should be ignored.
|
||||
#
|
||||
# The following table shows the corrections that must
|
||||
# be applied to compute International Atomic Time (TAI)
|
||||
# from the Coordinated Universal Time (UTC) values that
|
||||
# are transmitted by almost all time services.
|
||||
#
|
||||
# The first column shows an epoch as a number of seconds
|
||||
# since 1 January 1900, 00:00:00 (1900.0 is also used to
|
||||
# indicate the same epoch.) Both of these time stamp formats
|
||||
# ignore the complexities of the time scales that were
|
||||
# used before the current definition of UTC at the start
|
||||
# of 1972. (See note 3 below.)
|
||||
# The second column shows the number of seconds that
|
||||
# must be added to UTC to compute TAI for any timestamp
|
||||
# at or after that epoch. The value on each line is
|
||||
# valid from the indicated initial instant until the
|
||||
# epoch given on the next one or indefinitely into the
|
||||
# future if there is no next line.
|
||||
# (The comment on each line shows the representation of
|
||||
# the corresponding initial epoch in the usual
|
||||
# day-month-year format. The epoch always begins at
|
||||
# 00:00:00 UTC on the indicated day. See Note 5 below.)
|
||||
#
|
||||
# Important notes:
|
||||
#
|
||||
# 1. Coordinated Universal Time (UTC) is often referred to
|
||||
# as Greenwich Mean Time (GMT). The GMT time scale is no
|
||||
# longer used, and the use of GMT to designate UTC is
|
||||
# discouraged.
|
||||
#
|
||||
# 2. The UTC time scale is realized by many national
|
||||
# laboratories and timing centers. Each laboratory
|
||||
# identifies its realization with its name: Thus
|
||||
# UTC(NIST), UTC(USNO), etc. The differences among
|
||||
# these different realizations are typically on the
|
||||
# order of a few nanoseconds (i.e., 0.000 000 00x s)
|
||||
# and can be ignored for many purposes. These differences
|
||||
# are tabulated in Circular T, which is published monthly
|
||||
# by the International Bureau of Weights and Measures
|
||||
# (BIPM). See www.bipm.org for more information.
|
||||
#
|
||||
# 3. The current definition of the relationship between UTC
|
||||
# and TAI dates from 1 January 1972. A number of different
|
||||
# time scales were in use before that epoch, and it can be
|
||||
# quite difficult to compute precise timestamps and time
|
||||
# intervals in those "prehistoric" days. For more information,
|
||||
# consult:
|
||||
#
|
||||
# The Explanatory Supplement to the Astronomical
|
||||
# Ephemeris.
|
||||
# or
|
||||
# Terry Quinn, "The BIPM and the Accurate Measurement
|
||||
# of Time," Proc. of the IEEE, Vol. 79, pp. 894-905,
|
||||
# July, 1991. <http://dx.doi.org/10.1109/5.84965>
|
||||
# reprinted in:
|
||||
# Christine Hackman and Donald B Sullivan (eds.)
|
||||
# Time and Frequency Measurement
|
||||
# American Association of Physics Teachers (1996)
|
||||
# <http://tf.nist.gov/general/pdf/1168.pdf>, pp. 75-86
|
||||
#
|
||||
# 4. The decision to insert a leap second into UTC is currently
|
||||
# the responsibility of the International Earth Rotation and
|
||||
# Reference Systems Service. (The name was changed from the
|
||||
# International Earth Rotation Service, but the acronym IERS
|
||||
# is still used.)
|
||||
#
|
||||
# Leap seconds are announced by the IERS in its Bulletin C.
|
||||
#
|
||||
# See www.iers.org for more details.
|
||||
#
|
||||
# Every national laboratory and timing center uses the
|
||||
# data from the BIPM and the IERS to construct UTC(lab),
|
||||
# their local realization of UTC.
|
||||
#
|
||||
# Although the definition also includes the possibility
|
||||
# of dropping seconds ("negative" leap seconds), this has
|
||||
# never been done and is unlikely to be necessary in the
|
||||
# foreseeable future.
|
||||
#
|
||||
# 5. If your system keeps time as the number of seconds since
|
||||
# some epoch (e.g., NTP timestamps), then the algorithm for
|
||||
# assigning a UTC time stamp to an event that happens during a positive
|
||||
# leap second is not well defined. The official name of that leap
|
||||
# second is 23:59:60, but there is no way of representing that time
|
||||
# in these systems.
|
||||
# Many systems of this type effectively stop the system clock for
|
||||
# one second during the leap second and use a time that is equivalent
|
||||
# to 23:59:59 UTC twice. For these systems, the corresponding TAI
|
||||
# timestamp would be obtained by advancing to the next entry in the
|
||||
# following table when the time equivalent to 23:59:59 UTC
|
||||
# is used for the second time. Thus the leap second which
|
||||
# occurred on 30 June 1972 at 23:59:59 UTC would have TAI
|
||||
# timestamps computed as follows:
|
||||
#
|
||||
# ...
|
||||
# 30 June 1972 23:59:59 (2287785599, first time): TAI= UTC + 10 seconds
|
||||
# 30 June 1972 23:59:60 (2287785599,second time): TAI= UTC + 11 seconds
|
||||
# 1 July 1972 00:00:00 (2287785600) TAI= UTC + 11 seconds
|
||||
# ...
|
||||
#
|
||||
# If your system realizes the leap second by repeating 00:00:00 UTC twice
|
||||
# (this is possible but not usual), then the advance to the next entry
|
||||
# in the table must occur the second time that a time equivalent to
|
||||
# 00:00:00 UTC is used. Thus, using the same example as above:
|
||||
#
|
||||
# ...
|
||||
# 30 June 1972 23:59:59 (2287785599): TAI= UTC + 10 seconds
|
||||
# 30 June 1972 23:59:60 (2287785600, first time): TAI= UTC + 10 seconds
|
||||
# 1 July 1972 00:00:00 (2287785600,second time): TAI= UTC + 11 seconds
|
||||
# ...
|
||||
#
|
||||
# in both cases the use of timestamps based on TAI produces a smooth
|
||||
# time scale with no discontinuity in the time interval. However,
|
||||
# although the long-term behavior of the time scale is correct in both
|
||||
# methods, the second method is technically not correct because it adds
|
||||
# the extra second to the wrong day.
|
||||
#
|
||||
# This complexity would not be needed for negative leap seconds (if they
|
||||
# are ever used). The UTC time would skip 23:59:59 and advance from
|
||||
# 23:59:58 to 00:00:00 in that case. The TAI offset would decrease by
|
||||
# 1 second at the same instant. This is a much easier situation to deal
|
||||
# with, since the difficulty of unambiguously representing the epoch
|
||||
# during the leap second does not arise.
|
||||
#
|
||||
# Some systems implement leap seconds by amortizing the leap second
|
||||
# over the last few minutes of the day. The frequency of the local
|
||||
# clock is decreased (or increased) to realize the positive (or
|
||||
# negative) leap second. This method removes the time step described
|
||||
# above. Although the long-term behavior of the time scale is correct
|
||||
# in this case, this method introduces an error during the adjustment
|
||||
# period both in time and in frequency with respect to the official
|
||||
# definition of UTC.
|
||||
#
|
||||
# Questions or comments to:
|
||||
# Judah Levine
|
||||
# Time and Frequency Division
|
||||
# NIST
|
||||
# Boulder, Colorado
|
||||
# Judah.Levine@nist.gov
|
||||
#
|
||||
# Last Update of leap second values: 8 July 2016
|
||||
#
|
||||
# The following line shows this last update date in NTP timestamp
|
||||
# format. This is the date on which the most recent change to
|
||||
# the leap second data was added to the file. This line can
|
||||
# be identified by the unique pair of characters in the first two
|
||||
# columns as shown below.
|
||||
#
|
||||
#$ 3676924800
|
||||
#
|
||||
# The NTP timestamps are in units of seconds since the NTP epoch,
|
||||
# which is 1 January 1900, 00:00:00. The Modified Julian Day number
|
||||
# corresponding to the NTP time stamp, X, can be computed as
|
||||
#
|
||||
# X/86400 + 15020
|
||||
#
|
||||
# where the first term converts seconds to days and the second
|
||||
# term adds the MJD corresponding to the time origin defined above.
|
||||
# The integer portion of the result is the integer MJD for that
|
||||
# day, and any remainder is the time of day, expressed as the
|
||||
# fraction of the day since 0 hours UTC. The conversion from day
|
||||
# fraction to seconds or to hours, minutes, and seconds may involve
|
||||
# rounding or truncation, depending on the method used in the
|
||||
# computation.
|
||||
#
|
||||
# The data in this file will be updated periodically as new leap
|
||||
# seconds are announced. In addition to being entered on the line
|
||||
# above, the update time (in NTP format) will be added to the basic
|
||||
# file name leap-seconds to form the name leap-seconds.<NTP TIME>.
|
||||
# In addition, the generic name leap-seconds.list will always point to
|
||||
# the most recent version of the file.
|
||||
#
|
||||
# This update procedure will be performed only when a new leap second
|
||||
# is announced.
|
||||
#
|
||||
# The following entry specifies the expiration date of the data
|
||||
# in this file in units of seconds since the origin at the instant
|
||||
# 1 January 1900, 00:00:00. This expiration date will be changed
|
||||
# at least twice per year whether or not a new leap second is
|
||||
# announced. These semi-annual changes will be made no later
|
||||
# than 1 June and 1 December of each year to indicate what
|
||||
# action (if any) is to be taken on 30 June and 31 December,
|
||||
# respectively. (These are the customary effective dates for new
|
||||
# leap seconds.) This expiration date will be identified by a
|
||||
# unique pair of characters in columns 1 and 2 as shown below.
|
||||
# In the unlikely event that a leap second is announced with an
|
||||
# effective date other than 30 June or 31 December, then this
|
||||
# file will be edited to include that leap second as soon as it is
|
||||
# announced or at least one month before the effective date
|
||||
# (whichever is later).
|
||||
# If an announcement by the IERS specifies that no leap second is
|
||||
# scheduled, then only the expiration date of the file will
|
||||
# be advanced to show that the information in the file is still
|
||||
# current -- the update time stamp, the data and the name of the file
|
||||
# will not change.
|
||||
#
|
||||
# Updated through IERS Bulletin C66
|
||||
# File expires on: 28 June 2024
|
||||
#
|
||||
#@ 3928521600
|
||||
#
|
||||
2272060800 10 # 1 Jan 1972
|
||||
2287785600 11 # 1 Jul 1972
|
||||
2303683200 12 # 1 Jan 1973
|
||||
2335219200 13 # 1 Jan 1974
|
||||
2366755200 14 # 1 Jan 1975
|
||||
2398291200 15 # 1 Jan 1976
|
||||
2429913600 16 # 1 Jan 1977
|
||||
2461449600 17 # 1 Jan 1978
|
||||
2492985600 18 # 1 Jan 1979
|
||||
2524521600 19 # 1 Jan 1980
|
||||
2571782400 20 # 1 Jul 1981
|
||||
2603318400 21 # 1 Jul 1982
|
||||
2634854400 22 # 1 Jul 1983
|
||||
2698012800 23 # 1 Jul 1985
|
||||
2776982400 24 # 1 Jan 1988
|
||||
2840140800 25 # 1 Jan 1990
|
||||
2871676800 26 # 1 Jan 1991
|
||||
2918937600 27 # 1 Jul 1992
|
||||
2950473600 28 # 1 Jul 1993
|
||||
2982009600 29 # 1 Jul 1994
|
||||
3029443200 30 # 1 Jan 1996
|
||||
3076704000 31 # 1 Jul 1997
|
||||
3124137600 32 # 1 Jan 1999
|
||||
3345062400 33 # 1 Jan 2006
|
||||
3439756800 34 # 1 Jan 2009
|
||||
3550089600 35 # 1 Jul 2012
|
||||
3644697600 36 # 1 Jul 2015
|
||||
3692217600 37 # 1 Jan 2017
|
||||
#
|
||||
# the following special comment contains the
|
||||
# hash value of the data in this file computed
|
||||
# use the secure hash algorithm as specified
|
||||
# by FIPS 180-1. See the files in ~/pub/sha for
|
||||
# the details of how this hash value is
|
||||
# computed. Note that the hash computation
|
||||
# ignores comments and whitespace characters
|
||||
# in data lines. It includes the NTP values
|
||||
# of both the last modification time and the
|
||||
# expiration time of the file, but not the
|
||||
# white space on those lines.
|
||||
# the hash line is also ignored in the
|
||||
# computation.
|
||||
#
|
||||
#h 16edd0f0 3666784f 37db6bdd e74ced87 59af48f1
|
||||
82
src/data/leapseconds
Normal file
82
src/data/leapseconds
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# Allowance for leap seconds added to each time zone file.
|
||||
|
||||
# This file is in the public domain.
|
||||
|
||||
# This file is generated automatically from the data in the public-domain
|
||||
# NIST format leap-seconds.list file, which can be copied from
|
||||
# <ftp://ftp.nist.gov/pub/time/leap-seconds.list>
|
||||
# or <ftp://ftp.boulder.nist.gov/pub/time/leap-seconds.list>.
|
||||
# The NIST file is used instead of its IERS upstream counterpart
|
||||
# <https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list>
|
||||
# because under US law the NIST file is public domain
|
||||
# whereas the IERS file's copyright and license status is unclear.
|
||||
# For more about leap-seconds.list, please see
|
||||
# The NTP Timescale and Leap Seconds
|
||||
# <https://www.eecis.udel.edu/~mills/leap.html>.
|
||||
|
||||
# The rules for leap seconds are specified in Annex 1 (Time scales) of:
|
||||
# Standard-frequency and time-signal emissions.
|
||||
# International Telecommunication Union - Radiocommunication Sector
|
||||
# (ITU-R) Recommendation TF.460-6 (02/2002)
|
||||
# <https://www.itu.int/rec/R-REC-TF.460-6-200202-I/>.
|
||||
# The International Earth Rotation and Reference Systems Service (IERS)
|
||||
# periodically uses leap seconds to keep UTC to within 0.9 s of UT1
|
||||
# (a proxy for Earth's angle in space as measured by astronomers)
|
||||
# and publishes leap second data in a copyrighted file
|
||||
# <https://hpiers.obspm.fr/iers/bul/bulc/Leap_Second.dat>.
|
||||
# See: Levine J. Coordinated Universal Time and the leap second.
|
||||
# URSI Radio Sci Bull. 2016;89(4):30-6. doi:10.23919/URSIRSB.2016.7909995
|
||||
# <https://ieeexplore.ieee.org/document/7909995>.
|
||||
|
||||
# There were no leap seconds before 1972, as no official mechanism
|
||||
# accounted for the discrepancy between atomic time (TAI) and the earth's
|
||||
# rotation. The first ("1 Jan 1972") data line in leap-seconds.list
|
||||
# does not denote a leap second; it denotes the start of the current definition
|
||||
# of UTC.
|
||||
|
||||
# All leap-seconds are Stationary (S) at the given UTC time.
|
||||
# The correction (+ or -) is made at the given time, so in the unlikely
|
||||
# event of a negative leap second, a line would look like this:
|
||||
# Leap YEAR MON DAY 23:59:59 - S
|
||||
# Typical lines look like this:
|
||||
# Leap YEAR MON DAY 23:59:60 + S
|
||||
Leap 1972 Jun 30 23:59:60 + S
|
||||
Leap 1972 Dec 31 23:59:60 + S
|
||||
Leap 1973 Dec 31 23:59:60 + S
|
||||
Leap 1974 Dec 31 23:59:60 + S
|
||||
Leap 1975 Dec 31 23:59:60 + S
|
||||
Leap 1976 Dec 31 23:59:60 + S
|
||||
Leap 1977 Dec 31 23:59:60 + S
|
||||
Leap 1978 Dec 31 23:59:60 + S
|
||||
Leap 1979 Dec 31 23:59:60 + S
|
||||
Leap 1981 Jun 30 23:59:60 + S
|
||||
Leap 1982 Jun 30 23:59:60 + S
|
||||
Leap 1983 Jun 30 23:59:60 + S
|
||||
Leap 1985 Jun 30 23:59:60 + S
|
||||
Leap 1987 Dec 31 23:59:60 + S
|
||||
Leap 1989 Dec 31 23:59:60 + S
|
||||
Leap 1990 Dec 31 23:59:60 + S
|
||||
Leap 1992 Jun 30 23:59:60 + S
|
||||
Leap 1993 Jun 30 23:59:60 + S
|
||||
Leap 1994 Jun 30 23:59:60 + S
|
||||
Leap 1995 Dec 31 23:59:60 + S
|
||||
Leap 1997 Jun 30 23:59:60 + S
|
||||
Leap 1998 Dec 31 23:59:60 + S
|
||||
Leap 2005 Dec 31 23:59:60 + S
|
||||
Leap 2008 Dec 31 23:59:60 + S
|
||||
Leap 2012 Jun 30 23:59:60 + S
|
||||
Leap 2015 Jun 30 23:59:60 + S
|
||||
Leap 2016 Dec 31 23:59:60 + S
|
||||
|
||||
# UTC timestamp when this leap second list expires.
|
||||
# Any additional leap seconds will come after this.
|
||||
# This Expires line is commented out for now,
|
||||
# so that pre-2020a zic implementations do not reject this file.
|
||||
#Expires 2024 Jun 28 00:00:00
|
||||
|
||||
# POSIX timestamps for the data in this file:
|
||||
#updated 1467936000 (2016-07-08 00:00:00 UTC)
|
||||
#expires 1719532800 (2024-06-28 00:00:00 UTC)
|
||||
|
||||
# Updated through IERS Bulletin C66
|
||||
# File expires on: 28 June 2024
|
||||
608
src/error.rs
Normal file
608
src/error.rs
Normal file
|
|
@ -0,0 +1,608 @@
|
|||
use alloc::{boxed::Box, string::String};
|
||||
|
||||
use crate::{
|
||||
civil::DateTime,
|
||||
tz::{Offset, TimeZone},
|
||||
};
|
||||
|
||||
/// Creates a new ad hoc error with no causal chain.
|
||||
///
|
||||
/// This accepts the same arguments as the `format!` macro. The error it
|
||||
/// creates is just a wrapper around the string created by `format!`.
|
||||
macro_rules! err {
|
||||
($($tt:tt)*) => {{
|
||||
crate::error::Error::adhoc(alloc::format!($($tt)*))
|
||||
}}
|
||||
}
|
||||
|
||||
pub(crate) use err;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
inner: Box<ErrorInner>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ErrorInner {
|
||||
kind: ErrorKind,
|
||||
cause: Option<Error>,
|
||||
}
|
||||
|
||||
/// The underlying kind of a [`Error`].
|
||||
#[derive(Debug)]
|
||||
enum ErrorKind {
|
||||
/// An ad hoc error that is constructed from anything that implements
|
||||
/// the `core::fmt::Display` trait.
|
||||
///
|
||||
/// In theory we try to avoid these, but they tend to be awfully
|
||||
/// convenient. In practice, we use them a lot, and only use a structured
|
||||
/// representation when a lot of different error cases fit neatly into a
|
||||
/// structure (like range errors).
|
||||
Adhoc(AdhocError),
|
||||
/// An error that occurs when a number is not within its allowed range.
|
||||
///
|
||||
/// This can occur directly as a result of a number provided by the caller
|
||||
/// of a public API, or as a result of an operation on a number that
|
||||
/// results in it being out of range.
|
||||
Range(RangeError),
|
||||
/// An error that occurs when a lookup of a time zone, by name, fails
|
||||
/// because that time zone does not exist.
|
||||
TimeZoneLookup(TimeZoneLookupError),
|
||||
/// An error that occurs when convertion from a civil datetime to a
|
||||
/// precise instant results in ambiguity (for example, because the civil
|
||||
/// datetime occurs in or around a DST transition).
|
||||
AmbiguousInstant(AmbiguousInstantError),
|
||||
/// An error associated with a file path.
|
||||
///
|
||||
/// This is generally expected to always have a cause attached to it
|
||||
/// explaining what went wrong. The error variant is just a path to make
|
||||
/// it composable with other error types.
|
||||
///
|
||||
/// The cause is typically `Adhoc` or `IO`.
|
||||
///
|
||||
/// When `std` is not enabled, this variant can never be constructed.
|
||||
FilePath(FilePathError),
|
||||
/// An error that occurs when interacting with the file system.
|
||||
///
|
||||
/// This is effectively a wrapper around `std::io::Error` coupled with a
|
||||
/// `std::path::PathBuf`.
|
||||
///
|
||||
/// When `std` is not enabled, this variant can never be constructed.
|
||||
IO(IOError),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// Returns a reference to the underlying error kind.
|
||||
fn kind(&self) -> &ErrorKind {
|
||||
&self.inner.kind
|
||||
}
|
||||
|
||||
/// Creates a new "ad hoc" error value.
|
||||
///
|
||||
/// An ad hoc error value is just an opaque string. In theory we should
|
||||
/// avoid creating such error values, but in practice, they are extremely
|
||||
/// convenient. And the alternative is quite brutal given the varied ways
|
||||
/// in which things in a datetime library can fail. (Especially parsing
|
||||
/// errors.)
|
||||
pub(crate) fn adhoc(
|
||||
err: impl core::fmt::Display + Send + Sync + 'static,
|
||||
) -> Error {
|
||||
Error::from(ErrorKind::Adhoc(AdhocError(Box::new(err))))
|
||||
}
|
||||
|
||||
pub(crate) fn unsigned(
|
||||
what: &'static str,
|
||||
given: impl Into<u128>,
|
||||
min: impl Into<i128>,
|
||||
max: impl Into<i128>,
|
||||
) -> Error {
|
||||
Error::from(ErrorKind::Range(RangeError::unsigned(
|
||||
what, given, min, max,
|
||||
)))
|
||||
}
|
||||
|
||||
pub(crate) fn signed(
|
||||
what: &'static str,
|
||||
given: impl Into<i128>,
|
||||
min: impl Into<i128>,
|
||||
max: impl Into<i128>,
|
||||
) -> Error {
|
||||
Error::from(ErrorKind::Range(RangeError::signed(
|
||||
what, given, min, max,
|
||||
)))
|
||||
}
|
||||
|
||||
pub(crate) fn specific(
|
||||
what: &'static str,
|
||||
given: impl Into<i128>,
|
||||
) -> Error {
|
||||
Error::from(ErrorKind::Range(RangeError::specific(what, given)))
|
||||
}
|
||||
|
||||
pub(crate) fn time_zone_lookup(
|
||||
source: impl Into<String>,
|
||||
name: impl Into<String>,
|
||||
) -> Error {
|
||||
let inner = TimeZoneLookupErrorInner {
|
||||
source: source.into(),
|
||||
name: name.into(),
|
||||
};
|
||||
Error::from(ErrorKind::TimeZoneLookup(TimeZoneLookupError(Box::new(
|
||||
inner,
|
||||
))))
|
||||
}
|
||||
|
||||
pub(crate) fn ambiguous_gap(
|
||||
tz: TimeZone,
|
||||
dt: DateTime,
|
||||
before: Offset,
|
||||
after: Offset,
|
||||
) -> Error {
|
||||
let kind = AmbiguousInstantErrorKind::Gap { before, after };
|
||||
let err =
|
||||
AmbiguousInstantError(Box::new(AmbiguousInstantErrorInner {
|
||||
tz,
|
||||
dt,
|
||||
kind,
|
||||
}));
|
||||
Error::from(ErrorKind::AmbiguousInstant(err))
|
||||
}
|
||||
|
||||
pub(crate) fn ambiguous_fold(
|
||||
tz: TimeZone,
|
||||
dt: DateTime,
|
||||
before: Offset,
|
||||
after: Offset,
|
||||
) -> Error {
|
||||
let kind = AmbiguousInstantErrorKind::Fold { before, after };
|
||||
let err =
|
||||
AmbiguousInstantError(Box::new(AmbiguousInstantErrorInner {
|
||||
tz,
|
||||
dt,
|
||||
kind,
|
||||
}));
|
||||
Error::from(ErrorKind::AmbiguousInstant(err))
|
||||
}
|
||||
|
||||
/// A convenience constructor for building an I/O error associated with
|
||||
/// a file path.
|
||||
///
|
||||
/// Generallly speaking, an I/O error should always be associated with some
|
||||
/// sort of context. In Jiff, it's always a file path (at time of writing).
|
||||
///
|
||||
/// This is only available when the `std` feature is enabled.
|
||||
#[cfg(feature = "std")]
|
||||
pub(crate) fn fs(
|
||||
path: impl Into<std::path::PathBuf>,
|
||||
err: std::io::Error,
|
||||
) -> Error {
|
||||
Error::io(err).path(path)
|
||||
}
|
||||
|
||||
/// A convenience constructor for building an I/O error.
|
||||
///
|
||||
/// This returns an error that is just a simple wrapper around the
|
||||
/// `std::io::Error` type. In general, callers should alwasys attach some
|
||||
/// kind of context to this error (like a file path).
|
||||
///
|
||||
/// This is only available when the `std` feature is enabled.
|
||||
#[cfg(feature = "std")]
|
||||
pub(crate) fn io(err: std::io::Error) -> Error {
|
||||
Error::from(ErrorKind::IO(IOError { err }))
|
||||
}
|
||||
|
||||
/// Contextualizes this error by associating the given file path with it.
|
||||
///
|
||||
/// This is a convenience routine for calling `Error::context` with a
|
||||
/// `FilePathError`.
|
||||
///
|
||||
/// This is only available when the `std` feature is enabled.
|
||||
#[cfg(feature = "std")]
|
||||
pub(crate) fn path(self, path: impl Into<std::path::PathBuf>) -> Error {
|
||||
let err = Error::from(ErrorKind::FilePath(FilePathError {
|
||||
path: path.into(),
|
||||
}));
|
||||
self.context(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
impl core::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
let mut err = self;
|
||||
loop {
|
||||
write!(f, "{}", err.inner.kind)?;
|
||||
err = match err.inner.cause.as_ref() {
|
||||
None => break,
|
||||
Some(err) => err,
|
||||
};
|
||||
write!(f, ": ")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for ErrorKind {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
match *self {
|
||||
ErrorKind::Adhoc(ref msg) => msg.fmt(f),
|
||||
ErrorKind::Range(ref err) => err.fmt(f),
|
||||
ErrorKind::TimeZoneLookup(ref err) => err.fmt(f),
|
||||
ErrorKind::AmbiguousInstant(ref err) => err.fmt(f),
|
||||
ErrorKind::FilePath(ref err) => err.fmt(f),
|
||||
ErrorKind::IO(ref err) => err.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorKind> for Error {
|
||||
fn from(kind: ErrorKind) -> Error {
|
||||
Error { inner: Box::new(ErrorInner { kind, cause: None }) }
|
||||
}
|
||||
}
|
||||
|
||||
struct AdhocError(Box<dyn core::fmt::Display + Send + Sync + 'static>);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for AdhocError {}
|
||||
|
||||
impl core::fmt::Display for AdhocError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for AdhocError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that occurs when an input value is out of bounds.
|
||||
///
|
||||
/// The error message produced by this type will include a name describing
|
||||
/// which input was out of bounds, the value given and its minimum and maximum
|
||||
/// allowed values.
|
||||
#[derive(Debug)]
|
||||
struct RangeError(Box<RangeErrorKind>);
|
||||
|
||||
#[derive(Debug)]
|
||||
enum RangeErrorKind {
|
||||
Positive { what: &'static str, given: u128, min: i128, max: i128 },
|
||||
Negative { what: &'static str, given: i128, min: i128, max: i128 },
|
||||
Specific { what: &'static str, given: i128 },
|
||||
}
|
||||
|
||||
impl RangeError {
|
||||
fn unsigned(
|
||||
what: &'static str,
|
||||
given: impl Into<u128>,
|
||||
min: impl Into<i128>,
|
||||
max: impl Into<i128>,
|
||||
) -> RangeError {
|
||||
RangeError(Box::new(RangeErrorKind::Positive {
|
||||
what,
|
||||
given: given.into(),
|
||||
min: min.into(),
|
||||
max: max.into(),
|
||||
}))
|
||||
}
|
||||
|
||||
fn signed(
|
||||
what: &'static str,
|
||||
given: impl Into<i128>,
|
||||
min: impl Into<i128>,
|
||||
max: impl Into<i128>,
|
||||
) -> RangeError {
|
||||
RangeError(Box::new(RangeErrorKind::Negative {
|
||||
what,
|
||||
given: given.into(),
|
||||
min: min.into(),
|
||||
max: max.into(),
|
||||
}))
|
||||
}
|
||||
|
||||
fn specific(what: &'static str, given: impl Into<i128>) -> RangeError {
|
||||
RangeError(Box::new(RangeErrorKind::Specific {
|
||||
what,
|
||||
given: given.into(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for RangeError {}
|
||||
|
||||
impl core::fmt::Display for RangeError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
match *self.0 {
|
||||
RangeErrorKind::Positive { what, given, min, max } => {
|
||||
write!(
|
||||
f,
|
||||
"parameter '{what}' with value {given} \
|
||||
is not in the required range of {min}..={max}",
|
||||
)
|
||||
}
|
||||
RangeErrorKind::Negative { what, given, min, max } => {
|
||||
write!(
|
||||
f,
|
||||
"parameter '{what}' with value {given} \
|
||||
is not in the required range of {min}..={max}",
|
||||
)
|
||||
}
|
||||
RangeErrorKind::Specific { what, given } => {
|
||||
write!(f, "parameter '{what}' with value {given} is illegal",)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TimeZoneLookupError(Box<TimeZoneLookupErrorInner>);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TimeZoneLookupErrorInner {
|
||||
source: String,
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for TimeZoneLookupError {}
|
||||
|
||||
impl core::fmt::Display for TimeZoneLookupError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"failed to find timezone {:?} in {} database",
|
||||
self.0.name, self.0.source
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AmbiguousInstantError(Box<AmbiguousInstantErrorInner>);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AmbiguousInstantErrorInner {
|
||||
tz: crate::tz::TimeZone,
|
||||
dt: crate::civil::DateTime,
|
||||
kind: AmbiguousInstantErrorKind,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum AmbiguousInstantErrorKind {
|
||||
Gap { before: Offset, after: Offset },
|
||||
Fold { before: Offset, after: Offset },
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for AmbiguousInstantError {}
|
||||
|
||||
impl core::fmt::Display for AmbiguousInstantError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
match self.0.kind {
|
||||
AmbiguousInstantErrorKind::Gap { before, after } => {
|
||||
write!(
|
||||
f,
|
||||
"the datetime {dt} is ambiguous in time zone {tz}, \
|
||||
as it falls in a gap between offsets {before} and \
|
||||
{after}",
|
||||
dt = self.0.dt,
|
||||
tz = self.0.tz.name(),
|
||||
)
|
||||
}
|
||||
AmbiguousInstantErrorKind::Fold { before, after } => {
|
||||
write!(
|
||||
f,
|
||||
"the datetime {dt} is ambiguous in time zone {tz}, \
|
||||
as it falls in a fold between offsets {before} and \
|
||||
{after}",
|
||||
dt = self.0.dt,
|
||||
tz = self.0.tz.name(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A `std::io::Error`.
|
||||
///
|
||||
/// This type is itself always available, even when the `std` feature is not
|
||||
/// enabled. When `std` is not enabled, a value of this type can never be
|
||||
/// constructed.
|
||||
///
|
||||
/// Otherwise, this type is a simple wrapper around `std::io::Error`. Its
|
||||
/// purpose is to encapsulate the conditional compilation based on the `std`
|
||||
/// feature.
|
||||
struct IOError {
|
||||
#[cfg(feature = "std")]
|
||||
err: std::io::Error,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for IOError {}
|
||||
|
||||
impl core::fmt::Display for IOError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
write!(f, "{}", self.err)
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
write!(f, "<BUG: SHOULD NOT EXIST>")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for IOError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
f.debug_struct("IOError").field("err", &self.err).finish()
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
write!(f, "<BUG: SHOULD NOT EXIST>")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<std::io::Error> for IOError {
|
||||
fn from(err: std::io::Error) -> IOError {
|
||||
IOError { err }
|
||||
}
|
||||
}
|
||||
|
||||
struct FilePathError {
|
||||
#[cfg(feature = "std")]
|
||||
path: std::path::PathBuf,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for FilePathError {}
|
||||
|
||||
impl core::fmt::Display for FilePathError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
write!(f, "{}", self.path.display())
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
write!(f, "<BUG: SHOULD NOT EXIST>")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for FilePathError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
f.debug_struct("FilePathError").field("path", &self.path).finish()
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
write!(f, "<BUG: SHOULD NOT EXIST>")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple trait to encapsulate automatic conversion to `Error`.
|
||||
///
|
||||
/// This trait basically exists to make `Error::context` work without needing
|
||||
/// to rely on public `From` impls. For example, without this trait, we might
|
||||
/// otherwise write `impl From<String> for Error`. But this would make it part
|
||||
/// of the public API. Which... maybe we should do, but at time of writing,
|
||||
/// I'm starting very conservative so that we can evolve errors in semver
|
||||
/// compatible ways.
|
||||
pub(crate) trait IntoError {
|
||||
fn into_error(self) -> Error;
|
||||
}
|
||||
|
||||
impl IntoError for Error {
|
||||
fn into_error(self) -> Error {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoError for &'static str {
|
||||
fn into_error(self) -> Error {
|
||||
Error::adhoc(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoError for String {
|
||||
fn into_error(self) -> Error {
|
||||
Error::adhoc(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for contextualizing error values.
|
||||
///
|
||||
/// This makes it easy to contextualize either `Error` or `Result<T, Error>`.
|
||||
/// Specifically, in the latter case, it absolves one of the need to call
|
||||
/// `map_err` everywhere one wants to add context to an error.
|
||||
///
|
||||
/// This trick was borrowed from `anyhow`.
|
||||
pub(crate) trait ErrorContext {
|
||||
/// Contextualize the given consequent error with this (`self`) error as
|
||||
/// the cause.
|
||||
///
|
||||
/// This is equivalent to saying that "consequent is caused by self."
|
||||
///
|
||||
/// Note that if an `Error` is given for `kind`, then this panics if it has
|
||||
/// a cause. (Because the cause would otherwise be dropped. An error causal
|
||||
/// chain is just a linked list, not a tree.)
|
||||
fn context(self, consequent: impl IntoError) -> Self;
|
||||
|
||||
/// Like `context`, but hides error construction within a closure.
|
||||
///
|
||||
/// This is useful if the creation of the consequent error is not otherwise
|
||||
/// guarded and when error construction is potentially "costly" (i.e., it
|
||||
/// allocates). The closure avoids paying the cost of contextual error
|
||||
/// creation in the happy path.
|
||||
///
|
||||
/// Usually this only makes sense to use on a `Result<T, Error>`, otherwise
|
||||
/// the closure is just executed immediately anyway.
|
||||
fn with_context<E: IntoError>(
|
||||
self,
|
||||
consequent: impl FnOnce() -> E,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
impl ErrorContext for Error {
|
||||
fn context(self, consequent: impl IntoError) -> Error {
|
||||
let mut err = consequent.into_error();
|
||||
assert!(
|
||||
err.inner.cause.is_none(),
|
||||
"cause of consequence must be `None`"
|
||||
);
|
||||
err.inner.cause = Some(self);
|
||||
err
|
||||
}
|
||||
|
||||
fn with_context<E: IntoError>(
|
||||
self,
|
||||
consequent: impl FnOnce() -> E,
|
||||
) -> Error {
|
||||
let mut err = consequent().into_error();
|
||||
assert!(
|
||||
err.inner.cause.is_none(),
|
||||
"cause of consequence must be `None`"
|
||||
);
|
||||
err.inner.cause = Some(self);
|
||||
err
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ErrorContext for Result<T, Error> {
|
||||
fn context(self, consequent: impl IntoError) -> Result<T, Error> {
|
||||
self.map_err(|err| err.context(consequent))
|
||||
}
|
||||
|
||||
fn with_context<E: IntoError>(
|
||||
self,
|
||||
consequent: impl FnOnce() -> E,
|
||||
) -> Result<T, Error> {
|
||||
self.map_err(|err| err.with_context(consequent))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// We test that our 'Error' type is the size we expect. This isn't an API
|
||||
// guarantee, but if the size increases, we really want to make sure we
|
||||
// decide to do that intentionally. So this should be a speed bump. And in
|
||||
// general, we should not increase the size without a very good reason.
|
||||
#[test]
|
||||
fn error_size() {
|
||||
let expected_size = core::mem::size_of::<usize>();
|
||||
assert_eq!(expected_size, core::mem::size_of::<Error>());
|
||||
}
|
||||
}
|
||||
272
src/format/mod.rs
Normal file
272
src/format/mod.rs
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
use alloc::{string::String, vec::Vec};
|
||||
|
||||
use crate::{
|
||||
civil,
|
||||
error::{err, Error},
|
||||
tz::Offset,
|
||||
util::{escape, t},
|
||||
Instant, TimeScale, Zoned,
|
||||
};
|
||||
|
||||
use self::util::{Decimal, DecimalFormatter};
|
||||
|
||||
mod offset;
|
||||
pub mod rfc3339;
|
||||
mod rfc9557;
|
||||
pub mod temporal;
|
||||
mod util;
|
||||
|
||||
const _: &'static dyn Printer = &self::rfc3339::Printer::new();
|
||||
|
||||
pub trait Parser {
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
fn parse_zoned<'i, S: TimeScale>(
|
||||
&self,
|
||||
_input: &'i [u8],
|
||||
) -> Result<Parsed<'i, Zoned<S>>, Error> {
|
||||
Err(err!(
|
||||
"{name} does not support parsing zoned instants",
|
||||
name = self.name()
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_instant<'i, S: TimeScale>(
|
||||
&self,
|
||||
_input: &'i [u8],
|
||||
) -> Result<Parsed<'i, Instant<S>>, Error> {
|
||||
Err(err!(
|
||||
"{name} does not support parsing instants",
|
||||
name = self.name()
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_datetime<'i>(
|
||||
&self,
|
||||
_input: &'i [u8],
|
||||
) -> Result<Parsed<'i, civil::DateTime>, Error> {
|
||||
Err(err!(
|
||||
"{name} does not support parsing civil datetimes",
|
||||
name = self.name()
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_date<'i>(
|
||||
&self,
|
||||
_input: &'i [u8],
|
||||
) -> Result<Parsed<'i, civil::Date>, Error> {
|
||||
Err(err!(
|
||||
"{name} does not support parsing civil date",
|
||||
name = self.name()
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_time<'i>(
|
||||
&self,
|
||||
_input: &'i [u8],
|
||||
) -> Result<Parsed<'i, civil::Time>, Error> {
|
||||
Err(err!(
|
||||
"{name} does not support parsing civil times",
|
||||
name = self.name()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of parsing a value out of a slice of bytes.
|
||||
///
|
||||
/// This contains both the parsed value and the offset at which the value
|
||||
/// ended in the input given. This makes it possible to parse, for example, a
|
||||
/// datetime value as a prefix of some larger string without knowing ahead of
|
||||
/// time where it ends.
|
||||
#[derive(Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Parsed<'i, V> {
|
||||
/// The value parsed.
|
||||
pub value: V,
|
||||
/// The remaining unparsed input.
|
||||
pub input: &'i [u8],
|
||||
}
|
||||
|
||||
impl<'i, V: core::fmt::Display> Parsed<'i, V> {
|
||||
/// Ensures that the parsed value represents the entire input. This occurs
|
||||
/// precisely when the `input` on this parsed value is empty.
|
||||
///
|
||||
/// This is useful when one expects a parsed value to consume the entire
|
||||
/// input, and to consider it an error if it doesn't.
|
||||
pub fn into_full(self) -> Result<V, Error> {
|
||||
if self.input.is_empty() {
|
||||
return Ok(self.value);
|
||||
}
|
||||
Err(err!(
|
||||
"parsed value '{value}', but unparsed input {unparsed:?}
|
||||
remains (expected no unparsed input)",
|
||||
value = self.value,
|
||||
unparsed = escape::Bytes(self.input),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'i, V: core::fmt::Debug> core::fmt::Debug for Parsed<'i, V> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
f.debug_struct("Parsed")
|
||||
.field("value", &self.value)
|
||||
.field("input", &escape::Bytes(self.input))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Printer {
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
fn print_zoned<S: TimeScale, W: Write>(
|
||||
&self,
|
||||
_zoned: &Zoned<S>,
|
||||
_wtr: W,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Err(err!(
|
||||
"{name} does not support printing zoned instants",
|
||||
name = self.name()
|
||||
))
|
||||
}
|
||||
|
||||
fn print_instant<S: TimeScale, W: Write>(
|
||||
&self,
|
||||
_instant: &Instant<S>,
|
||||
_wtr: W,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Err(err!(
|
||||
"{name} does not support printing instants",
|
||||
name = self.name()
|
||||
))
|
||||
}
|
||||
|
||||
fn print_datetime<W: Write>(
|
||||
&self,
|
||||
_datetime: &civil::DateTime,
|
||||
_wtr: W,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Err(err!(
|
||||
"{name} does not support printing civil datetimes",
|
||||
name = self.name()
|
||||
))
|
||||
}
|
||||
|
||||
fn print_date<W: Write>(
|
||||
&self,
|
||||
_date: &civil::Date,
|
||||
_wtr: W,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Err(err!(
|
||||
"{name} does not support printing civil dates",
|
||||
name = self.name()
|
||||
))
|
||||
}
|
||||
|
||||
fn print_time<W: Write>(
|
||||
&self,
|
||||
_time: &civil::Time,
|
||||
_wtr: W,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Err(err!(
|
||||
"{name} does not support printing civil times",
|
||||
name = self.name()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Write {
|
||||
fn write_str(&mut self, string: &str) -> Result<(), Error>;
|
||||
|
||||
#[inline]
|
||||
fn write_char(&mut self, char: char) -> Result<(), Error> {
|
||||
self.write_str(char.encode_utf8(&mut [0; 4]))
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for String {
|
||||
#[inline]
|
||||
fn write_str(&mut self, string: &str) -> Result<(), Error> {
|
||||
self.push_str(string);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Vec<u8> {
|
||||
#[inline]
|
||||
fn write_str(&mut self, string: &str) -> Result<(), Error> {
|
||||
self.extend_from_slice(string.as_bytes());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> Write for &mut W {
|
||||
fn write_str(&mut self, string: &str) -> Result<(), Error> {
|
||||
(**self).write_str(string)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_char(&mut self, char: char) -> Result<(), Error> {
|
||||
(**self).write_char(char)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StdWrite<W>(pub W);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<W: std::io::Write> Write for StdWrite<W> {
|
||||
#[inline]
|
||||
fn write_str(&mut self, string: &str) -> Result<(), Error> {
|
||||
use alloc::string::ToString;
|
||||
|
||||
self.0.write_all(string.as_bytes()).map_err(Error::adhoc)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FmtWrite<W>(pub W);
|
||||
|
||||
impl<W: core::fmt::Write> Write for FmtWrite<W> {
|
||||
#[inline]
|
||||
fn write_str(&mut self, string: &str) -> Result<(), Error> {
|
||||
use alloc::string::ToString;
|
||||
|
||||
self.0.write_str(string).map_err(Error::adhoc)
|
||||
}
|
||||
}
|
||||
|
||||
trait WriteExt: Write {
|
||||
/// Write the given number as a decimal using ASCII digits to this buffer.
|
||||
/// The given formatter controls how the decimal is formatted.
|
||||
#[inline]
|
||||
fn write_int(
|
||||
&mut self,
|
||||
formatter: &DecimalFormatter,
|
||||
n: impl Into<i64>,
|
||||
) -> Result<(), Error> {
|
||||
self.write_decimal(&Decimal::new(formatter, n.into()))
|
||||
}
|
||||
|
||||
/// Write the given decimal number to this buffer.
|
||||
#[inline]
|
||||
fn write_decimal(&mut self, decimal: &Decimal) -> Result<(), Error> {
|
||||
self.write_str(decimal.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write> WriteExt for W {}
|
||||
1021
src/format/offset.rs
Normal file
1021
src/format/offset.rs
Normal file
File diff suppressed because it is too large
Load diff
213
src/format/rfc3339.rs
Normal file
213
src/format/rfc3339.rs
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
use alloc::{string::String, vec::Vec};
|
||||
|
||||
use crate::{
|
||||
civil::DateTime,
|
||||
error::Error,
|
||||
format::{self, util::DecimalFormatter, Write, WriteExt},
|
||||
tz::Offset,
|
||||
Instant, TimeScale, TimeZone, Zoned,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Parser {
|
||||
flexible_separator: bool,
|
||||
rfc9557: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Printer {
|
||||
lowercase: bool,
|
||||
separator: u8,
|
||||
rfc9557: bool,
|
||||
}
|
||||
|
||||
impl Printer {
|
||||
pub const fn new() -> Printer {
|
||||
Printer { lowercase: false, separator: b'T', rfc9557: true }
|
||||
}
|
||||
|
||||
pub const fn lowercase(self, yes: bool) -> Printer {
|
||||
Printer { lowercase: yes, ..self }
|
||||
}
|
||||
|
||||
pub const fn separator(self, ascii_char: u8) -> Printer {
|
||||
assert!(ascii_char.is_ascii(), "RFC3339 separator must be ASCII");
|
||||
Printer { separator: ascii_char, ..self }
|
||||
}
|
||||
|
||||
pub const fn rfc9557(self, yes: bool) -> Printer {
|
||||
Printer { rfc9557: yes, ..self }
|
||||
}
|
||||
|
||||
/// Formats the given datetime into the writer given.
|
||||
fn print_datetime<W: Write>(
|
||||
&self,
|
||||
dt: &DateTime,
|
||||
mut wtr: W,
|
||||
) -> Result<(), Error> {
|
||||
static FMT_YEAR: DecimalFormatter =
|
||||
DecimalFormatter::new().minimum_digits(4);
|
||||
static FMT_TWO: DecimalFormatter =
|
||||
DecimalFormatter::new().minimum_digits(2);
|
||||
static FMT_FRACTION: DecimalFormatter =
|
||||
DecimalFormatter::new().minimum_digits(9);
|
||||
|
||||
wtr.write_int(&FMT_YEAR, dt.date().year())?;
|
||||
wtr.write_str("-");
|
||||
wtr.write_int(&FMT_TWO, dt.date().month())?;
|
||||
wtr.write_str("-")?;
|
||||
wtr.write_int(&FMT_TWO, dt.date().day())?;
|
||||
wtr.write_char(char::from(if self.lowercase {
|
||||
self.separator.to_ascii_lowercase()
|
||||
} else {
|
||||
self.separator
|
||||
}))?;
|
||||
wtr.write_int(&FMT_TWO, dt.time().hour())?;
|
||||
wtr.write_str(":")?;
|
||||
wtr.write_int(&FMT_TWO, dt.time().minute())?;
|
||||
wtr.write_str(":")?;
|
||||
wtr.write_int(&FMT_TWO, dt.time().second())?;
|
||||
let fractional_nanosecond = dt.time().subsec_nanosecond();
|
||||
if fractional_nanosecond != 0 {
|
||||
wtr.write_str(".")?;
|
||||
wtr.write_int(&FMT_FRACTION, fractional_nanosecond)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Formats the given offset into the writer given.
|
||||
fn print_offset<W: Write>(
|
||||
&self,
|
||||
offset: &Offset,
|
||||
mut wtr: W,
|
||||
) -> Result<(), Error> {
|
||||
static FMT_TWO: DecimalFormatter =
|
||||
DecimalFormatter::new().minimum_digits(2);
|
||||
|
||||
wtr.write_str(if offset.is_negative() { "-" } else { "+" })?;
|
||||
let mut hours = offset.part_hours_ranged().abs().get();
|
||||
let mut minutes = offset.part_minutes_ranged().abs().get();
|
||||
// RFC 3339 requires that time zone offsets are an integral number
|
||||
// of minutes. While rounding based on seconds doesn't seem clearly
|
||||
// indicated, the `1937-01-01T12:00:27.87+00:20` example seems
|
||||
// to suggest that the number of minutes should be "as close as
|
||||
// possible" to the actual offset. So we just do basic rounding
|
||||
// here.
|
||||
if offset.part_seconds_ranged().abs() >= 30 {
|
||||
if minutes == 59 {
|
||||
hours = hours.saturating_add(1);
|
||||
minutes = 0;
|
||||
} else {
|
||||
minutes = minutes.saturating_add(1);
|
||||
}
|
||||
}
|
||||
wtr.write_int(&FMT_TWO, hours)?;
|
||||
wtr.write_str(":")?;
|
||||
wtr.write_int(&FMT_TWO, minutes)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Prints the "zulu" indicator.
|
||||
///
|
||||
/// This should only be used when the local offset is not known. For
|
||||
/// example, when printing an `Instant`.
|
||||
fn print_zulu<W: Write>(&self, mut wtr: W) -> Result<(), Error> {
|
||||
wtr.write_str(if self.lowercase { "z" } else { "Z" })
|
||||
}
|
||||
|
||||
/// Formats the given time zone name into the writer given.
|
||||
///
|
||||
/// This is a no-op when RFC 9557 support isn't enabled. And when the given
|
||||
/// time zone is not an IANA time zone name, then the offset is printed
|
||||
/// instead. (This means the offset will be printed twice, which is indeed
|
||||
/// an intended behavior of RFC 9557 for cases where a time zone name is
|
||||
/// not used or unavailable.)
|
||||
fn print_time_zone<W: Write>(
|
||||
&self,
|
||||
time_zone: &TimeZone,
|
||||
offset: &Offset,
|
||||
mut wtr: W,
|
||||
) -> Result<(), Error> {
|
||||
if !self.rfc9557 {
|
||||
return Ok(());
|
||||
}
|
||||
wtr.write_str("[")?;
|
||||
if let Some(iana_name) = time_zone.iana_name() {
|
||||
wtr.write_str(iana_name)?;
|
||||
} else {
|
||||
self.print_offset(offset, &mut wtr)?;
|
||||
}
|
||||
wtr.write_str("]")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Printer {
|
||||
fn default() -> Printer {
|
||||
Printer::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl format::Printer for Printer {
|
||||
fn name(&self) -> &'static str {
|
||||
"RFC3339"
|
||||
}
|
||||
|
||||
fn print_zoned<S: TimeScale, W: Write>(
|
||||
&self,
|
||||
zoned: &Zoned<S>,
|
||||
mut wtr: W,
|
||||
) -> Result<(), Error> {
|
||||
let instant = zoned.to_instant();
|
||||
let tz = zoned.time_zone();
|
||||
let (offset, _, _) = tz.to_offset(instant);
|
||||
let dt = offset.to_datetime(instant);
|
||||
self.print_datetime(&dt, &mut wtr)?;
|
||||
self.print_offset(&offset, &mut wtr)?;
|
||||
self.print_time_zone(&tz, &offset, &mut wtr)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_instant<S: TimeScale, W: Write>(
|
||||
&self,
|
||||
instant: &Instant<S>,
|
||||
mut wtr: W,
|
||||
) -> Result<(), Error> {
|
||||
let dt = TimeZone::UTC.to_datetime(*instant);
|
||||
self.print_datetime(&dt, &mut wtr)?;
|
||||
self.print_zulu(&mut wtr)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::format::Printer as _;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn print_zoned() {
|
||||
let dt = DateTime::constant(2024, 3, 10, 5, 34, 45, 0);
|
||||
let zoned: Zoned = dt.to_zoned("America/New_York").unwrap();
|
||||
let mut buf = String::new();
|
||||
Printer::new().print_zoned(&zoned, &mut buf).unwrap();
|
||||
assert_eq!(buf, "2024-03-10T05:34:45-04:00[America/New_York]");
|
||||
|
||||
let dt = DateTime::constant(2024, 3, 10, 5, 34, 45, 0);
|
||||
let zoned: Zoned = dt.to_zoned("America/New_York").unwrap();
|
||||
let zoned = zoned.with_time_zone(TimeZone::UTC);
|
||||
let mut buf = String::new();
|
||||
Printer::new().print_zoned(&zoned, &mut buf).unwrap();
|
||||
assert_eq!(buf, "2024-03-10T09:34:45+00:00[UTC]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn print_instant() {
|
||||
let dt = DateTime::constant(2024, 3, 10, 5, 34, 45, 0);
|
||||
let zoned: Zoned = dt.to_zoned("America/New_York").unwrap();
|
||||
let mut buf = String::new();
|
||||
Printer::new().print_instant(&zoned.to_instant(), &mut buf).unwrap();
|
||||
assert_eq!(buf, "2024-03-10T09:34:45Z");
|
||||
}
|
||||
}
|
||||
1020
src/format/rfc9557.rs
Normal file
1020
src/format/rfc9557.rs
Normal file
File diff suppressed because it is too large
Load diff
2298
src/format/temporal.rs
Normal file
2298
src/format/temporal.rs
Normal file
File diff suppressed because it is too large
Load diff
236
src/format/util.rs
Normal file
236
src/format/util.rs
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
/// A simple formatter for converting `i64` values to ASCII byte strings.
|
||||
///
|
||||
/// This avoids going through the formatting machinery which seems to
|
||||
/// substantially slow things down.
|
||||
///
|
||||
/// The `itoa` crate does the same thing as this formatter, but is a bit
|
||||
/// faster. We roll our own which is a bit slower, but gets us enough of a win
|
||||
/// to be satisfied with and with pure safe code.
|
||||
///
|
||||
/// By default, this only includes the sign if it's negative. To always include
|
||||
/// the sign, set `force_sign` to `true`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct DecimalFormatter {
|
||||
force_sign: Option<bool>,
|
||||
minimum_digits: Option<u8>,
|
||||
fractional: bool,
|
||||
}
|
||||
|
||||
impl DecimalFormatter {
|
||||
/// Creates a new decimal formatter using the default configuration.
|
||||
pub(crate) const fn new() -> DecimalFormatter {
|
||||
DecimalFormatter {
|
||||
force_sign: None,
|
||||
minimum_digits: None,
|
||||
fractional: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Format the given value using this configuration as a decimal ASCII
|
||||
/// number.
|
||||
pub(crate) const fn format(&self, value: i64) -> Decimal {
|
||||
Decimal::new(self, value)
|
||||
}
|
||||
|
||||
/// Forces the sign to be rendered, even if it's positive.
|
||||
///
|
||||
/// When `zero_is_positive` is true, then a zero value is formatted with a
|
||||
/// positive sign. Otherwise, it is formatted with a negative sign.
|
||||
pub(crate) const fn force_sign(
|
||||
self,
|
||||
zero_is_positive: bool,
|
||||
) -> DecimalFormatter {
|
||||
DecimalFormatter { force_sign: Some(zero_is_positive), ..self }
|
||||
}
|
||||
|
||||
/// The minimum number of digits that this number should be formatted with.
|
||||
/// If the number would have fewer digits than this, then it is padded out
|
||||
/// with zeros until the minimum is reached.
|
||||
///
|
||||
/// The minimum number of digits is capped at the maximum number of digits
|
||||
/// for an i64 value (which is 19).
|
||||
pub(crate) const fn minimum_digits(
|
||||
self,
|
||||
mut digits: u8,
|
||||
) -> DecimalFormatter {
|
||||
if digits > Decimal::MAX_I64_DIGITS {
|
||||
digits = Decimal::MAX_I64_DIGITS;
|
||||
}
|
||||
DecimalFormatter { minimum_digits: Some(digits), ..self }
|
||||
}
|
||||
|
||||
/// Sets the maximum precision of this as a fractional number.
|
||||
///
|
||||
/// This is useful for formatting the fractional digits to the right-hand
|
||||
/// side of a decimal point.
|
||||
///
|
||||
/// This implies `minimum_digits(max_precision)`, but also strips all
|
||||
/// trailing zeros.
|
||||
///
|
||||
/// The maximum precision is capped at the maximum number of digits for an
|
||||
/// i64 value (which is 19).
|
||||
pub(crate) const fn fractional(
|
||||
self,
|
||||
max_precision: u8,
|
||||
) -> DecimalFormatter {
|
||||
DecimalFormatter {
|
||||
fractional: true,
|
||||
..self.minimum_digits(max_precision)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DecimalFormatter {
|
||||
fn default() -> DecimalFormatter {
|
||||
DecimalFormatter::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// A formatted decimal number that can be converted to a sequence of bytes.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Decimal {
|
||||
buf: [u8; Self::MAX_I64_LEN as usize],
|
||||
start: u8,
|
||||
end: u8,
|
||||
}
|
||||
|
||||
impl Decimal {
|
||||
/// Discovered via `i64::MIN.to_string().len()`.
|
||||
const MAX_I64_LEN: u8 = 20;
|
||||
/// Discovered via `i64::MAX.to_string().len()`.
|
||||
const MAX_I64_DIGITS: u8 = 19;
|
||||
|
||||
/// Using the given formatter, turn the value given into a decimal
|
||||
/// representation using ASCII bytes.
|
||||
pub(crate) const fn new(
|
||||
formatter: &DecimalFormatter,
|
||||
value: i64,
|
||||
) -> Decimal {
|
||||
let sign = value.signum();
|
||||
let Some(mut value) = value.checked_abs() else {
|
||||
let buf = [
|
||||
b'-', b'9', b'2', b'2', b'3', b'3', b'7', b'2', b'0', b'3',
|
||||
b'6', b'8', b'5', b'4', b'7', b'7', b'5', b'8', b'0', b'8',
|
||||
];
|
||||
return Decimal { buf, start: 0, end: Self::MAX_I64_LEN };
|
||||
};
|
||||
let mut decimal = Decimal {
|
||||
buf: [0; Self::MAX_I64_LEN as usize],
|
||||
start: Self::MAX_I64_LEN,
|
||||
end: Self::MAX_I64_LEN,
|
||||
};
|
||||
loop {
|
||||
decimal.start -= 1;
|
||||
|
||||
let digit = (value % 10) as u8;
|
||||
value /= 10;
|
||||
decimal.buf[decimal.start as usize] = b'0' + digit;
|
||||
if value == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(minimum_digits) = formatter.minimum_digits {
|
||||
while decimal.len() < minimum_digits {
|
||||
decimal.start -= 1;
|
||||
decimal.buf[decimal.start as usize] = b'0';
|
||||
}
|
||||
}
|
||||
if sign < 0 {
|
||||
decimal.start -= 1;
|
||||
decimal.buf[decimal.start as usize] = b'-';
|
||||
} else if let Some(zero_is_positive) = formatter.force_sign {
|
||||
let ascii_sign =
|
||||
if sign > 0 || zero_is_positive { b'+' } else { b'-' };
|
||||
decimal.start -= 1;
|
||||
decimal.buf[decimal.start as usize] = ascii_sign;
|
||||
}
|
||||
if formatter.fractional {
|
||||
while decimal.end > 0
|
||||
&& decimal.buf[decimal.end as usize - 1] == b'0'
|
||||
{
|
||||
decimal.end -= 1;
|
||||
}
|
||||
}
|
||||
decimal
|
||||
}
|
||||
|
||||
/// Returns the total number of ASCII bytes (including the sign) that are
|
||||
/// used to represent this decimal number.
|
||||
const fn len(&self) -> u8 {
|
||||
Self::MAX_I64_LEN - self.start
|
||||
}
|
||||
|
||||
/// Returns the ASCII representation of this decimal as a byte slice.
|
||||
///
|
||||
/// The slice returned is guaranteed to be valid ASCII.
|
||||
pub(crate) fn as_bytes(&self) -> &[u8] {
|
||||
&self.buf[usize::from(self.start)..usize::from(self.end)]
|
||||
}
|
||||
|
||||
/// Returns the ASCII representation of this decimal as a string slice.
|
||||
pub(crate) fn as_str(&self) -> &str {
|
||||
// SAFETY: This is safe because all bytes written to `self.buf` are
|
||||
// guaranteed to be ASCII (including in its initial state), and thus,
|
||||
// any subsequence is guaranteed to be valid UTF-8.
|
||||
unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn decimal() {
|
||||
let x = DecimalFormatter::new().format(i64::MIN);
|
||||
assert_eq!(x.as_str(), "-9223372036854775808");
|
||||
|
||||
let x = DecimalFormatter::new().format(i64::MIN + 1);
|
||||
assert_eq!(x.as_str(), "-9223372036854775807");
|
||||
|
||||
let x = DecimalFormatter::new().format(i64::MAX);
|
||||
assert_eq!(x.as_str(), "9223372036854775807");
|
||||
|
||||
let x = DecimalFormatter::new().force_sign(true).format(i64::MAX);
|
||||
assert_eq!(x.as_str(), "+9223372036854775807");
|
||||
|
||||
let x = DecimalFormatter::new().format(0);
|
||||
assert_eq!(x.as_str(), "0");
|
||||
|
||||
let x = DecimalFormatter::new().force_sign(true).format(0);
|
||||
assert_eq!(x.as_str(), "+0");
|
||||
|
||||
let x = DecimalFormatter::new().force_sign(false).format(0);
|
||||
assert_eq!(x.as_str(), "-0");
|
||||
|
||||
let x = DecimalFormatter::new().minimum_digits(4).format(0);
|
||||
assert_eq!(x.as_str(), "0000");
|
||||
|
||||
let x = DecimalFormatter::new().minimum_digits(4).format(789);
|
||||
assert_eq!(x.as_str(), "0789");
|
||||
|
||||
let x = DecimalFormatter::new().minimum_digits(4).format(-789);
|
||||
assert_eq!(x.as_str(), "-0789");
|
||||
|
||||
let x = DecimalFormatter::new()
|
||||
.force_sign(true)
|
||||
.minimum_digits(4)
|
||||
.format(789);
|
||||
assert_eq!(x.as_str(), "+0789");
|
||||
|
||||
let x = DecimalFormatter::new().fractional(9).format(123_000_000);
|
||||
assert_eq!(x.as_str(), "123");
|
||||
|
||||
let x = DecimalFormatter::new().fractional(9).format(123_456_000);
|
||||
assert_eq!(x.as_str(), "123456");
|
||||
|
||||
let x = DecimalFormatter::new().fractional(9).format(123_456_789);
|
||||
assert_eq!(x.as_str(), "123456789");
|
||||
|
||||
let x = DecimalFormatter::new().fractional(9).format(456_789);
|
||||
assert_eq!(x.as_str(), "000456789");
|
||||
|
||||
let x = DecimalFormatter::new().fractional(9).format(789);
|
||||
assert_eq!(x.as_str(), "000000789");
|
||||
}
|
||||
}
|
||||
1202
src/instant.rs
Normal file
1202
src/instant.rs
Normal file
File diff suppressed because it is too large
Load diff
453
src/leapseconds.rs
Normal file
453
src/leapseconds.rs
Normal file
|
|
@ -0,0 +1,453 @@
|
|||
use alloc::{vec, vec::Vec};
|
||||
|
||||
use crate::{
|
||||
civil::{Date, DateTime, Time},
|
||||
error::{err, Error, ErrorContext},
|
||||
instant::{Instant, Tai, Unix},
|
||||
tz::TimeZone,
|
||||
util::{
|
||||
parse,
|
||||
rangeint::{RFrom, RInto, TryRFrom},
|
||||
t::{self, C},
|
||||
},
|
||||
};
|
||||
|
||||
/// The number of seconds that elapsed between the NTP epoch
|
||||
/// (`1900-01-01T00:00:00Z`) and the Unix epoch (`1970-01-01T00:00:00Z`).
|
||||
const NTP_UNIX_EPOCH_DIFFERENCE: i64 = 2208988800;
|
||||
|
||||
/// Leap seconds in NIST format, which is mostly a copy of the [IERS upstream
|
||||
/// format].
|
||||
///
|
||||
/// Apparently the IERS data file isn't commonly used because of some bullshit
|
||||
/// about copyright.
|
||||
///
|
||||
/// [IERA upstream format]: https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list
|
||||
static NIST: &'static [u8] = include_bytes!("data/leap-seconds.list");
|
||||
|
||||
/// Leap seconds in IANA format.
|
||||
///
|
||||
/// I'm not totally clear on why this format exists, but it expresses the same
|
||||
/// thing as the NIST formatted data, but... in a different format. It is also
|
||||
/// derived from the NIST data. Here are some differences I observed:
|
||||
///
|
||||
/// * The leap seconds specified in UTC. This is arguably more correct, because
|
||||
/// this is to me how leap seconds are defined. But, it also makes the format
|
||||
/// more annoying to parse and use. For example, it implies that you need a
|
||||
/// way to go from civil datetimes to Unix timestamps. The NIST data instead
|
||||
/// reports leap seconds in Unix time with a `1900-01-01T00:00:00Z` epoch.
|
||||
/// * Each leap second is specified as a `+` or a `-`, where as in NIST,
|
||||
/// each leap second reports the total accumulated offset. I find the NIST
|
||||
/// representation easier to work with personally.
|
||||
/// * The NIST data includes the 10 second offset at the start of UTC (Jan 1
|
||||
/// 1972), where as the IANA data does not. The IANA data seems to omit it
|
||||
/// because it doesn't technically denote a single leap second. But in my view,
|
||||
/// it effectively denotes an accumulation of 10 leap seconds.
|
||||
/// * The NIST data uses comments to denote the date immediately following the
|
||||
/// leap second, where as the IANA UTC datetimes correspond to leap second
|
||||
/// itself.
|
||||
///
|
||||
/// We just support both because it's not that hard to, and because it'd be
|
||||
/// frustrating if you only had one format and not the other. For example, on
|
||||
/// my Archlinux system, I have both `/usr/share/zoneinfo/leapseconds` (that's
|
||||
/// IANA) and `/usr/share/zoneinfo/leap-seconds.list` (that's NIST), but on my
|
||||
/// mac, all I have is `/usr/share/zoneinfo/leapseconds`. Fun times.
|
||||
static IANA: &'static [u8] = include_bytes!("data/leapseconds");
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct LeapSeconds {
|
||||
expires: Instant,
|
||||
by_unix: Vec<LeapSecondUnix>,
|
||||
by_tai: Vec<LeapSecondTai>,
|
||||
}
|
||||
|
||||
impl LeapSeconds {
|
||||
pub fn builtin() -> LeapSeconds {
|
||||
LeapSeconds::from_nist_bytes(NIST)
|
||||
.expect("hard-coded leap seconds always parse correctly")
|
||||
}
|
||||
|
||||
pub fn from_nist(data: &str) -> Result<LeapSeconds, Error> {
|
||||
parse_nist(data)
|
||||
}
|
||||
|
||||
pub fn from_nist_bytes(data: &[u8]) -> Result<LeapSeconds, Error> {
|
||||
let data = core::str::from_utf8(data)
|
||||
.map_err(Error::adhoc)
|
||||
.context("invalid UTF-8")?;
|
||||
LeapSeconds::from_nist(data)
|
||||
}
|
||||
|
||||
pub fn from_iana(data: &str) -> Result<LeapSeconds, Error> {
|
||||
parse_iana(data)
|
||||
}
|
||||
|
||||
pub fn from_iana_bytes(data: &[u8]) -> Result<LeapSeconds, Error> {
|
||||
let data = core::str::from_utf8(data)
|
||||
.map_err(Error::adhoc)
|
||||
.context("invalid UTF-8")?;
|
||||
LeapSeconds::from_iana(data)
|
||||
}
|
||||
|
||||
pub fn unix_to_tai(
|
||||
&self,
|
||||
instant: Instant<Unix>,
|
||||
) -> Result<Instant<Tai>, Error> {
|
||||
let tai_timestamp =
|
||||
self.unix_to_tai_timestamp(instant.second_ranged())?;
|
||||
Ok(Instant::from_timestamp_ranged(
|
||||
tai_timestamp,
|
||||
instant.nanosecond_ranged(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn tai_to_unix(&self, instant: Instant<Tai>) -> Instant<Unix> {
|
||||
let (unix_timestamp, _) =
|
||||
self.tai_to_unix_timestamp(instant.second_ranged());
|
||||
Instant::from_timestamp_ranged(
|
||||
unix_timestamp,
|
||||
instant.nanosecond_ranged(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn unix_to_tai_timestamp(
|
||||
&self,
|
||||
unix_timestamp: t::UnixSeconds,
|
||||
) -> Result<t::TaiSeconds, Error> {
|
||||
let result = self
|
||||
.by_unix
|
||||
.binary_search_by(|ls| ls.timestamp.cmp(&unix_timestamp));
|
||||
let i = match result {
|
||||
Ok(i) => i,
|
||||
Err(i) if i == 0 => {
|
||||
return t::TaiSeconds::try_rfrom(
|
||||
"unix-to-tai seconds",
|
||||
unix_timestamp,
|
||||
);
|
||||
}
|
||||
Err(i) => i - 1,
|
||||
};
|
||||
let unix_timestamp = t::TaiSeconds::rfrom(unix_timestamp);
|
||||
Ok(unix_timestamp.try_checked_add(
|
||||
"unix-to-tai seconds",
|
||||
self.by_unix[i].leap_seconds,
|
||||
)?)
|
||||
}
|
||||
|
||||
pub fn tai_to_unix_timestamp(
|
||||
&self,
|
||||
tai_timestamp: t::TaiSeconds,
|
||||
) -> (t::UnixSeconds, bool) {
|
||||
let result = self
|
||||
.by_tai
|
||||
.binary_search_by(|ls| ls.timestamp.cmp(&tai_timestamp));
|
||||
let i = match result {
|
||||
Ok(i) => i,
|
||||
Err(i) if i == 0 => return (tai_timestamp.rinto(), false),
|
||||
Err(i) => i - 1,
|
||||
};
|
||||
// The leap second table is keyed by the first second *after* the leap
|
||||
// second. So we know we have a leap second when it is precisely one
|
||||
// less than the timestamp in the *next* entry.
|
||||
let is_leap = i
|
||||
.checked_add(1)
|
||||
.and_then(|i| self.by_tai.get(i))
|
||||
.and_then(|ls| ls.timestamp.checked_sub(C(1)))
|
||||
.map_or(false, |ts| ts == tai_timestamp);
|
||||
((tai_timestamp + self.by_tai[i].leap_seconds).rinto(), is_leap)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
struct LeapSecondTai {
|
||||
timestamp: t::TaiSeconds,
|
||||
leap_seconds: t::LeapSecondOffset,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
struct LeapSecondUnix {
|
||||
timestamp: t::UnixSeconds,
|
||||
leap_seconds: t::LeapSecondOffset,
|
||||
}
|
||||
|
||||
impl LeapSecondUnix {
|
||||
/// Creates a new leap second for the given Unix timestamp and the leap
|
||||
/// second offset. This returns an error if the given values are not valid
|
||||
/// Unix timestamps in Jiff.
|
||||
fn new(
|
||||
timestamp: i64,
|
||||
leap_seconds: i64,
|
||||
) -> Result<LeapSecondUnix, Error> {
|
||||
let timestamp =
|
||||
t::UnixSeconds::try_new("", timestamp).with_context(|| {
|
||||
err!("Unix timestamp {timestamp} is out of Jiff's range")
|
||||
})?;
|
||||
let leap_seconds = t::LeapSecondOffset::try_new("", leap_seconds)
|
||||
.with_context(|| {
|
||||
err!(
|
||||
"leap second offset {leap_seconds} is out of Jiff's range"
|
||||
)
|
||||
})?;
|
||||
Ok(LeapSecondUnix { timestamp, leap_seconds })
|
||||
}
|
||||
|
||||
/// Convert this leap second in terms of Unix time to TAI time.
|
||||
///
|
||||
/// In effect, the corresponding TAI leap second is just the Unix time
|
||||
/// plus the number of leap seconds that have been added/subtracted since
|
||||
/// that point.
|
||||
fn to_tai(&self) -> Result<LeapSecondTai, Error> {
|
||||
let LeapSecondUnix { timestamp, leap_seconds } = *self;
|
||||
let timestamp = t::TaiSeconds::rfrom(timestamp)
|
||||
.try_checked_add("", leap_seconds)
|
||||
.with_context(|| {
|
||||
err!(
|
||||
"overflow occurred when adding Unix timestamp \
|
||||
{timestamp} to leap second offset {leap_seconds}",
|
||||
)
|
||||
})?;
|
||||
let leap_seconds = t::LeapSecondOffset::rfrom(-leap_seconds);
|
||||
Ok(LeapSecondTai { timestamp, leap_seconds })
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_nist(string: &str) -> Result<LeapSeconds, Error> {
|
||||
let mut expires: Option<Instant> = None;
|
||||
let mut by_unix = vec![];
|
||||
let mut by_tai = vec![];
|
||||
for line in string.lines() {
|
||||
if let Some(expires_str) = line.strip_prefix("#@") {
|
||||
if expires.is_some() {
|
||||
return Err(err!("found multiple expiration lines"));
|
||||
}
|
||||
let n = parse::i64(expires_str.trim().as_bytes()).with_context(
|
||||
|| err!("failed to parse expiration timestamp from {line:?}"),
|
||||
)?;
|
||||
expires = Some(ntp_to_instant(n)?);
|
||||
} else if line.starts_with("#") || line.trim().is_empty() {
|
||||
continue;
|
||||
} else {
|
||||
let mut fields = line.trim().split_whitespace();
|
||||
let start_str = fields.next().ok_or_else(|| {
|
||||
err!(
|
||||
"could not find first field in line {line:?} \
|
||||
in NIST formatted leap second data",
|
||||
)
|
||||
})?;
|
||||
let offset_str = fields.next().ok_or_else(|| {
|
||||
err!(
|
||||
"could not find second field in line {line:?} \
|
||||
in NIST formatted leap second data",
|
||||
)
|
||||
})?;
|
||||
let ntp_timestamp = parse::i64(start_str.as_bytes())
|
||||
.with_context(|| {
|
||||
err!("failed to parse NTP timestamp from {line:?}")
|
||||
})?;
|
||||
let timestamp = ntp_to_unix(ntp_timestamp).with_context(|| {
|
||||
err!("failed to convert NTP timestamp to Unix in {line:?}")
|
||||
})?;
|
||||
let leap_seconds = parse::i64(offset_str.as_bytes())
|
||||
.with_context(|| {
|
||||
err!("failed to parse leap second offset in {line:?}")
|
||||
})?;
|
||||
let unix = LeapSecondUnix::new(timestamp, leap_seconds)
|
||||
.with_context(|| err!("out of Jiff's range in {line:?}"))?;
|
||||
let tai = unix.to_tai()?;
|
||||
by_unix.push(unix);
|
||||
by_tai.push(tai);
|
||||
}
|
||||
}
|
||||
let Some(expires) = expires else {
|
||||
return Err(err!(
|
||||
"could not find expiration in NIST formatted leap second data"
|
||||
));
|
||||
};
|
||||
Ok(LeapSeconds { expires, by_unix, by_tai })
|
||||
}
|
||||
|
||||
fn parse_iana(string: &str) -> Result<LeapSeconds, Error> {
|
||||
let mut expires: Option<Instant> = None;
|
||||
let mut by_unix = vec![];
|
||||
let mut by_tai = vec![];
|
||||
let mut leap_seconds: i64 = 9;
|
||||
// Add a dummy line corresponding to the initial 10 second offset.
|
||||
let init = "Leap 1971 Dec 31 23:59:60 + S";
|
||||
for line in [init].into_iter().chain(string.lines()) {
|
||||
if let Some(expires_str) = line.strip_prefix("#Expires") {
|
||||
if expires.is_some() {
|
||||
return Err(err!("found multiple expiration lines"));
|
||||
}
|
||||
expires = Some(parse_iana_expires(expires_str)?);
|
||||
} else if let Some(expires_str) = line.strip_prefix("Expires") {
|
||||
if expires.is_some() {
|
||||
return Err(err!("found multiple expiration lines"));
|
||||
}
|
||||
expires = Some(parse_iana_expires(expires_str)?);
|
||||
} else if line.starts_with("#") || line.trim().is_empty() {
|
||||
continue;
|
||||
} else {
|
||||
let leap = line.strip_prefix("Leap").ok_or_else(|| {
|
||||
err!("expected 'Leap' prefix in line {line:?}")
|
||||
})?;
|
||||
let dt = if let Some((datetime_str, _)) = leap.split_once("+") {
|
||||
let dt = parse_iana_datetime(datetime_str)
|
||||
.context("failed to parse leap second")?;
|
||||
leap_seconds = leap_seconds
|
||||
.checked_add(1)
|
||||
.ok_or_else(|| err!("leap second offset is too big"))?;
|
||||
dt
|
||||
} else if let Some((datetime_str, _)) = leap.split_once("-") {
|
||||
let dt = parse_iana_datetime(datetime_str)
|
||||
.context("failed to parse leap second")?;
|
||||
leap_seconds = leap_seconds
|
||||
.checked_sub(1)
|
||||
.ok_or_else(|| err!("leap second offset is too small"))?;
|
||||
dt
|
||||
} else {
|
||||
return Err(err!(
|
||||
"expected '+' or '-' in leap second line {line:?}"
|
||||
));
|
||||
};
|
||||
let instant = TimeZone::UTC.to_instant(dt).with_context(|| {
|
||||
err!("leap second from line {line:?} is out of bounds")
|
||||
})?;
|
||||
let timestamp = instant.to_unix().0;
|
||||
let unix = LeapSecondUnix::new(timestamp, leap_seconds)
|
||||
.with_context(|| err!("out of Jiff's range in {line:?}"))?;
|
||||
let tai = unix.to_tai()?;
|
||||
by_unix.push(unix);
|
||||
by_tai.push(tai);
|
||||
}
|
||||
}
|
||||
let Some(expires) = expires else {
|
||||
return Err(err!(
|
||||
"could not find expiration in NIST formatted leap second data"
|
||||
));
|
||||
};
|
||||
Ok(LeapSeconds { expires, by_unix, by_tai })
|
||||
}
|
||||
|
||||
fn parse_iana_expires(expires_str: &str) -> Result<Instant, Error> {
|
||||
let dt = parse_iana_datetime(expires_str)
|
||||
.context("failed to parse expiration datetime")?;
|
||||
let instant = TimeZone::UTC
|
||||
.to_instant(dt)
|
||||
.context("expiration datetime out of bounds")?;
|
||||
Ok(instant)
|
||||
}
|
||||
|
||||
fn parse_iana_datetime(datetime_str: &str) -> Result<DateTime, Error> {
|
||||
let mut fields = datetime_str.trim().split_whitespace();
|
||||
let year_str = fields.next().ok_or_else(|| {
|
||||
err!("could not find year field in {datetime_str:?}")
|
||||
})?;
|
||||
let month_str = fields.next().ok_or_else(|| {
|
||||
err!("could not find month field in {datetime_str:?}")
|
||||
})?;
|
||||
let day_str = fields
|
||||
.next()
|
||||
.ok_or_else(|| err!("could not find day field in {datetime_str:?}"))?;
|
||||
let time_str = fields.next().ok_or_else(|| {
|
||||
err!("could not find time field in {datetime_str:?}")
|
||||
})?;
|
||||
|
||||
let mut time_fields = time_str.trim().split(':');
|
||||
let hour_str = time_fields
|
||||
.next()
|
||||
.ok_or_else(|| err!("could not find hour field in {time_str:?}"))?;
|
||||
let minute_str = time_fields
|
||||
.next()
|
||||
.ok_or_else(|| err!("could not find minute field in {time_str:?}"))?;
|
||||
let second_str = time_fields
|
||||
.next()
|
||||
.ok_or_else(|| err!("could not find second field in {time_str:?}"))?;
|
||||
|
||||
let year64 = parse::i64(year_str.as_bytes())
|
||||
.with_context(|| err!("failed to parse year from {year_str:?}"))?;
|
||||
let year = t::Year::try_new("year", year64)?;
|
||||
|
||||
let month = parse_iana_month(month_str)?;
|
||||
|
||||
let day64 = parse::i64(day_str.as_bytes())
|
||||
.with_context(|| err!("failed to parse day from {day_str:?}"))?;
|
||||
let day = t::Day::try_new("day", day64)?;
|
||||
|
||||
let hour64 = parse::i64(hour_str.as_bytes())
|
||||
.with_context(|| err!("failed to parse hour from {hour_str:?}"))?;
|
||||
let hour = t::Hour::try_new("hour", hour64)?;
|
||||
|
||||
let minute64 = parse::i64(minute_str.as_bytes())
|
||||
.with_context(|| err!("failed to parse minute from {minute_str:?}"))?;
|
||||
let minute = t::Minute::try_new("minute", minute64)?;
|
||||
|
||||
let mut second64 = parse::i64(second_str.as_bytes())
|
||||
.with_context(|| err!("failed to parse second from {second_str:?}"))?;
|
||||
let second = t::UtcSecond::try_new("second", second64)?;
|
||||
|
||||
let date = Date::new_ranged(year, month, day)?;
|
||||
let time = Time::new_ranged(hour, minute, second);
|
||||
Ok(DateTime::from_parts(date, time))
|
||||
}
|
||||
|
||||
fn parse_iana_month(month_str: &str) -> Result<t::Month, Error> {
|
||||
let n = match month_str {
|
||||
"Jan" => 1,
|
||||
"Feb" => 2,
|
||||
"Mar" => 3,
|
||||
"Apr" => 4,
|
||||
"May" => 5,
|
||||
"Jun" => 6,
|
||||
"Jul" => 7,
|
||||
"Aug" => 8,
|
||||
"Sep" => 9,
|
||||
"Oct" => 10,
|
||||
"Nov" => 11,
|
||||
"Dec" => 12,
|
||||
_ => return Err(err!("unrecognized month name {month_str:?}")),
|
||||
};
|
||||
Ok(t::Month::new_unchecked(n))
|
||||
}
|
||||
|
||||
fn ntp_to_instant(ntp_timestamp: i64) -> Result<Instant, Error> {
|
||||
Instant::from_unix(ntp_to_unix(ntp_timestamp)?, 0).with_context(|| {
|
||||
err!(
|
||||
"Unix time (from NTP timestamp {ntp_timestamp}) overflows \
|
||||
allowed range in Jiff",
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn ntp_to_unix(ntp_timestamp: i64) -> Result<i64, Error> {
|
||||
ntp_timestamp.checked_sub(NTP_UNIX_EPOCH_DIFFERENCE).ok_or_else(|| {
|
||||
err!(
|
||||
"overflow when converting NTP timestamp \
|
||||
{ntp_timestamp} to Unix time"
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// The leap seconds parsed from the NIST formatted file should be
|
||||
/// precisely equivalent to the leap seconds parsed from the IANA
|
||||
/// formatted file.
|
||||
#[test]
|
||||
fn equivalent() {
|
||||
let nist = LeapSeconds::from_nist_bytes(NIST).unwrap();
|
||||
let iana = LeapSeconds::from_iana_bytes(IANA).unwrap();
|
||||
assert_eq!(nist, iana);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nist() {
|
||||
insta::assert_debug_snapshot!(LeapSeconds::from_nist_bytes(NIST));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iana() {
|
||||
insta::assert_debug_snapshot!(LeapSeconds::from_iana_bytes(IANA));
|
||||
}
|
||||
}
|
||||
260
src/lib.rs
260
src/lib.rs
|
|
@ -1 +1,261 @@
|
|||
#![allow(warnings)]
|
||||
#![no_std]
|
||||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
// No clue why this thing is still unstable because it's pretty amazing. This
|
||||
// adds Cargo feature annotations to items in the rustdoc output. Which is
|
||||
// sadly hugely beneficial for this crate due to the number of features.
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
// We generally want all types to impl Debug.
|
||||
#![warn(missing_debug_implementations)]
|
||||
|
||||
// It should be possible to support other pointer widths, but this library
|
||||
// hasn't been tested nor thought about much in contexts with pointers less
|
||||
// than 32 bits.
|
||||
//
|
||||
// If you need support for 8-bit or 16-bit, please submit a bug report at
|
||||
// https://github.com/BurntSushi/jiff
|
||||
#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))]
|
||||
compile_error!("jiff currently not supported on non-{32,64}");
|
||||
|
||||
#[cfg(any(test, feature = "std"))]
|
||||
extern crate std;
|
||||
|
||||
// We don't currently support a non-alloc mode for Jiff. I'm not opposed to
|
||||
// doing it, but dynamic memory allocation is pretty heavily weaved into some
|
||||
// core parts of Jiff. In particular, its error types.
|
||||
//
|
||||
// When I originally started writing Jiff, my goal was to support a core-only
|
||||
// mode. But it became too painful to make every use of the heap conditional.
|
||||
//
|
||||
// With that said, I believe errors are the only thing that is "pervasive"
|
||||
// that allocates. That, and time zones. So if core-only was deeply desired,
|
||||
// we could probably pull the "much worse user experience" level and make it
|
||||
// happen. Alternatively, we could carve out a "jiff core" crate, although I
|
||||
// don't really know what that would look like.
|
||||
//
|
||||
// If you have a use case for a core-only Jiff, please file an issue. And
|
||||
// please don't just say, "I want Jiff without heap allocation." Please give a
|
||||
// detailed accounting of 1) why you can't use dynamic memory allocation and 2)
|
||||
// what specific functionality from Jiff you actually need.
|
||||
extern crate alloc;
|
||||
|
||||
pub use crate::{
|
||||
error::Error,
|
||||
instant::{Instant, Tai, TimeScale, Unix},
|
||||
span::{Span, ToSpan},
|
||||
tz::TimeZone,
|
||||
zoned::Zoned,
|
||||
};
|
||||
|
||||
#[macro_use]
|
||||
mod logging;
|
||||
|
||||
pub mod civil;
|
||||
mod error;
|
||||
pub mod format;
|
||||
mod instant;
|
||||
mod leapseconds;
|
||||
pub mod round;
|
||||
mod scale;
|
||||
pub mod span;
|
||||
pub mod tz;
|
||||
mod util;
|
||||
mod zoned;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::SystemTime;
|
||||
|
||||
use crate::{civil::Date, round::Unit, util::t};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn topscratch() {
|
||||
let _ = env_logger::try_init();
|
||||
// std::dbg!(t::SpanMonths::MIN, t::SpanMonths::MAX);
|
||||
// std::dbg!(t::SpanWeeks::MIN, t::SpanWeeks::MAX);
|
||||
// std::dbg!(t::SpanDays::MIN, t::SpanDays::MAX);
|
||||
// std::dbg!(t::SpanHours::MIN, t::SpanHours::MAX);
|
||||
// std::dbg!(t::SpanMinutes::MIN, t::SpanMinutes::MAX);
|
||||
// std::dbg!(t::SpanSeconds::MIN, t::SpanSeconds::MAX);
|
||||
// std::dbg!(t::SpanNanoseconds::MIN, t::SpanNanoseconds::MAX);
|
||||
// std::dbg!(t::UnixSeconds::MIN, t::UnixSeconds::MAX);
|
||||
|
||||
// let tzname = "America/New_York";
|
||||
//
|
||||
// let dt = civil::DateTime::constant(2024, 3, 10, 2, 30, 0, 0);
|
||||
// let inst: Zoned = dt.to_zoned(tzname).unwrap();
|
||||
// let start = inst.start_of_day().unwrap();
|
||||
// let end = start.checked_add(1.day()).unwrap();
|
||||
// std::dbg!(start.to_instant().until(end.to_instant()));
|
||||
//
|
||||
// let dt = civil::DateTime::constant(2024, 11, 3, 2, 30, 0, 0);
|
||||
// let inst: Zoned = dt.to_zoned(tzname).unwrap();
|
||||
// let start = inst.start_of_day().unwrap();
|
||||
// let end = start.checked_add(1.day()).unwrap();
|
||||
// std::dbg!(start.to_instant().until(end.to_instant()));
|
||||
|
||||
// let dt = civil::DateTime::constant(-9999, 1, 2, 1, 59, 59, 0);
|
||||
// let inst: Zoned =
|
||||
// dt.to_zoned_with(TimeZone::fixed(tz::Offset::UTC)).unwrap();
|
||||
|
||||
// let dt = civil::DateTime::constant(2024, 3, 9, 2, 30, 0, 0);
|
||||
// let inst: Zoned = dt.to_zoned(tzname).unwrap();
|
||||
// let later = inst.checked_add(1.day()).unwrap();
|
||||
// // let later = inst.checked_add(24.hours()).unwrap();
|
||||
// std::dbg!(inst.to_datetime());
|
||||
// std::dbg!(later.to_datetime());
|
||||
|
||||
// let dt = civil::DateTime::constant(2024, 11, 2, 1, 30, 0, 0);
|
||||
// let inst: Zoned = dt.to_zoned(tzname).unwrap();
|
||||
// let later = inst.checked_add(1.day()).unwrap();
|
||||
// // let later = inst.checked_add(24.hours()).unwrap();
|
||||
// std::dbg!(inst.to_datetime());
|
||||
// std::dbg!(later.to_datetime());
|
||||
// std::dbg!(later.time_zone().to_offset(later.to_instant()));
|
||||
|
||||
// let tzname = "America/Los_Angeles";
|
||||
// let tzdb = tz::TimeZoneDatabase::from_env();
|
||||
// let tz = tzdb.get(tzname).unwrap();
|
||||
|
||||
// let dt = civil::DateTime::constant(2015, 06, 30, 23, 59, 60, 0);
|
||||
// let unix: Instant = Instant::from_datetime_zulu(dt).unwrap();
|
||||
// let tai: Instant<Tai> = Instant::from_datetime_zulu(dt).unwrap();
|
||||
// std::dbg!(unix.to_datetime());
|
||||
// std::dbg!(tai.to_datetime());
|
||||
|
||||
// let unixz = unix.to_zoned(tzname).unwrap();
|
||||
// let taiz = tai.to_zoned(tzname).unwrap();
|
||||
// let unixz = Zoned::new(unix, TimeZone::UTC);
|
||||
// let taiz = Zoned::new(tai, TimeZone::UTC);
|
||||
// std::dbg!(unixz.to_datetime());
|
||||
// std::dbg!(taiz.to_datetime());
|
||||
|
||||
// let now = Zoned::new(Instant::now(), tz);
|
||||
// std::dbg!(now.to_datetime());
|
||||
// let naive_dt = NaiveDateTime::new(date, time);
|
||||
// let dt = TIMEZONE.from_local_datetime(&naive_dt).single().unwrap();
|
||||
// // The timezone is EST and the DST offset is zero
|
||||
// assert_timezone_and_offset(&dt, "EST", 0);
|
||||
|
||||
// let dt = civil::DateTime::constant(2015, 06, 30, 23, 59, 59, 0);
|
||||
// let unix: Instant = Instant::from_datetime_zulu(dt).unwrap();
|
||||
// let tai: Instant<Tai> = Instant::from_datetime_zulu(dt).unwrap();
|
||||
// std::dbg!(dt, unix.second(), tai.second(), tai.to_datetime(), "-----");
|
||||
//
|
||||
// let dt = civil::DateTime::constant(2015, 06, 30, 23, 59, 60, 0);
|
||||
// let unix: Instant = Instant::from_datetime_zulu(dt).unwrap();
|
||||
// let tai: Instant<Tai> = Instant::from_datetime_zulu(dt).unwrap();
|
||||
// std::dbg!(dt, unix.second(), tai.second(), tai.to_datetime(), "-----");
|
||||
//
|
||||
// let dt = civil::DateTime::constant(2015, 7, 1, 0, 0, 0, 0);
|
||||
// let unix: Instant = Instant::from_datetime_zulu(dt).unwrap();
|
||||
// let tai: Instant<Tai> = Instant::from_datetime_zulu(dt).unwrap();
|
||||
// std::dbg!(dt, unix.second(), tai.second(), tai.to_datetime(), "-----");
|
||||
//
|
||||
// let dt = civil::DateTime::constant(2015, 7, 1, 0, 0, 1, 0);
|
||||
// let unix: Instant = Instant::from_datetime_zulu(dt).unwrap();
|
||||
// let tai: Instant<Tai> = Instant::from_datetime_zulu(dt).unwrap();
|
||||
// std::dbg!(dt, unix.second(), tai.second(), tai.to_datetime(), "-----");
|
||||
|
||||
// let dt1 = civil::DateTime::constant(2015, 06, 30, 23, 59, 59, 0);
|
||||
// let unix1: Instant = Instant::from_datetime_zulu(dt1).unwrap();
|
||||
// let tai1: Instant<Tai> = Instant::from_datetime_zulu(dt1).unwrap();
|
||||
//
|
||||
// let dt2 = civil::DateTime::constant(2015, 7, 1, 0, 0, 0, 0);
|
||||
// let unix2: Instant = Instant::from_datetime_zulu(dt2).unwrap();
|
||||
// let tai2: Instant<Tai> = Instant::from_datetime_zulu(dt2).unwrap();
|
||||
//
|
||||
// std::dbg!(dt2.since(dt1).get_seconds());
|
||||
// std::dbg!(unix2.since(unix1).get_seconds());
|
||||
// std::dbg!(tai2.since(tai1).get_seconds());
|
||||
|
||||
// let dt = civil::DateTime::constant(2016, 12, 31, 23, 59, 59, 0);
|
||||
// let inst: Instant = Instant::from_datetime_zulu(dt).unwrap();
|
||||
// std::dbg!(dt, inst);
|
||||
//
|
||||
// let dt = civil::DateTime::constant(2016, 12, 31, 23, 59, 60, 0);
|
||||
// let inst: Instant = Instant::from_datetime_zulu(dt).unwrap();
|
||||
// std::dbg!(dt, inst);
|
||||
//
|
||||
// let dt = civil::DateTime::constant(2017, 1, 1, 0, 0, 0, 0);
|
||||
// let inst: Instant = Instant::from_datetime_zulu(dt).unwrap();
|
||||
// std::dbg!(dt, inst);
|
||||
|
||||
// let dt1: Zoned = civil::DateTime::constant(2014, 3, 15, 19, 0, 0, 0)
|
||||
// .to_zoned("America/New_York")
|
||||
// .unwrap();
|
||||
// let dt2: Zoned = civil::DateTime::constant(2016, 3, 15, 19, 0, 0, 0)
|
||||
// .to_zoned("America/New_York")
|
||||
// .unwrap();
|
||||
// let span = dt1.until_with_largest_unit(Unit::Hour, &dt2).unwrap();
|
||||
// std::eprintln!("{span:?}");
|
||||
//
|
||||
// let dt1: Zoned<Tai> =
|
||||
// civil::DateTime::constant(2014, 3, 15, 19, 0, 0, 0)
|
||||
// .to_zoned("America/New_York")
|
||||
// .unwrap();
|
||||
// let dt2: Zoned<Tai> =
|
||||
// civil::DateTime::constant(2016, 3, 15, 19, 0, 0, 0)
|
||||
// .to_zoned("America/New_York")
|
||||
// .unwrap();
|
||||
// let span = dt1.until_with_largest_unit(Unit::Hour, &dt2).unwrap();
|
||||
// std::eprintln!("{span:?}");
|
||||
|
||||
{
|
||||
use crate::format::temporal::{
|
||||
DateTimeParser, Disambiguation, ResolveOffsetConflict,
|
||||
};
|
||||
|
||||
// let x = "2020-01-01T12:00-02:00[America/Sao_Paulo]";
|
||||
// let x = "2024-03-10T02:30[America/New_York]";
|
||||
let x = "2024-11-03T01:30-05[America/New_York]";
|
||||
let parsed = DateTimeParser::new()
|
||||
.parse_temporal_datetime(x.as_bytes())
|
||||
.unwrap()
|
||||
.into_full()
|
||||
.unwrap();
|
||||
let result: Result<Zoned, crate::Error> = parsed.to_zoned(
|
||||
crate::tz::db(),
|
||||
ResolveOffsetConflict::Reject,
|
||||
Disambiguation::Reject,
|
||||
);
|
||||
match result {
|
||||
Ok(zdt) => {
|
||||
std::eprintln!("{}", zdt);
|
||||
}
|
||||
Err(err) => {
|
||||
std::eprintln!("{}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
{
|
||||
use crate::format::temporal::{
|
||||
DateTimeParser, Disambiguation, ResolveOffsetConflict,
|
||||
};
|
||||
|
||||
let x = "2024-11-03T01:30-05:00[America/New_York]";
|
||||
let parsed = DateTimeParser::new()
|
||||
.parse_temporal_datetime(x.as_bytes())
|
||||
.unwrap()
|
||||
.into_full()
|
||||
.unwrap();
|
||||
let result: Result<Zoned, crate::Error> = parsed.to_zoned(
|
||||
crate::tz::db(),
|
||||
ResolveOffsetConflict::Reject,
|
||||
Disambiguation::Compatible,
|
||||
);
|
||||
match result {
|
||||
Ok(zdt) => {
|
||||
std::eprintln!("{}", zdt);
|
||||
}
|
||||
Err(err) => {
|
||||
std::eprintln!("{}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
|||
63
src/logging.rs
Normal file
63
src/logging.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// Some feature combinations result in some of these macros never being used.
|
||||
// Which is fine. Just squash the warnings.
|
||||
#![allow(unused_macros)]
|
||||
|
||||
macro_rules! log {
|
||||
($($tt:tt)*) => {
|
||||
#[cfg(feature = "logging")]
|
||||
{
|
||||
$($tt)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! error {
|
||||
($($tt:tt)*) => { log!(log::error!($($tt)*)) }
|
||||
}
|
||||
|
||||
macro_rules! warn {
|
||||
($($tt:tt)*) => { log!(log::warn!($($tt)*)) }
|
||||
}
|
||||
|
||||
macro_rules! info {
|
||||
($($tt:tt)*) => { log!(log::info!($($tt)*)) }
|
||||
}
|
||||
|
||||
macro_rules! debug {
|
||||
($($tt:tt)*) => { log!(log::debug!($($tt)*)) }
|
||||
}
|
||||
|
||||
macro_rules! trace {
|
||||
($($tt:tt)*) => { log!(log::trace!($($tt)*)) }
|
||||
}
|
||||
|
||||
/// A copy of std's `dbg!` macro that doesn't do pretty printing.
|
||||
///
|
||||
/// This is nice because we usually want more compact output in this crate.
|
||||
/// Also, because we don't import std's prelude, we have to use `std::dbg!`.
|
||||
/// This macro definition makes it available as `dbg!`.
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_export]
|
||||
macro_rules! dbg {
|
||||
() => {
|
||||
std::eprintln!("[{}:{}:{}]", $crate::file!(), $crate::line!(), $crate::column!())
|
||||
};
|
||||
($val:expr $(,)?) => {
|
||||
match $val {
|
||||
tmp => {
|
||||
std::eprintln!(
|
||||
"[{}:{}:{}] {} = {:?}",
|
||||
$crate::file!(),
|
||||
$crate::line!(),
|
||||
$crate::column!(),
|
||||
$crate::stringify!($val),
|
||||
&tmp,
|
||||
);
|
||||
tmp
|
||||
}
|
||||
}
|
||||
};
|
||||
($($val:expr),+ $(,)?) => {
|
||||
($($crate::dbg!($val)),+,)
|
||||
};
|
||||
}
|
||||
1521
src/round.rs
Normal file
1521
src/round.rs
Normal file
File diff suppressed because it is too large
Load diff
107
src/scale.rs
Normal file
107
src/scale.rs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
use core::{
|
||||
fmt::Debug,
|
||||
ops::{Add, Div, Mul, Rem, Sub},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
util::{
|
||||
rangeint::{ri64, RInto, RangedDebug, TryRFrom},
|
||||
t::{
|
||||
FractionalNanosecond, SpanSeconds, SubsecNanosecond, TaiSeconds,
|
||||
UnixSeconds,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
pub trait TimeScale: TimeScaleInternal {}
|
||||
impl<S: TimeScaleInternal> TimeScale for S {}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct Unix;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct Tai;
|
||||
|
||||
pub(crate) trait TimeScaleInternal: Clone + Copy {
|
||||
type Seconds: Seconds;
|
||||
|
||||
fn name() -> &'static str;
|
||||
|
||||
fn from_unix_timestamp(
|
||||
unix_second: UnixSeconds,
|
||||
) -> Result<Self::Seconds, Error>;
|
||||
|
||||
fn to_unix_timestamp(scale_second: Self::Seconds) -> UnixSeconds;
|
||||
}
|
||||
|
||||
pub(crate) trait Seconds:
|
||||
Copy
|
||||
+ Clone
|
||||
+ Debug
|
||||
+ Eq
|
||||
+ PartialEq
|
||||
+ PartialOrd
|
||||
+ Ord
|
||||
+ Add
|
||||
+ Sub
|
||||
+ Mul
|
||||
+ Div
|
||||
+ Rem
|
||||
{
|
||||
fn new(val: i64) -> Option<Self>;
|
||||
|
||||
fn from_span_seconds(val: SpanSeconds) -> Self;
|
||||
|
||||
fn try_from_span_seconds(val: SpanSeconds) -> Result<Self, Error>;
|
||||
|
||||
fn to_span_seconds(self) -> SpanSeconds;
|
||||
|
||||
fn get(self) -> i64;
|
||||
}
|
||||
|
||||
/*
|
||||
impl TimeScaleInternal for super::Unix {
|
||||
type Seconds = UnixSeconds;
|
||||
|
||||
fn name() -> &'static str {
|
||||
"UNIX"
|
||||
}
|
||||
|
||||
fn from_unix_time(
|
||||
unix_time_seconds: UnixSeconds,
|
||||
unix_time_nanos: FractionalNanosecond,
|
||||
) -> Result<(UnixSeconds, FractionalNanosecond), Error> {
|
||||
Ok((unix_time_seconds, unix_time_nanos))
|
||||
}
|
||||
|
||||
fn to_unix_time(
|
||||
scale_time_seconds: UnixSeconds,
|
||||
scale_time_nanos: FractionalNanosecond,
|
||||
) -> (UnixSeconds, FractionalNanosecond) {
|
||||
(scale_time_seconds, scale_time_nanos)
|
||||
}
|
||||
}
|
||||
|
||||
impl Seconds for UnixSeconds {
|
||||
fn new(val: i64) -> Option<Self> {
|
||||
UnixSeconds::new(val)
|
||||
}
|
||||
|
||||
fn from_span_seconds(val: SpanSeconds) -> Self {
|
||||
val.rinto()
|
||||
}
|
||||
|
||||
fn try_from_span_seconds(val: SpanSeconds) -> Result<Self, Error> {
|
||||
Self::try_rfrom("instant-seconds", val)
|
||||
}
|
||||
|
||||
fn to_span_seconds(self) -> SpanSeconds {
|
||||
self.rinto()
|
||||
}
|
||||
|
||||
fn get(self) -> i64 {
|
||||
UnixSeconds::get(self)
|
||||
}
|
||||
}
|
||||
*/
|
||||
241
src/snapshots/jiff__leapseconds__tests__iana.snap
Normal file
241
src/snapshots/jiff__leapseconds__tests__iana.snap
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
---
|
||||
source: src/leapseconds.rs
|
||||
expression: "LeapSeconds::from_iana_bytes(IANA)"
|
||||
---
|
||||
Ok(
|
||||
LeapSeconds {
|
||||
expires: Instant {
|
||||
scale: "UNIX",
|
||||
second: 1719532800,
|
||||
nanosecond: 0,
|
||||
},
|
||||
by_unix: [
|
||||
LeapSecondUnix {
|
||||
timestamp: 63072000,
|
||||
leap_seconds: 10,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 78796800,
|
||||
leap_seconds: 11,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 94694400,
|
||||
leap_seconds: 12,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 126230400,
|
||||
leap_seconds: 13,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 157766400,
|
||||
leap_seconds: 14,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 189302400,
|
||||
leap_seconds: 15,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 220924800,
|
||||
leap_seconds: 16,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 252460800,
|
||||
leap_seconds: 17,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 283996800,
|
||||
leap_seconds: 18,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 315532800,
|
||||
leap_seconds: 19,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 362793600,
|
||||
leap_seconds: 20,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 394329600,
|
||||
leap_seconds: 21,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 425865600,
|
||||
leap_seconds: 22,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 489024000,
|
||||
leap_seconds: 23,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 567993600,
|
||||
leap_seconds: 24,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 631152000,
|
||||
leap_seconds: 25,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 662688000,
|
||||
leap_seconds: 26,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 709948800,
|
||||
leap_seconds: 27,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 741484800,
|
||||
leap_seconds: 28,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 773020800,
|
||||
leap_seconds: 29,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 820454400,
|
||||
leap_seconds: 30,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 867715200,
|
||||
leap_seconds: 31,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 915148800,
|
||||
leap_seconds: 32,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 1136073600,
|
||||
leap_seconds: 33,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 1230768000,
|
||||
leap_seconds: 34,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 1341100800,
|
||||
leap_seconds: 35,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 1435708800,
|
||||
leap_seconds: 36,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 1483228800,
|
||||
leap_seconds: 37,
|
||||
},
|
||||
],
|
||||
by_tai: [
|
||||
LeapSecondTai {
|
||||
timestamp: 63072010,
|
||||
leap_seconds: -10,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 78796811,
|
||||
leap_seconds: -11,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 94694412,
|
||||
leap_seconds: -12,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 126230413,
|
||||
leap_seconds: -13,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 157766414,
|
||||
leap_seconds: -14,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 189302415,
|
||||
leap_seconds: -15,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 220924816,
|
||||
leap_seconds: -16,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 252460817,
|
||||
leap_seconds: -17,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 283996818,
|
||||
leap_seconds: -18,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 315532819,
|
||||
leap_seconds: -19,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 362793620,
|
||||
leap_seconds: -20,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 394329621,
|
||||
leap_seconds: -21,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 425865622,
|
||||
leap_seconds: -22,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 489024023,
|
||||
leap_seconds: -23,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 567993624,
|
||||
leap_seconds: -24,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 631152025,
|
||||
leap_seconds: -25,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 662688026,
|
||||
leap_seconds: -26,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 709948827,
|
||||
leap_seconds: -27,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 741484828,
|
||||
leap_seconds: -28,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 773020829,
|
||||
leap_seconds: -29,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 820454430,
|
||||
leap_seconds: -30,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 867715231,
|
||||
leap_seconds: -31,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 915148832,
|
||||
leap_seconds: -32,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 1136073633,
|
||||
leap_seconds: -33,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 1230768034,
|
||||
leap_seconds: -34,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 1341100835,
|
||||
leap_seconds: -35,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 1435708836,
|
||||
leap_seconds: -36,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 1483228837,
|
||||
leap_seconds: -37,
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
241
src/snapshots/jiff__leapseconds__tests__nist.snap
Normal file
241
src/snapshots/jiff__leapseconds__tests__nist.snap
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
---
|
||||
source: src/leapseconds.rs
|
||||
expression: "LeapSeconds::from_nist_bytes(NIST)"
|
||||
---
|
||||
Ok(
|
||||
LeapSeconds {
|
||||
expires: Instant {
|
||||
scale: "UNIX",
|
||||
second: 1719532800,
|
||||
nanosecond: 0,
|
||||
},
|
||||
by_unix: [
|
||||
LeapSecondUnix {
|
||||
timestamp: 63072000,
|
||||
leap_seconds: 10,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 78796800,
|
||||
leap_seconds: 11,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 94694400,
|
||||
leap_seconds: 12,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 126230400,
|
||||
leap_seconds: 13,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 157766400,
|
||||
leap_seconds: 14,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 189302400,
|
||||
leap_seconds: 15,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 220924800,
|
||||
leap_seconds: 16,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 252460800,
|
||||
leap_seconds: 17,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 283996800,
|
||||
leap_seconds: 18,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 315532800,
|
||||
leap_seconds: 19,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 362793600,
|
||||
leap_seconds: 20,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 394329600,
|
||||
leap_seconds: 21,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 425865600,
|
||||
leap_seconds: 22,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 489024000,
|
||||
leap_seconds: 23,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 567993600,
|
||||
leap_seconds: 24,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 631152000,
|
||||
leap_seconds: 25,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 662688000,
|
||||
leap_seconds: 26,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 709948800,
|
||||
leap_seconds: 27,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 741484800,
|
||||
leap_seconds: 28,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 773020800,
|
||||
leap_seconds: 29,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 820454400,
|
||||
leap_seconds: 30,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 867715200,
|
||||
leap_seconds: 31,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 915148800,
|
||||
leap_seconds: 32,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 1136073600,
|
||||
leap_seconds: 33,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 1230768000,
|
||||
leap_seconds: 34,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 1341100800,
|
||||
leap_seconds: 35,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 1435708800,
|
||||
leap_seconds: 36,
|
||||
},
|
||||
LeapSecondUnix {
|
||||
timestamp: 1483228800,
|
||||
leap_seconds: 37,
|
||||
},
|
||||
],
|
||||
by_tai: [
|
||||
LeapSecondTai {
|
||||
timestamp: 63072010,
|
||||
leap_seconds: -10,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 78796811,
|
||||
leap_seconds: -11,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 94694412,
|
||||
leap_seconds: -12,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 126230413,
|
||||
leap_seconds: -13,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 157766414,
|
||||
leap_seconds: -14,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 189302415,
|
||||
leap_seconds: -15,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 220924816,
|
||||
leap_seconds: -16,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 252460817,
|
||||
leap_seconds: -17,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 283996818,
|
||||
leap_seconds: -18,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 315532819,
|
||||
leap_seconds: -19,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 362793620,
|
||||
leap_seconds: -20,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 394329621,
|
||||
leap_seconds: -21,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 425865622,
|
||||
leap_seconds: -22,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 489024023,
|
||||
leap_seconds: -23,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 567993624,
|
||||
leap_seconds: -24,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 631152025,
|
||||
leap_seconds: -25,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 662688026,
|
||||
leap_seconds: -26,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 709948827,
|
||||
leap_seconds: -27,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 741484828,
|
||||
leap_seconds: -28,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 773020829,
|
||||
leap_seconds: -29,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 820454430,
|
||||
leap_seconds: -30,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 867715231,
|
||||
leap_seconds: -31,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 915148832,
|
||||
leap_seconds: -32,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 1136073633,
|
||||
leap_seconds: -33,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 1230768034,
|
||||
leap_seconds: -34,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 1341100835,
|
||||
leap_seconds: -35,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 1435708836,
|
||||
leap_seconds: -36,
|
||||
},
|
||||
LeapSecondTai {
|
||||
timestamp: 1483228837,
|
||||
leap_seconds: -37,
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
863
src/span/duration.rs
Normal file
863
src/span/duration.rs
Normal file
|
|
@ -0,0 +1,863 @@
|
|||
use core::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign};
|
||||
|
||||
use crate::{
|
||||
civil,
|
||||
error::Error,
|
||||
span::Span,
|
||||
util::{
|
||||
rangeint::{RFrom, RInto, TryRFrom},
|
||||
t::{self, NoUnits128, C},
|
||||
},
|
||||
};
|
||||
|
||||
/// Represents a duration in time in units of seconds with a fractional
|
||||
/// nanosecond part.
|
||||
///
|
||||
/// The range of seconds is big enough to represent all possible spans in the
|
||||
/// range `UnixSeconds::MIN..=UnixSeconds::MAX`. That is, it can represent any
|
||||
/// span of time with the allowed range of representable times supported by
|
||||
/// this library. (It can technically represent up to `999_999_999` nanoseconds
|
||||
/// outside of both the minimum and maximum.)
|
||||
///
|
||||
/// # Construction
|
||||
///
|
||||
/// Typically construction is done via [`Span::time_parts_to_duration`].
|
||||
///
|
||||
/// # Comparison with `std::time::Duration`
|
||||
///
|
||||
/// The main operational difference is that this duration can be negative,
|
||||
/// where as the standard library duration is always positive. Otherwise, this
|
||||
/// duration is clamped to the specific range of seconds supported by this
|
||||
/// library, and supports a wider variety of operations tailored to this
|
||||
/// datetime library.
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) struct TimeDuration {
|
||||
seconds: t::SpanSeconds,
|
||||
nanoseconds: t::FractionalNanosecond,
|
||||
}
|
||||
|
||||
impl TimeDuration {
|
||||
/// The minimum possible time duration.
|
||||
pub(crate) const MIN: TimeDuration = TimeDuration {
|
||||
seconds: t::SpanSeconds::MIN_SELF,
|
||||
nanoseconds: t::FractionalNanosecond::MIN_SELF,
|
||||
};
|
||||
|
||||
/// The maximum possible time duration.
|
||||
pub(crate) const MAX: TimeDuration = TimeDuration {
|
||||
seconds: t::SpanSeconds::MAX_SELF,
|
||||
nanoseconds: t::FractionalNanosecond::MAX_SELF,
|
||||
};
|
||||
|
||||
/// The zero duration.
|
||||
pub(crate) const ZERO: TimeDuration = TimeDuration {
|
||||
seconds: t::SpanSeconds::N::<0>(),
|
||||
nanoseconds: t::FractionalNanosecond::N::<0>(),
|
||||
};
|
||||
|
||||
/// A duration corresponding to a single civil day. i.e., 86,400 seconds.
|
||||
pub(crate) const CIVIL_DAY: TimeDuration = TimeDuration {
|
||||
seconds: t::SpanSeconds::N::<86_400>(),
|
||||
nanoseconds: t::FractionalNanosecond::N::<0>(),
|
||||
};
|
||||
|
||||
/// Create a new duration from the given number of seconds.
|
||||
#[inline]
|
||||
pub(crate) fn new(
|
||||
seconds: impl RInto<t::SpanSeconds>,
|
||||
nanoseconds: impl RInto<t::FractionalNanosecond>,
|
||||
) -> TimeDuration {
|
||||
let seconds = seconds.rinto();
|
||||
let nanoseconds = nanoseconds.rinto();
|
||||
if seconds.signum() == nanoseconds.signum()
|
||||
|| seconds == 0
|
||||
|| nanoseconds == 0
|
||||
{
|
||||
return TimeDuration { seconds, nanoseconds };
|
||||
}
|
||||
let seconds = seconds.without_bounds();
|
||||
let nanoseconds = nanoseconds.without_bounds();
|
||||
let [delta_seconds, delta_nanos] = t::NoUnits::vary_many(
|
||||
[seconds, nanoseconds],
|
||||
|[seconds, nanoseconds]| {
|
||||
if seconds < 0 && nanoseconds > 0 {
|
||||
[C(1), (-t::NANOS_PER_SECOND).rinto()]
|
||||
} else if seconds > 0 && nanoseconds < 0 {
|
||||
[C(-1), t::NANOS_PER_SECOND.rinto()]
|
||||
} else {
|
||||
[C(0), C(0)]
|
||||
}
|
||||
},
|
||||
);
|
||||
TimeDuration {
|
||||
seconds: (seconds + delta_seconds).rinto(),
|
||||
nanoseconds: (nanoseconds + delta_nanos).rinto(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new duration from primitive values.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This returns an error when either `seconds` exceeds the maximum span
|
||||
/// of seconds allowed, or if `nanoseconds` is not in the range
|
||||
/// `-999_999_999..=999_999_999`.
|
||||
#[inline]
|
||||
pub(crate) fn try_new(
|
||||
seconds: i64,
|
||||
nanoseconds: i32,
|
||||
) -> Result<TimeDuration, Error> {
|
||||
let seconds = t::SpanSeconds::try_new("seconds", seconds)?;
|
||||
let nanoseconds =
|
||||
t::FractionalNanosecond::try_new("nanoseconds", nanoseconds)?;
|
||||
Ok(TimeDuration::new(seconds, nanoseconds))
|
||||
}
|
||||
|
||||
/// Returns *only* the time parts of the given [`Span`] as a
|
||||
/// [`TimeDuration`].
|
||||
///
|
||||
/// That is, the `years`, `months`, `weeks` and `days` fields on a span are
|
||||
/// ignored.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This returns an error if this span exceeds what can be represented
|
||||
/// in a `SpanSeconds`.
|
||||
#[inline]
|
||||
pub(crate) fn from_span(span: &Span) -> Result<TimeDuration, Error> {
|
||||
let hours = t::SpanSeconds::rfrom(span.get_hours_ranged());
|
||||
let minutes = span.get_minutes_ranged();
|
||||
let mut seconds: t::SpanSeconds = (hours * t::SECONDS_PER_HOUR)
|
||||
.try_checked_add(
|
||||
"minutes-to-seconds",
|
||||
minutes * t::SECONDS_PER_MINUTE,
|
||||
)?
|
||||
.try_checked_add("seconds", span.get_seconds_ranged())?;
|
||||
let milliseconds = span.get_milliseconds_ranged();
|
||||
seconds = seconds.try_checked_add(
|
||||
"milliseconds-to-seconds",
|
||||
milliseconds.div_ceil(t::MILLIS_PER_SECOND),
|
||||
)?;
|
||||
let microseconds = span.get_microseconds_ranged();
|
||||
seconds = seconds.try_checked_add(
|
||||
"microseconds-to-seconds",
|
||||
microseconds.div_ceil(t::MICROS_PER_SECOND),
|
||||
)?;
|
||||
let nanoseconds = span.get_nanoseconds_ranged();
|
||||
seconds = seconds.try_checked_add(
|
||||
"nanoseconds-to-seconds",
|
||||
nanoseconds.div_ceil(t::NANOS_PER_SECOND),
|
||||
)?;
|
||||
|
||||
let mut fractional_nanoseconds = t::FractionalNanosecond::rfrom(
|
||||
nanoseconds.rem_ceil(t::NANOS_PER_SECOND),
|
||||
);
|
||||
fractional_nanoseconds +=
|
||||
t::NANOS_PER_MICRO * microseconds.rem_ceil(t::MICROS_PER_SECOND);
|
||||
fractional_nanoseconds +=
|
||||
t::NANOS_PER_MILLI * milliseconds.rem_ceil(t::MILLIS_PER_SECOND);
|
||||
seconds += fractional_nanoseconds.div_ceil(t::NANOS_PER_SECOND);
|
||||
fractional_nanoseconds =
|
||||
fractional_nanoseconds.rem_ceil(t::NANOS_PER_SECOND);
|
||||
Ok(TimeDuration::new(seconds, fractional_nanoseconds))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from_nanoseconds(
|
||||
nanoseconds: NoUnits128,
|
||||
) -> Result<TimeDuration, Error> {
|
||||
let seconds = t::SpanSeconds::try_rfrom(
|
||||
"duration-as-nanoseconds",
|
||||
nanoseconds.div_ceil(t::NANOS_PER_SECOND),
|
||||
)?;
|
||||
let nanoseconds = nanoseconds.rem_ceil(t::NANOS_PER_SECOND);
|
||||
Ok(TimeDuration::new(seconds, nanoseconds))
|
||||
}
|
||||
|
||||
/// Return a new duration with the number of seconds set to the given
|
||||
/// value. The nanoseconds remain the same as in `self`.
|
||||
#[inline]
|
||||
pub(crate) fn with_seconds(
|
||||
self,
|
||||
seconds: impl RInto<t::SpanSeconds>,
|
||||
) -> TimeDuration {
|
||||
TimeDuration::new(seconds, self.nanoseconds)
|
||||
}
|
||||
|
||||
/// Return a new duration with the number of nanoseconds set to the given
|
||||
/// value. The seconds remain the same as in `self`.
|
||||
#[inline]
|
||||
pub(crate) fn with_nanos(
|
||||
self,
|
||||
nanoseconds: impl RInto<t::FractionalNanosecond>,
|
||||
) -> TimeDuration {
|
||||
TimeDuration::new(self.seconds, nanoseconds)
|
||||
}
|
||||
|
||||
/// Negate this duration.
|
||||
///
|
||||
/// If it was negative, then this will make the duration positive. If it
|
||||
/// was positive, then this wil make the duration negative. If the duration
|
||||
/// is `0`, then this is a no-op.
|
||||
#[inline]
|
||||
pub(crate) fn negate(self) -> TimeDuration {
|
||||
TimeDuration { seconds: -self.seconds, nanoseconds: -self.nanoseconds }
|
||||
}
|
||||
|
||||
/// Returns the absolute value of this duration.
|
||||
///
|
||||
/// If the duration was negative, and then this returns the same duration
|
||||
/// but with the sign flipped to positive. If the duration was positive,
|
||||
/// then this returns the duration as is.
|
||||
#[inline]
|
||||
pub(crate) fn abs(self) -> TimeDuration {
|
||||
TimeDuration {
|
||||
seconds: self.seconds.abs(),
|
||||
nanoseconds: self.nanoseconds.abs(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert this duration into a `Span`.
|
||||
#[inline]
|
||||
pub(crate) fn to_span(self) -> Span {
|
||||
Span::new()
|
||||
.seconds_ranged(self.seconds())
|
||||
.nanoseconds_ranged(self.nanoseconds())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_nanoseconds(self) -> NoUnits128 {
|
||||
let seconds = NoUnits128::rfrom(self.seconds());
|
||||
let nanoseconds = NoUnits128::rfrom(self.nanoseconds());
|
||||
seconds * t::NANOS_PER_SECOND + nanoseconds
|
||||
}
|
||||
|
||||
/// Return the primitive second and nanosecond components of this duration.
|
||||
#[inline]
|
||||
pub(crate) fn to_parts(self) -> (i64, i32) {
|
||||
(self.seconds.get(), self.nanoseconds.get())
|
||||
}
|
||||
|
||||
/// Return the ranged second and nanosecond components of this duration.
|
||||
#[inline]
|
||||
pub(crate) fn to_parts_ranged(
|
||||
self,
|
||||
) -> (t::SpanSeconds, t::FractionalNanosecond) {
|
||||
(self.seconds, self.nanoseconds)
|
||||
}
|
||||
|
||||
/// Returns the number of seconds in this duration.
|
||||
#[inline]
|
||||
pub(crate) fn seconds(self) -> t::SpanSeconds {
|
||||
self.seconds
|
||||
}
|
||||
|
||||
/// Returns the number of nanoseconds in this duration.
|
||||
///
|
||||
/// As the return type indicates, the number of nanoseconds is always less
|
||||
/// than 1 second.
|
||||
#[inline]
|
||||
pub(crate) fn nanoseconds(self) -> t::FractionalNanosecond {
|
||||
self.nanoseconds
|
||||
}
|
||||
|
||||
/// Return the sign of this duration.
|
||||
#[inline]
|
||||
pub(crate) fn signum(self) -> t::Sign {
|
||||
let seconds = self.seconds().without_bounds();
|
||||
let nanoseconds = self.nanoseconds().without_bounds();
|
||||
let [signum] = t::NoUnits::vary_many(
|
||||
[seconds, nanoseconds],
|
||||
|[seconds, nanoseconds]| {
|
||||
if seconds != 0 {
|
||||
[seconds.signum()]
|
||||
} else {
|
||||
[nanoseconds.signum()]
|
||||
}
|
||||
},
|
||||
);
|
||||
signum.rinto()
|
||||
}
|
||||
|
||||
/// Returns true if this duration is precisely equal to zero.
|
||||
#[inline]
|
||||
pub(crate) fn is_zero(self) -> bool {
|
||||
self.seconds() == 0 && self.nanoseconds() == 0
|
||||
}
|
||||
|
||||
/// Adds the given right-hand-side duration to this one.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the addition of two durations would represent a bigger span of time
|
||||
/// than what is supported by this library, then an error is returned.
|
||||
#[inline]
|
||||
pub(crate) fn checked_add(
|
||||
self,
|
||||
rhs: TimeDuration,
|
||||
) -> Result<TimeDuration, Error> {
|
||||
let seconds =
|
||||
self.seconds().try_checked_add("seconds", rhs.seconds())?;
|
||||
let nanoseconds = self.nanoseconds().without_bounds()
|
||||
+ rhs.nanoseconds().without_bounds();
|
||||
if let Ok(nanoseconds) =
|
||||
t::FractionalNanosecond::try_rfrom("nanoseconds", nanoseconds)
|
||||
{
|
||||
return Ok(TimeDuration::new(seconds, nanoseconds));
|
||||
}
|
||||
let seconds = seconds.without_bounds();
|
||||
// let nanoseconds = nanoseconds.without_bounds();
|
||||
// This is a little tricky, but both our seconds and nanosecond values
|
||||
// can change, and that change is dependent on both or either of
|
||||
// seconds and nanoseconds. Because of that, we need our range integers
|
||||
// to capture the full scope of dependent variation. So we need to
|
||||
// calculate how much we're going to change each by. This is also why
|
||||
// we convert our nanoseconds to `SpanSeconds`, so that we can vary
|
||||
// both values at the same time.
|
||||
//
|
||||
// It is much simpler to implement this using div/mod (basically,
|
||||
// "balancing"), but I theorized that it would be better to use
|
||||
// simpler ops here given that this is probably a hot path (since
|
||||
// a TimeDuration is the representation of an Instant). I haven't
|
||||
// actually benchmarked it though.
|
||||
let [delta_seconds, delta_nanos] = t::NoUnits::vary_many(
|
||||
[seconds, nanoseconds],
|
||||
|[seconds, nanoseconds]| {
|
||||
// We generally have two cases to handle here: when the
|
||||
// addition of nanoseconds causes it to go out of range (in
|
||||
// either direction), or when seconds and nanoseconds have a
|
||||
// different sign.
|
||||
//
|
||||
// The first case is somewhat straightforward. If nanoseconds
|
||||
// overflows, then it can overflow by at most 999_999_999. So
|
||||
// we add (or subtract) one second, and then add (or subtract)
|
||||
// 1_000_000_000 to the leftovers.
|
||||
//
|
||||
// The second case is handled by the `TimeDuration::new`
|
||||
// constructor call below.
|
||||
if nanoseconds >= t::NANOS_PER_SECOND {
|
||||
[C(1), (-t::NANOS_PER_SECOND).rinto()]
|
||||
} else if nanoseconds <= -t::NANOS_PER_SECOND {
|
||||
[C(-1), t::NANOS_PER_SECOND.rinto()]
|
||||
} else {
|
||||
[C(0), C(0)]
|
||||
}
|
||||
},
|
||||
);
|
||||
let mut seconds = t::SpanSeconds::rfrom(seconds);
|
||||
let mut nanoseconds = t::FractionalNanosecond::rfrom(nanoseconds);
|
||||
seconds = seconds.try_checked_add("seconds", delta_seconds)?;
|
||||
nanoseconds += delta_nanos;
|
||||
Ok(TimeDuration::new(seconds, nanoseconds))
|
||||
}
|
||||
|
||||
/// Subtracts the given right-hand-side duration from this one.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the subtraction of two durations would represent a bigger span of
|
||||
/// time than what is supported by this library, then an error is returned.
|
||||
#[inline]
|
||||
pub(crate) fn checked_sub(
|
||||
self,
|
||||
rhs: TimeDuration,
|
||||
) -> Result<TimeDuration, Error> {
|
||||
self.checked_add(rhs.negate())
|
||||
}
|
||||
|
||||
/// Multiplies this duration by the given factor.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the multiplication overflows this duration, then an error is
|
||||
/// returned.
|
||||
#[inline]
|
||||
pub(crate) fn checked_mul(
|
||||
self,
|
||||
rhs: impl RInto<t::NoUnits>,
|
||||
) -> Result<TimeDuration, Error> {
|
||||
let rhs = rhs.rinto();
|
||||
let seconds = self.seconds().try_checked_mul("seconds", rhs)?;
|
||||
let nanoseconds = self
|
||||
.nanoseconds()
|
||||
.without_bounds()
|
||||
.try_checked_mul("nanoseconds", rhs)?;
|
||||
let add_seconds = nanoseconds.div_ceil(t::NANOS_PER_SECOND);
|
||||
let nanoseconds = t::FractionalNanosecond::rfrom(
|
||||
nanoseconds.rem_ceil(t::NANOS_PER_SECOND),
|
||||
);
|
||||
let seconds = seconds.try_checked_add("seconds", add_seconds)?;
|
||||
Ok(TimeDuration { seconds, nanoseconds })
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TimeDuration {
|
||||
#[inline]
|
||||
fn default() -> TimeDuration {
|
||||
TimeDuration::ZERO
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for TimeDuration {}
|
||||
|
||||
impl PartialEq for TimeDuration {
|
||||
#[inline]
|
||||
fn eq(&self, rhs: &TimeDuration) -> bool {
|
||||
self.seconds.get() == rhs.seconds.get()
|
||||
&& self.nanoseconds.get() == rhs.nanoseconds.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for TimeDuration {
|
||||
#[inline]
|
||||
fn cmp(&self, rhs: &TimeDuration) -> core::cmp::Ordering {
|
||||
(self.seconds.get(), self.nanoseconds.get())
|
||||
.cmp(&(rhs.seconds.get(), rhs.nanoseconds.get()))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for TimeDuration {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, rhs: &TimeDuration) -> Option<core::cmp::Ordering> {
|
||||
Some(self.cmp(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for TimeDuration {
|
||||
type Output = TimeDuration;
|
||||
|
||||
#[inline]
|
||||
fn neg(self) -> Self {
|
||||
self.negate()
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for TimeDuration {
|
||||
type Output = TimeDuration;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: TimeDuration) -> Self {
|
||||
// See comments in `checked_add` for how this works. The only
|
||||
// difference here is that we don't do checked arithmetic. We rely on
|
||||
// our range integers to catch boundary bugs.
|
||||
|
||||
let seconds = self.seconds() + rhs.seconds();
|
||||
let nanoseconds = self.nanoseconds().without_bounds()
|
||||
+ rhs.nanoseconds().without_bounds();
|
||||
if let Ok(nanoseconds) =
|
||||
t::FractionalNanosecond::try_rfrom("nanoseconds", nanoseconds)
|
||||
{
|
||||
return TimeDuration::new(seconds, nanoseconds);
|
||||
}
|
||||
let seconds = seconds.without_bounds();
|
||||
let [delta_seconds, delta_nanos] = t::NoUnits::vary_many(
|
||||
[seconds, nanoseconds],
|
||||
|[seconds, nanoseconds]| {
|
||||
if nanoseconds >= t::NANOS_PER_SECOND {
|
||||
[C(1), (-t::NANOS_PER_SECOND).rinto()]
|
||||
} else if nanoseconds <= -t::NANOS_PER_SECOND {
|
||||
[C(-1), t::NANOS_PER_SECOND.rinto()]
|
||||
} else {
|
||||
[C(0), C(0)]
|
||||
}
|
||||
},
|
||||
);
|
||||
let mut seconds = t::SpanSeconds::rfrom(seconds);
|
||||
let mut nanoseconds = t::FractionalNanosecond::rfrom(nanoseconds);
|
||||
seconds += delta_seconds;
|
||||
nanoseconds += delta_nanos;
|
||||
TimeDuration::new(seconds, nanoseconds)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for TimeDuration {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: TimeDuration) {
|
||||
*self = *self + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for TimeDuration {
|
||||
type Output = TimeDuration;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: TimeDuration) -> Self {
|
||||
self.add(-rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for TimeDuration {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: TimeDuration) {
|
||||
*self = *self - rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: RInto<t::NoUnits>> Mul<N> for TimeDuration {
|
||||
type Output = TimeDuration;
|
||||
|
||||
#[inline]
|
||||
fn mul(self, rhs: N) -> Self {
|
||||
let rhs = rhs.rinto();
|
||||
let mut seconds = self.seconds() * rhs;
|
||||
let nanoseconds = self.nanoseconds().without_bounds() * rhs;
|
||||
let add_seconds = nanoseconds.div_ceil(t::NANOS_PER_SECOND);
|
||||
seconds += add_seconds;
|
||||
let nanoseconds = t::FractionalNanosecond::rfrom(
|
||||
nanoseconds.rem_ceil(t::NANOS_PER_SECOND),
|
||||
);
|
||||
TimeDuration { seconds, nanoseconds }
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for TimeDuration {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
let minus = if self.signum() >= 0 { "" } else { "-" };
|
||||
if self.nanoseconds == 0 {
|
||||
write!(f, "{minus}{:?}s", self.seconds.abs().debug())
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"{minus}{:?}s{:?}ns",
|
||||
self.seconds.abs().debug(),
|
||||
self.nanoseconds.abs().debug(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl quickcheck::Arbitrary for TimeDuration {
|
||||
fn arbitrary(g: &mut quickcheck::Gen) -> TimeDuration {
|
||||
let seconds = t::SpanSeconds::arbitrary(g);
|
||||
let nanoseconds = t::FractionalNanosecond::arbitrary(g);
|
||||
TimeDuration::new(seconds, nanoseconds)
|
||||
}
|
||||
|
||||
fn shrink(&self) -> alloc::boxed::Box<dyn Iterator<Item = Self>> {
|
||||
alloc::boxed::Box::new((self.seconds, self.nanoseconds).shrink().map(
|
||||
|(seconds, nanoseconds)| TimeDuration { seconds, nanoseconds },
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::ToSpan;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn span_to_time_duration(span: Span) -> Result<(i64, i32), Error> {
|
||||
TimeDuration::from_span(&span).map(|d| d.to_parts())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_span() {
|
||||
let d = |span| span_to_time_duration(span).unwrap();
|
||||
|
||||
assert_eq!((1, 0), d(Span::new().seconds(1)));
|
||||
assert_eq!((1, 1), d(Span::new().seconds(1).nanoseconds(1)));
|
||||
assert_eq!(
|
||||
(2, 0),
|
||||
d(Span::new().seconds(1).nanoseconds(1_000_000_000))
|
||||
);
|
||||
assert_eq!(
|
||||
(t::SpanSeconds::MAX_REPR, 0),
|
||||
d(Span::new().hours(t::SpanHours::MAX_REPR))
|
||||
);
|
||||
assert_eq!(
|
||||
(t::SpanSeconds::MAX_REPR, 999_999_999),
|
||||
d(Span::new()
|
||||
.hours(t::SpanHours::MAX_REPR)
|
||||
.nanoseconds(999_999_999))
|
||||
);
|
||||
assert_eq!((1, 1_000_000), d(Span::new().milliseconds(1_001)));
|
||||
assert_eq!((1, 1_000), d(Span::new().microseconds(1_000_001)));
|
||||
assert_eq!(
|
||||
(2, 1_001_000),
|
||||
d(Span::new().milliseconds(1_001).microseconds(1_000_001))
|
||||
);
|
||||
assert_eq!(
|
||||
(3, 1_001_001),
|
||||
d(Span::new()
|
||||
.milliseconds(1_001)
|
||||
.microseconds(1_000_001)
|
||||
.nanoseconds(1_000_000_001))
|
||||
);
|
||||
assert_eq!(
|
||||
(0, 123_456_789),
|
||||
d(Span::new()
|
||||
.milliseconds(123)
|
||||
.microseconds(456)
|
||||
.nanoseconds(789))
|
||||
);
|
||||
assert_eq!(
|
||||
(1, 0),
|
||||
d(Span::new()
|
||||
.milliseconds(900)
|
||||
.microseconds(50_000)
|
||||
.nanoseconds(50_000_000)),
|
||||
);
|
||||
|
||||
// Negative spans.
|
||||
assert_eq!((-3, -400), d(Span::new().nanoseconds(-3_000_000_400i64)));
|
||||
|
||||
// Error cases where the `Span` represents a period of time that cannot
|
||||
// be represented by a `TimeDuration`.
|
||||
let d = |span| span_to_time_duration(span);
|
||||
assert!(
|
||||
d(Span::new().hours(t::SpanHours::MAX_REPR).minutes(1)).is_err()
|
||||
);
|
||||
assert!(
|
||||
d(Span::new().hours(t::SpanHours::MAX_REPR).seconds(1)).is_err()
|
||||
);
|
||||
assert!(d(Span::new()
|
||||
.hours(t::SpanHours::MAX_REPR)
|
||||
.nanoseconds(1_000_000_000))
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_add() {
|
||||
let add = |(s1, n1), (s2, n2)| {
|
||||
let d1 = TimeDuration::try_new(s1, n1).unwrap();
|
||||
let d2 = TimeDuration::try_new(s2, n2).unwrap();
|
||||
d1.checked_add(d2)
|
||||
.map(|d3| (d3.seconds().get(), d3.nanoseconds().get()))
|
||||
};
|
||||
assert_eq!((0, 0), add((0, 0), (0, 0)).unwrap());
|
||||
assert_eq!((3, 999_999_999), add((1, 999_999_998), (2, 1)).unwrap());
|
||||
assert_eq!((4, 0), add((1, 999_999_999), (2, 1)).unwrap());
|
||||
assert_eq!(
|
||||
(4, 999999998),
|
||||
add((1, 999_999_999), (2, 999_999_999)).unwrap(),
|
||||
);
|
||||
assert_eq!(
|
||||
(t::SpanSeconds::MAX_REPR, 0),
|
||||
add((t::SpanSeconds::MAX_REPR, 0), (0, 0)).unwrap(),
|
||||
);
|
||||
assert_eq!(
|
||||
(t::SpanSeconds::MAX_REPR, 999_999_999),
|
||||
add((t::SpanSeconds::MAX_REPR, 0), (0, 999_999_999)).unwrap(),
|
||||
);
|
||||
|
||||
// Tests with negatives.
|
||||
assert_eq!((2, 0), add((3, 0), (-1, 0)).unwrap());
|
||||
// e.g., The nanos are being ADDED here. But if the -1 means the
|
||||
// duration is overall negative, then they should be subtracted.
|
||||
assert_eq!((1, 1), add((3, 0), (-1, -999_999_999)).unwrap());
|
||||
assert_eq!((-7, -5_000), add((3, 0), (-10, -5_000)).unwrap());
|
||||
assert_eq!(
|
||||
(-6, -999_999_000),
|
||||
add((3, 6_000), (-10, -5_000)).unwrap(),
|
||||
);
|
||||
|
||||
// Error cases where addition results in a duration that is too big.
|
||||
assert!(add((t::SpanSeconds::MAX_REPR, 0), (1, 0)).is_err());
|
||||
assert!(add((t::SpanSeconds::MAX_REPR, 1), (0, 999_999_999)).is_err());
|
||||
assert!(add(
|
||||
(t::SpanSeconds::MAX_REPR, 0),
|
||||
(t::SpanSeconds::MAX_REPR, 0)
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add() {
|
||||
let add = |(s1, n1), (s2, n2)| {
|
||||
let d1 = TimeDuration::new(C(s1), C(n1));
|
||||
let d2 = TimeDuration::new(C(s2), C(n2));
|
||||
(d1 + d2).to_parts()
|
||||
};
|
||||
assert_eq!((0, 0), add((0, 0), (0, 0)));
|
||||
assert_eq!((3, 999_999_999), add((1, 999_999_998), (2, 1)));
|
||||
assert_eq!((4, 0), add((1, 999_999_999), (2, 1)));
|
||||
assert_eq!((4, 999999998), add((1, 999_999_999), (2, 999_999_999)));
|
||||
assert_eq!(
|
||||
(t::SpanSeconds::MAX_REPR, 0),
|
||||
add((t::SpanSeconds::MAX_REPR, 0), (0, 0))
|
||||
);
|
||||
assert_eq!(
|
||||
(t::SpanSeconds::MAX_REPR, 999_999_999),
|
||||
add((t::SpanSeconds::MAX_REPR, 0), (0, 999_999_999))
|
||||
);
|
||||
|
||||
// Tests with negatives.
|
||||
assert_eq!((2, 0), add((3, 0), (-1, 0)));
|
||||
// e.g., The nanos are being ADDED here. But if the -1 means the
|
||||
// duration is overall negative, then they should be subtracted.
|
||||
assert_eq!((1, 1), add((3, 0), (-1, -999_999_999)));
|
||||
assert_eq!((-7, -5_000), add((3, 0), (-10, -5_000)));
|
||||
assert_eq!((-6, -999_999_000), add((3, 6_000), (-10, -5_000)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_sub() {
|
||||
let sub = |(s1, n1), (s2, n2)| {
|
||||
let d1 = TimeDuration::try_new(s1, n1).unwrap();
|
||||
let d2 = TimeDuration::try_new(s2, n2).unwrap();
|
||||
d1.checked_sub(d2)
|
||||
.map(|d3| (d3.seconds().get(), d3.nanoseconds.get()))
|
||||
};
|
||||
assert_eq!((0, 0), sub((0, 0), (0, 0)).unwrap());
|
||||
assert_eq!((2, 0), sub((5, 0), (3, 0)).unwrap());
|
||||
assert_eq!((2, 400), sub((5, 1_000), (3, 600)).unwrap());
|
||||
assert_eq!((1, 999_999_900), sub((5, 1_000), (3, 1_100)).unwrap());
|
||||
assert_eq!((0, -3), sub((1, 999_999_998), (2, 1)).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub() {
|
||||
let sub = |(s1, n1), (s2, n2)| {
|
||||
let d1 = TimeDuration::new(C(s1), C(n1));
|
||||
let d2 = TimeDuration::new(C(s2), C(n2));
|
||||
(d1 - d2).to_parts()
|
||||
};
|
||||
assert_eq!((0, 0), sub((0, 0), (0, 0)));
|
||||
assert_eq!((2, 0), sub((5, 0), (3, 0)));
|
||||
assert_eq!((2, 400), sub((5, 1_000), (3, 600)));
|
||||
assert_eq!((1, 999_999_900), sub((5, 1_000), (3, 1_100)));
|
||||
assert_eq!((0, -3), sub((1, 999_999_998), (2, 1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new() {
|
||||
let t = TimeDuration::try_new(1, -1).unwrap();
|
||||
assert_eq!(t.to_parts(), (0, 999_999_999));
|
||||
|
||||
let t = TimeDuration::try_new(-1, 1).unwrap();
|
||||
assert_eq!(t.to_parts(), (0, -999_999_999));
|
||||
|
||||
let t = TimeDuration::try_new(1, 1).unwrap();
|
||||
assert_eq!(t.to_parts(), (1, 1));
|
||||
|
||||
let t = TimeDuration::try_new(-1, -1).unwrap();
|
||||
assert_eq!(t.to_parts(), (-1, -1));
|
||||
|
||||
let t = TimeDuration::try_new(0, 1).unwrap();
|
||||
assert_eq!(t.to_parts(), (0, 1));
|
||||
|
||||
let t = TimeDuration::try_new(0, -1).unwrap();
|
||||
assert_eq!(t.to_parts(), (0, -1));
|
||||
|
||||
let t = TimeDuration::try_new(1, 0).unwrap();
|
||||
assert_eq!(t.to_parts(), (1, 0));
|
||||
|
||||
let t = TimeDuration::try_new(-1, 0).unwrap();
|
||||
assert_eq!(t.to_parts(), (-1, 0));
|
||||
|
||||
let t = TimeDuration::try_new(1, -999_999_999).unwrap();
|
||||
assert_eq!(t.to_parts(), (0, 1));
|
||||
|
||||
let t = TimeDuration::try_new(-1, 999_999_999).unwrap();
|
||||
assert_eq!(t.to_parts(), (0, -1));
|
||||
|
||||
let t = TimeDuration::try_new(1, 999_999_999).unwrap();
|
||||
assert_eq!(t.to_parts(), (1, 999_999_999));
|
||||
|
||||
let t = TimeDuration::try_new(-1, -999_999_999).unwrap();
|
||||
assert_eq!(t.to_parts(), (-1, -999_999_999));
|
||||
|
||||
let t = TimeDuration::new(
|
||||
t::SpanSeconds::MAX_SELF,
|
||||
t::FractionalNanosecond::MIN_SELF,
|
||||
);
|
||||
assert_eq!(t.to_parts(), (t::SpanSeconds::MAX_REPR - 1, 1));
|
||||
|
||||
let t = TimeDuration::new(
|
||||
t::SpanSeconds::MAX_SELF,
|
||||
t::FractionalNanosecond::MAX_SELF,
|
||||
);
|
||||
assert_eq!(t.to_parts(), (t::SpanSeconds::MAX_REPR, 999_999_999));
|
||||
|
||||
let t = TimeDuration::new(
|
||||
t::SpanSeconds::MIN_SELF,
|
||||
t::FractionalNanosecond::MIN_SELF,
|
||||
);
|
||||
assert_eq!(t.to_parts(), (t::SpanSeconds::MIN_REPR, -999_999_999));
|
||||
|
||||
let t = TimeDuration::new(
|
||||
t::SpanSeconds::MIN_SELF,
|
||||
t::FractionalNanosecond::MAX_SELF,
|
||||
);
|
||||
assert_eq!(t.to_parts(), (t::SpanSeconds::MIN_REPR + 1, -1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mul() {
|
||||
let td = TimeDuration::new(C(5), C(400_000_000));
|
||||
let got = td * C(2);
|
||||
assert_eq!(got.to_parts(), (10, 800_000_000));
|
||||
|
||||
let td = TimeDuration::new(C(5), C(400_000_000));
|
||||
let got = td * C(3);
|
||||
assert_eq!(got.to_parts(), (16, 200_000_000));
|
||||
|
||||
let td = TimeDuration::new(C(-5), C(-400_000_000));
|
||||
let got = td * C(2);
|
||||
assert_eq!(got.to_parts(), (-10, -800_000_000));
|
||||
|
||||
let td = TimeDuration::new(C(-5), C(-400_000_000));
|
||||
let got = td * C(3);
|
||||
assert_eq!(got.to_parts(), (-16, -200_000_000));
|
||||
|
||||
let td = TimeDuration::new(C(5), C(400_000_000));
|
||||
let got = td * C(-2);
|
||||
assert_eq!(got.to_parts(), (-10, -800_000_000));
|
||||
|
||||
let td = TimeDuration::new(C(5), C(400_000_000));
|
||||
let got = td * C(-3);
|
||||
assert_eq!(got.to_parts(), (-16, -200_000_000));
|
||||
|
||||
let td = TimeDuration::new(C(-5), C(-400_000_000));
|
||||
let got = td * C(-2);
|
||||
assert_eq!(got.to_parts(), (10, 800_000_000));
|
||||
|
||||
let td = TimeDuration::new(C(-5), C(-400_000_000));
|
||||
let got = td * C(-3);
|
||||
assert_eq!(got.to_parts(), (16, 200_000_000));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_mul() {
|
||||
let td = TimeDuration::try_new(5, 400_000_000).unwrap();
|
||||
let got = td.checked_mul(t::NoUnits::new(2).unwrap()).unwrap();
|
||||
assert_eq!(got.to_parts(), (10, 800_000_000));
|
||||
|
||||
let td = TimeDuration::try_new(5, 400_000_000).unwrap();
|
||||
let got = td.checked_mul(t::NoUnits::new(3).unwrap()).unwrap();
|
||||
assert_eq!(got.to_parts(), (16, 200_000_000));
|
||||
|
||||
let td = TimeDuration::try_new(-5, -400_000_000).unwrap();
|
||||
let got = td.checked_mul(t::NoUnits::new(2).unwrap()).unwrap();
|
||||
assert_eq!(got.to_parts(), (-10, -800_000_000));
|
||||
|
||||
let td = TimeDuration::try_new(-5, -400_000_000).unwrap();
|
||||
let got = td.checked_mul(t::NoUnits::new(3).unwrap()).unwrap();
|
||||
assert_eq!(got.to_parts(), (-16, -200_000_000));
|
||||
|
||||
let td = TimeDuration::try_new(5, 400_000_000).unwrap();
|
||||
let got = td.checked_mul(t::NoUnits::new(-2).unwrap()).unwrap();
|
||||
assert_eq!(got.to_parts(), (-10, -800_000_000));
|
||||
|
||||
let td = TimeDuration::try_new(5, 400_000_000).unwrap();
|
||||
let got = td.checked_mul(t::NoUnits::new(-3).unwrap()).unwrap();
|
||||
assert_eq!(got.to_parts(), (-16, -200_000_000));
|
||||
|
||||
let td = TimeDuration::try_new(-5, -400_000_000).unwrap();
|
||||
let got = td.checked_mul(t::NoUnits::new(-2).unwrap()).unwrap();
|
||||
assert_eq!(got.to_parts(), (10, 800_000_000));
|
||||
|
||||
let td = TimeDuration::try_new(-5, -400_000_000).unwrap();
|
||||
let got = td.checked_mul(t::NoUnits::new(-3).unwrap()).unwrap();
|
||||
assert_eq!(got.to_parts(), (16, 200_000_000));
|
||||
}
|
||||
|
||||
quickcheck::quickcheck! {
|
||||
fn prop_roundtrip_nanoseconds(td: TimeDuration) -> bool {
|
||||
let nanos = td.to_nanoseconds();
|
||||
let got = TimeDuration::from_nanoseconds(nanos).unwrap();
|
||||
td == got
|
||||
}
|
||||
}
|
||||
}
|
||||
1761
src/span/mod.rs
Normal file
1761
src/span/mod.rs
Normal file
File diff suppressed because it is too large
Load diff
116
src/tz/db/mod.rs
Normal file
116
src/tz/db/mod.rs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
use crate::{
|
||||
error::Error,
|
||||
instant::{Instant, Tai, Unix},
|
||||
tz::TimeZone,
|
||||
util::t,
|
||||
};
|
||||
|
||||
use self::zoneinfo::ZoneInfo;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod zoneinfo;
|
||||
|
||||
pub fn db() -> &'static TimeZoneDatabase {
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
static NONE: &'static TimeZoneDatabase = TimeZoneDatabase::none();
|
||||
NONE
|
||||
}
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
use std::sync::OnceLock;
|
||||
|
||||
static DB: OnceLock<TimeZoneDatabase> = OnceLock::new();
|
||||
DB.get_or_init(|| TimeZoneDatabase::from_env())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TimeZoneDatabase {
|
||||
kind: TimeZoneDatabaseKind,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum TimeZoneDatabaseKind {
|
||||
None,
|
||||
ZoneInfo(ZoneInfo),
|
||||
}
|
||||
|
||||
impl TimeZoneDatabase {
|
||||
pub fn from_env() -> TimeZoneDatabase {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
let zoneinfo = ZoneInfo::from_env();
|
||||
let kind = TimeZoneDatabaseKind::ZoneInfo(zoneinfo);
|
||||
TimeZoneDatabase { kind }
|
||||
}
|
||||
#[cfg(not(feature = "std"))]
|
||||
{
|
||||
TimeZoneDatabase::none()
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn none() -> TimeZoneDatabase {
|
||||
let kind = TimeZoneDatabaseKind::None;
|
||||
TimeZoneDatabase { kind }
|
||||
}
|
||||
|
||||
pub fn get(&self, name: &str) -> Result<TimeZone, Error> {
|
||||
match self.kind {
|
||||
TimeZoneDatabaseKind::None => {
|
||||
Err(Error::time_zone_lookup("unavailable", name))
|
||||
}
|
||||
TimeZoneDatabaseKind::ZoneInfo(ref db) => db
|
||||
.get(name)
|
||||
.ok_or_else(|| Error::time_zone_lookup("zoneinfo", name)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unix_to_tai(
|
||||
&self,
|
||||
instant: Instant<Unix>,
|
||||
) -> Result<Instant<Tai>, Error> {
|
||||
match self.kind {
|
||||
TimeZoneDatabaseKind::None => todo!(),
|
||||
TimeZoneDatabaseKind::ZoneInfo(ref db) => db.unix_to_tai(instant),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tai_to_unix(&self, instant: Instant<Tai>) -> Instant<Unix> {
|
||||
match self.kind {
|
||||
TimeZoneDatabaseKind::None => todo!(),
|
||||
TimeZoneDatabaseKind::ZoneInfo(ref db) => db.tai_to_unix(instant),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&self) {
|
||||
match self.kind {
|
||||
TimeZoneDatabaseKind::None => {}
|
||||
TimeZoneDatabaseKind::ZoneInfo(ref db) => db.reset(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unix_to_tai_timestamp(
|
||||
&self,
|
||||
unix_timestamp: t::UnixSeconds,
|
||||
) -> Result<t::TaiSeconds, Error> {
|
||||
match self.kind {
|
||||
TimeZoneDatabaseKind::None => todo!(),
|
||||
TimeZoneDatabaseKind::ZoneInfo(ref db) => {
|
||||
db.unix_to_tai_timestamp(unix_timestamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn tai_to_unix_timestamp(
|
||||
&self,
|
||||
tai_timestamp: t::TaiSeconds,
|
||||
) -> (t::UnixSeconds, bool) {
|
||||
match self.kind {
|
||||
TimeZoneDatabaseKind::None => todo!(),
|
||||
TimeZoneDatabaseKind::ZoneInfo(ref db) => {
|
||||
db.tai_to_unix_timestamp(tai_timestamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
980
src/tz/db/zoneinfo.rs
Normal file
980
src/tz/db/zoneinfo.rs
Normal file
|
|
@ -0,0 +1,980 @@
|
|||
use std::{
|
||||
fs::File,
|
||||
io::{self, Read},
|
||||
path::{Path, PathBuf},
|
||||
sync::{Arc, RwLock},
|
||||
time::{Duration, Instant as MonotonicInstant},
|
||||
};
|
||||
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
vec,
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{err, Error},
|
||||
instant::{Instant, Tai, Unix},
|
||||
leapseconds::LeapSeconds,
|
||||
tz::{tzif::is_possibly_tzif, TimeZone},
|
||||
util::{escape::Bytes, parse, t},
|
||||
};
|
||||
|
||||
const DEFAULT_TTL: Duration = Duration::new(5 * 60, 0);
|
||||
|
||||
const ZONEINFO_DIRECTORIES: &[&str] =
|
||||
&["/usr/share/zoneinfo", "/etc/zoneinfo"];
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ZoneInfo {
|
||||
names: Option<ZoneInfoNames>,
|
||||
zones: RwLock<CachedZones>,
|
||||
leaps: RwLock<Leaps>,
|
||||
}
|
||||
|
||||
impl ZoneInfo {
|
||||
pub(crate) fn from_env() -> ZoneInfo {
|
||||
if let Some(tzdir) = std::env::var_os("TZDIR") {
|
||||
let tzdir = PathBuf::from(tzdir);
|
||||
debug!("opening zoneinfo database at TZDIR={}", tzdir.display());
|
||||
match ZoneInfo::from_dir(&tzdir) {
|
||||
Ok(db) => return db,
|
||||
Err(err) => {
|
||||
warn!("failed opening TZDIR={}: {err}", tzdir.display());
|
||||
// fall through to attempt default directories
|
||||
}
|
||||
}
|
||||
}
|
||||
for dir in ZONEINFO_DIRECTORIES {
|
||||
let tzdir = Path::new(dir);
|
||||
debug!("opening zoneinfo database at {}", tzdir.display());
|
||||
match ZoneInfo::from_dir(&tzdir) {
|
||||
Ok(db) => return db,
|
||||
Err(err) => {
|
||||
debug!("failed opening TZDIR={}: {err}", tzdir.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
warn!(
|
||||
"could not find zoneinfo database at any of the following \
|
||||
paths: {}",
|
||||
ZONEINFO_DIRECTORIES.join(", "),
|
||||
);
|
||||
ZoneInfo::none()
|
||||
}
|
||||
|
||||
pub(crate) fn from_dir(dir: &Path) -> Result<ZoneInfo, Error> {
|
||||
let names = Some(ZoneInfoNames::new(dir)?);
|
||||
let zones = RwLock::new(CachedZones::new());
|
||||
// TODO: We shouldn't load leap data eagerly. Most users will probably
|
||||
// never use it!
|
||||
let leaps = RwLock::new(match Leaps::new(dir) {
|
||||
Ok(leaps) => leaps,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"failed to load leap second data from {}, \
|
||||
falling back to builtin data: {err}",
|
||||
dir.display()
|
||||
);
|
||||
Leaps::builtin()
|
||||
}
|
||||
});
|
||||
Ok(ZoneInfo { names, zones, leaps })
|
||||
}
|
||||
|
||||
/// Creates a "dummy" zoneinfo database in which all lookups fail.
|
||||
pub(crate) fn none() -> ZoneInfo {
|
||||
let names = None;
|
||||
let zones = RwLock::new(CachedZones::new());
|
||||
let leaps = RwLock::new(Leaps::builtin());
|
||||
ZoneInfo { names, zones, leaps }
|
||||
}
|
||||
|
||||
/// Returns true if it is known that all lookups will always fail.
|
||||
pub(crate) fn is_none(&self) -> bool {
|
||||
self.names.is_none()
|
||||
}
|
||||
|
||||
pub(crate) fn reset(&self) {
|
||||
let mut zones = self.zones.write().unwrap();
|
||||
let mut leaps = self.leaps.write().unwrap();
|
||||
if let Some(ref names) = self.names {
|
||||
names.reset();
|
||||
}
|
||||
zones.reset();
|
||||
leaps.reset();
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, query: &str) -> Option<TimeZone> {
|
||||
// If we couldn't build any time zone names, then every lookup will
|
||||
// fail. So just bail now.
|
||||
let names = self.names.as_ref()?;
|
||||
// The fast path is when the query matches a pre-existing unexpired
|
||||
// time zone.
|
||||
{
|
||||
let zones = self.zones.read().unwrap();
|
||||
if let Some(czone) = zones.get(query) {
|
||||
if !czone.is_expired() {
|
||||
return Some(czone.tz.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
// At this point, one of three possible cases is true:
|
||||
//
|
||||
// 1. The given query does not match any time zone in this database.
|
||||
// 2. A time zone exists, but isn't cached.
|
||||
// 3. A zime exists and is cached, but needs to be revalidated.
|
||||
//
|
||||
// While (3) is probably the common case since our TTLs are pretty
|
||||
// short, both (2) and (3) require write access. Thus we rule out (1)
|
||||
// before acquiring a write lock on the entire database. Plus, we'll
|
||||
// need the zone info for case (2) and possibly for (3) if cache
|
||||
// revalidation fails.
|
||||
//
|
||||
// I feel kind of bad about all this because it seems to me like there
|
||||
// is too much work being done while holding on to the write lock.
|
||||
// In particular, it seems like bad juju to do any I/O of any kind
|
||||
// while holding any lock at all. I think I could design something
|
||||
// that avoids doing I/O while holding a lock, but it seems a lot more
|
||||
// complicated. (And what happens if the I/O becomes outdated by the
|
||||
// time you acquire the lock?)
|
||||
let info = names.get(query)?;
|
||||
let mut zones = self.zones.write().unwrap();
|
||||
let ttl = zones.ttl;
|
||||
match zones.get_zone_index(query) {
|
||||
Ok(i) => {
|
||||
let czone = &mut zones.zones[i];
|
||||
if czone.revalidate(&info, ttl) {
|
||||
// Metadata on the file didn't change, so we assume the
|
||||
// file hasn't either.
|
||||
return Some(czone.tz.clone());
|
||||
}
|
||||
// Revalidation failed. Re-read the TZif data.
|
||||
let czone = match CachedTimeZone::new(&info, zones.ttl) {
|
||||
Ok(czone) => czone,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"failed to re-cache time zone from file {}: {err}",
|
||||
info.inner.full.display(),
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let tz = czone.tz.clone();
|
||||
zones.zones[i] = czone;
|
||||
Some(tz)
|
||||
}
|
||||
Err(i) => {
|
||||
let czone = match CachedTimeZone::new(&info, ttl) {
|
||||
Ok(czone) => czone,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"failed to cache time zone from file {}: {err}",
|
||||
info.inner.full.display(),
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let tz = czone.tz.clone();
|
||||
zones.zones.insert(i, czone);
|
||||
Some(tz)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unix_to_tai(
|
||||
&self,
|
||||
instant: Instant<Unix>,
|
||||
) -> Result<Instant<Tai>, Error> {
|
||||
self.with_leap_seconds(|ls| ls.unix_to_tai(instant))
|
||||
}
|
||||
|
||||
pub(crate) fn tai_to_unix(&self, instant: Instant<Tai>) -> Instant<Unix> {
|
||||
self.with_leap_seconds(|ls| ls.tai_to_unix(instant))
|
||||
}
|
||||
|
||||
pub(crate) fn unix_to_tai_timestamp(
|
||||
&self,
|
||||
unix_timestamp: t::UnixSeconds,
|
||||
) -> Result<t::TaiSeconds, Error> {
|
||||
self.with_leap_seconds(|ls| ls.unix_to_tai_timestamp(unix_timestamp))
|
||||
}
|
||||
|
||||
pub(crate) fn tai_to_unix_timestamp(
|
||||
&self,
|
||||
tai_timestamp: t::TaiSeconds,
|
||||
) -> (t::UnixSeconds, bool) {
|
||||
self.with_leap_seconds(|ls| ls.tai_to_unix_timestamp(tai_timestamp))
|
||||
}
|
||||
|
||||
fn with_leap_seconds<T>(&self, mut f: impl FnMut(&LeapSeconds) -> T) -> T {
|
||||
{
|
||||
let leaps = self.leaps.read().unwrap();
|
||||
if !leaps.expiration.is_expired() {
|
||||
return f(&leaps.leapseconds);
|
||||
}
|
||||
}
|
||||
let mut leaps = self.leaps.write().unwrap();
|
||||
if leaps.revalidate() {
|
||||
return f(&leaps.leapseconds);
|
||||
}
|
||||
// OK because we can only be here when we have a path.
|
||||
let path = leaps.path.as_ref().unwrap().to_path_buf();
|
||||
match Leaps::from_path(&path) {
|
||||
Ok(new_leaps) => *leaps = new_leaps,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"failed to update leap second data for {}: {err}",
|
||||
path.display(),
|
||||
);
|
||||
leaps.expiration = Expiration::after(leaps.ttl);
|
||||
}
|
||||
}
|
||||
f(&leaps.leapseconds)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CachedZones {
|
||||
zones: Vec<CachedTimeZone>,
|
||||
ttl: Duration,
|
||||
}
|
||||
|
||||
impl CachedZones {
|
||||
const DEFAULT_TTL: Duration = DEFAULT_TTL;
|
||||
|
||||
fn new() -> CachedZones {
|
||||
CachedZones { zones: vec![], ttl: CachedZones::DEFAULT_TTL }
|
||||
}
|
||||
|
||||
fn get(&self, query: &str) -> Option<&CachedTimeZone> {
|
||||
self.get_zone_index(query).ok().map(|i| &self.zones[i])
|
||||
}
|
||||
|
||||
fn get_zone_index(&self, query: &str) -> Result<usize, usize> {
|
||||
self.zones.binary_search_by(|zone| {
|
||||
cmp_ignore_ascii_case(zone.tz.name(), query)
|
||||
})
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.zones.clear();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct CachedTimeZone {
|
||||
tz: TimeZone,
|
||||
expiration: Expiration,
|
||||
last_modified: Option<Instant>,
|
||||
}
|
||||
|
||||
impl CachedTimeZone {
|
||||
/// Create a new cached time zone.
|
||||
///
|
||||
/// The `info` says which time zone to create and where to find it. The
|
||||
/// `ttl` says how long the cached time zone should minimally remain fresh
|
||||
/// for.
|
||||
fn new(
|
||||
info: &ZoneInfoName,
|
||||
ttl: Duration,
|
||||
) -> Result<CachedTimeZone, Error> {
|
||||
let path = &info.inner.full;
|
||||
let mut file = File::open(path).map_err(|e| Error::fs(path, e))?;
|
||||
let mut data = vec![];
|
||||
file.read_to_end(&mut data).map_err(|e| Error::fs(path, e))?;
|
||||
let tz = TimeZone::tzif(&info.inner.original, &data)
|
||||
.map_err(|e| e.path(path))?;
|
||||
let last_modified = last_modified_from_file(path, &file);
|
||||
let expiration = Expiration::after(ttl);
|
||||
Ok(CachedTimeZone { tz, expiration, last_modified })
|
||||
}
|
||||
|
||||
/// Returns true if this time zone has gone stale and should, at minimum,
|
||||
/// be revalidated.
|
||||
fn is_expired(&self) -> bool {
|
||||
self.expiration.is_expired()
|
||||
}
|
||||
|
||||
/// Attempts to revalidate this cached time zone.
|
||||
///
|
||||
/// Upon successful revalidation (that is, the cached time zone is still
|
||||
/// fresh and okay to use), this returns true. Otherwise, the cached time
|
||||
/// zone should be considered stale and must be re-created.
|
||||
///
|
||||
/// Note that technically another layer of revalidation could be done.
|
||||
/// For example, we could keep a checksum of the TZif data, and only
|
||||
/// consider rebuilding the time zone when the checksum changes. But I
|
||||
/// think the last modified metadata will in practice be good enough, and
|
||||
/// parsing a TZif file should be quite fast.
|
||||
fn revalidate(&mut self, info: &ZoneInfoName, ttl: Duration) -> bool {
|
||||
// If we started with no last modified timestamp, then I guess we
|
||||
// should always fail revalidation? I suppose a case could be made to
|
||||
// do the opposite: always pass revalidation.
|
||||
let Some(old_last_modified) = self.last_modified else {
|
||||
info!(
|
||||
"revalidation for {} failed because old last modified time \
|
||||
is unavailable",
|
||||
info.inner.full.display(),
|
||||
);
|
||||
return false;
|
||||
};
|
||||
let Some(new_last_modified) =
|
||||
last_modified_from_path(&info.inner.full)
|
||||
else {
|
||||
info!(
|
||||
"revalidation for {} failed because new last modified time \
|
||||
is unavailable",
|
||||
info.inner.full.display(),
|
||||
);
|
||||
return false;
|
||||
};
|
||||
// We consider any change to invalidate cache.
|
||||
if old_last_modified != new_last_modified {
|
||||
info!(
|
||||
"revalidation for {} failed because last modified times \
|
||||
do not match: old = {} != {} = new",
|
||||
info.inner.full.display(),
|
||||
old_last_modified,
|
||||
new_last_modified,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
trace!(
|
||||
"revalidation for {} succeeded because last modified times \
|
||||
match: old = {} == {} = new",
|
||||
info.inner.full.display(),
|
||||
old_last_modified,
|
||||
new_last_modified,
|
||||
);
|
||||
self.expiration = Expiration::after(ttl);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// A collection of time zone names extracted from a zoneinfo directory.
|
||||
///
|
||||
/// Each time zone name maps to a full path on the file system corresponding
|
||||
/// to the TZif formatted data file for that time zone.
|
||||
///
|
||||
/// This type is responsible not just for providing the names, but also for
|
||||
/// updating them periodically.
|
||||
#[derive(Debug)]
|
||||
struct ZoneInfoNames {
|
||||
inner: RwLock<ZoneInfoNamesInner>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ZoneInfoNamesInner {
|
||||
/// The directory from which we collected time zone names.
|
||||
dir: PathBuf,
|
||||
/// All available names from the `zoneinfo` directory.
|
||||
///
|
||||
/// Each name corresponds to the suffix of a file path
|
||||
/// starting with `dir`. For example, `America/New_York` in
|
||||
/// `/usr/share/zoneinfo/America/New_York`. Each name also has a normalized
|
||||
/// lowercase version of the name for easy case insensitive lookup.
|
||||
names: Vec<ZoneInfoName>,
|
||||
/// The expiration time of this cached value.
|
||||
///
|
||||
/// Note that this is a necessary but not sufficient criterion for
|
||||
/// invalidating the cached value.
|
||||
ttl: Duration,
|
||||
/// The time at which the data in `names` becomes stale.
|
||||
///
|
||||
/// When `None`, it implies that the expiration time is at some arbitrary
|
||||
/// point in the past beyond any possible `ttl` value. i.e., A `None` value
|
||||
/// invalidates the cache at the next failed lookup.
|
||||
expiration: Expiration,
|
||||
}
|
||||
|
||||
impl ZoneInfoNames {
|
||||
/// The default amount of time to wait before checking for added/removed
|
||||
/// time zones.
|
||||
///
|
||||
/// Note that this TTL is a necessary but not sufficient criterion to
|
||||
/// provoke cache invalidation. Namely, since we don't expect the set of
|
||||
/// possible time zone names to change often, we only invalidate the cache
|
||||
/// under these circumstances:
|
||||
///
|
||||
/// 1. The TTL or more has passed since the last time the names were
|
||||
/// attempted to be refreshed (even if it wasn't successful).
|
||||
/// 2. A name lookup is attempted and it isn't found. This is required
|
||||
/// because otherwise there isn't much point in refreshing the names.
|
||||
///
|
||||
/// This logic does not deal as well with removals from the underlying time
|
||||
/// zone database. That in turn is covered by the TTL on constructing the
|
||||
/// `TimeZone` values themselves.
|
||||
///
|
||||
/// We could just use the second criterion on its own, but we require the
|
||||
/// TTL to expire out of "good sense." Namely, if there is something borked
|
||||
/// in the environment, the TTL will prevent doing a full scan of the
|
||||
/// zoneinfo directory for every missed time zone lookup.
|
||||
const DEFAULT_TTL: Duration = DEFAULT_TTL;
|
||||
|
||||
/// Create a new collection of names from the zoneinfo database directory
|
||||
/// given.
|
||||
///
|
||||
/// If no names of time zones with corresponding TZif data files could be
|
||||
/// found in the given directory, then an error is returned.
|
||||
fn new(dir: &Path) -> Result<ZoneInfoNames, Error> {
|
||||
let names = walk(dir)?;
|
||||
let dir = dir.to_path_buf();
|
||||
let ttl = ZoneInfoNames::DEFAULT_TTL;
|
||||
let expiration = Expiration::after(ttl);
|
||||
let inner = ZoneInfoNamesInner { dir, names, ttl, expiration };
|
||||
Ok(ZoneInfoNames { inner: RwLock::new(inner) })
|
||||
}
|
||||
|
||||
/// Attempts to find the name entry for the given query using a case
|
||||
/// insensitive search.
|
||||
///
|
||||
/// If no match is found and the data is stale, then the time zone names
|
||||
/// are refreshed from the file system before doing another check.
|
||||
fn get(&self, query: &str) -> Option<ZoneInfoName> {
|
||||
{
|
||||
let inner = self.inner.read().unwrap();
|
||||
if let Some(zone_info_name) = inner.get(query) {
|
||||
return Some(zone_info_name);
|
||||
}
|
||||
drop(inner); // unlock
|
||||
}
|
||||
let mut inner = self.inner.write().unwrap();
|
||||
inner.attempt_refresh();
|
||||
inner.get(query)
|
||||
}
|
||||
|
||||
fn reset(&self) {
|
||||
self.inner.write().unwrap().reset();
|
||||
}
|
||||
}
|
||||
|
||||
impl ZoneInfoNamesInner {
|
||||
/// Attempts to find the name entry for the given query using a case
|
||||
/// insensitive search.
|
||||
///
|
||||
/// `None` is returned if one isn't found.
|
||||
fn get(&self, query: &str) -> Option<ZoneInfoName> {
|
||||
self.names
|
||||
.binary_search_by(|n| cmp_ignore_ascii_case(&n.inner.lower, query))
|
||||
.ok()
|
||||
.map(|i| self.names[i].clone())
|
||||
}
|
||||
|
||||
/// Attempts a refresh, but only follows through if the TTL has been
|
||||
/// exceeded.
|
||||
///
|
||||
/// The caller must ensure that the other cache invalidation criteria
|
||||
/// have been upheld. For example, this should only be called for a missed
|
||||
/// zone name lookup.
|
||||
fn attempt_refresh(&mut self) {
|
||||
if self.expiration.is_expired() {
|
||||
self.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/// Forcefully refreshes the cached names with possibly new data from disk.
|
||||
/// If an error occurs when fetching the names, then no names are updated
|
||||
/// (but the `expires_at` is updated). This will also emit a warning log on
|
||||
/// failure.
|
||||
fn refresh(&mut self) {
|
||||
// PERF: Should we try to move this `walk` call to run outside of a
|
||||
// lock? It probably happens pretty rarely, so it might not matter.
|
||||
let result = walk(&self.dir);
|
||||
self.expiration = Expiration::after(self.ttl);
|
||||
match result {
|
||||
Ok(names) => {
|
||||
self.names = names;
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"failed to refresh zoneinfo time zone name cache \
|
||||
for {}: {err}",
|
||||
self.dir.display(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Resets the state such that the next lookup is guaranteed to force a
|
||||
/// cache refresh, and that it is impossible for any data to be stale.
|
||||
fn reset(&mut self) {
|
||||
// This will force the next lookup to fail.
|
||||
self.names.clear();
|
||||
// And this will force the next failed lookup to result in a refresh.
|
||||
self.expiration = Expiration::expired();
|
||||
}
|
||||
}
|
||||
|
||||
/// A single TZif entry in a zoneinfo database directory.
|
||||
#[derive(Clone, Debug)]
|
||||
struct ZoneInfoName {
|
||||
inner: Arc<ZoneInfoNameInner>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct ZoneInfoNameInner {
|
||||
/// A file path resolvable to the corresponding file relative to the
|
||||
/// working directory of this program.
|
||||
///
|
||||
/// Should we canonicalize this to a absolute path? I guess in practice it
|
||||
/// is an absolute path in most cases.
|
||||
full: PathBuf,
|
||||
/// The original name of this time zone taken from the file path with
|
||||
/// no additional changes.
|
||||
original: String,
|
||||
/// The lowercase version of `original`. This is how we determine name
|
||||
/// equality.
|
||||
lower: String,
|
||||
}
|
||||
|
||||
impl ZoneInfoName {
|
||||
/// Create a new time zone info name.
|
||||
///
|
||||
/// `base` should corresponding to the zoneinfo directory from which the
|
||||
/// suffix `time_zone_name` path was returned.
|
||||
fn new(base: &Path, time_zone_name: &Path) -> Result<ZoneInfoName, Error> {
|
||||
let full = base.join(time_zone_name);
|
||||
let original = parse::os_str_utf8(time_zone_name.as_os_str())
|
||||
.map_err(|err| err.path(base))?;
|
||||
let lower = original.to_ascii_lowercase();
|
||||
let inner =
|
||||
ZoneInfoNameInner { full, original: original.to_string(), lower };
|
||||
Ok(ZoneInfoName { inner: Arc::new(inner) })
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ZoneInfoName {}
|
||||
|
||||
impl PartialEq for ZoneInfoName {
|
||||
fn eq(&self, rhs: &ZoneInfoName) -> bool {
|
||||
self.inner.lower == rhs.inner.lower
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for ZoneInfoName {
|
||||
fn cmp(&self, rhs: &ZoneInfoName) -> core::cmp::Ordering {
|
||||
self.inner.lower.cmp(&rhs.inner.lower)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for ZoneInfoName {
|
||||
fn partial_cmp(&self, rhs: &ZoneInfoName) -> Option<core::cmp::Ordering> {
|
||||
Some(self.cmp(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl core::hash::Hash for ZoneInfoName {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.inner.lower.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: I think Leaps should perhaps be an enum which is either a builtin
|
||||
// or something that is updated from the file system. And the RwLock should
|
||||
// only exist in the latter. Otherwise, the builtin should be used. Although,
|
||||
// maybe we want something more flexible, since we might still want to use the
|
||||
// builtin if it's equivalent to what's on disk, since it will likely be faster
|
||||
// since it is forever immutable. So maybe:
|
||||
//
|
||||
// struct Leaps {
|
||||
// builtin: LeapSeconds,
|
||||
// builtin_active: AtomicBool,
|
||||
// fs: RwLock<LeapsFromFile>,
|
||||
// }
|
||||
//
|
||||
// Or something like that.
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Leaps {
|
||||
/// The actual table of leap seconds. This permits Unix<->TAI conversions.
|
||||
leapseconds: LeapSeconds,
|
||||
/// The file path to the specific leap second data file we are using.
|
||||
///
|
||||
/// This is `None` when using builtin leap second data.
|
||||
path: Option<PathBuf>,
|
||||
/// The length of time that we should consider leap second data fresh for.
|
||||
ttl: Duration,
|
||||
/// A point in the future where leap second data should be considered
|
||||
/// potentially stale.
|
||||
expiration: Expiration,
|
||||
/// The last modified time of the file we've read leap second data from.
|
||||
last_modified: Option<Instant>,
|
||||
}
|
||||
|
||||
impl Leaps {
|
||||
const DEFAULT_TTL: Duration = DEFAULT_TTL;
|
||||
|
||||
fn builtin() -> Leaps {
|
||||
let ttl = Duration::MAX;
|
||||
Leaps {
|
||||
leapseconds: LeapSeconds::builtin(),
|
||||
path: None,
|
||||
// builtin leap seconds will never change
|
||||
ttl,
|
||||
expiration: Expiration::after(ttl),
|
||||
last_modified: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn new(dir: &Path) -> Result<Leaps, Error> {
|
||||
// The IANA formatted `leapseconds` seems to be more ubiquitous. e.g.,
|
||||
// My mac and Linux machines both have it, but only my Linux machine
|
||||
// has the NIST formatted `leap-seconds.list`.
|
||||
let tries = [
|
||||
("iana", dir.join("leapseconds")),
|
||||
("nist", dir.join("leap-seconds.list")),
|
||||
];
|
||||
for (parse, path) in tries {
|
||||
match Leaps::from_path(&path) {
|
||||
Ok(leaps) => return Ok(leaps),
|
||||
Err(err) => {
|
||||
debug!(
|
||||
"could not open leap second data file candidate \
|
||||
{}: {err}",
|
||||
path.display(),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err!("could not find leap second data file").path(dir))
|
||||
}
|
||||
|
||||
fn from_path(path: &Path) -> Result<Leaps, Error> {
|
||||
let mut file = File::open(&path).map_err(|e| Error::fs(path, e))?;
|
||||
let mut data = vec![];
|
||||
file.read_to_end(&mut data).map_err(|e| Error::fs(path, e))?;
|
||||
let leapseconds = if path.ends_with("leapseconds") {
|
||||
LeapSeconds::from_iana_bytes(&data).map_err(|e| e.path(path))?
|
||||
} else if path.ends_with("leap-seconds.list") {
|
||||
LeapSeconds::from_nist_bytes(&data).map_err(|e| e.path(path))?
|
||||
} else {
|
||||
return Err(err!(
|
||||
"unrecognized leap second data file format, \
|
||||
expected either `leapseconds` or `leap-seconds.list`",
|
||||
)
|
||||
.path(path));
|
||||
};
|
||||
let last_modified = last_modified_from_file(&path, &file);
|
||||
Ok(Leaps {
|
||||
leapseconds,
|
||||
path: Some(path.to_path_buf()),
|
||||
ttl: Leaps::DEFAULT_TTL,
|
||||
expiration: Expiration::after(Leaps::DEFAULT_TTL),
|
||||
last_modified,
|
||||
})
|
||||
}
|
||||
|
||||
fn revalidate(&mut self) -> bool {
|
||||
// TODO: This can be factored out and shared with time zone
|
||||
// revalidation.
|
||||
|
||||
// No path implies builtin, and builtin is always valid.
|
||||
let Some(ref path) = self.path else { return true };
|
||||
// If we started with no last modified timestamp, then I guess we
|
||||
// should always fail revalidation? I suppose a case could be made to
|
||||
// do the opposite: always pass revalidation.
|
||||
let Some(old_last_modified) = self.last_modified else {
|
||||
info!(
|
||||
"revalidation for {} failed because old last modified time \
|
||||
is unavailable",
|
||||
path.display(),
|
||||
);
|
||||
return false;
|
||||
};
|
||||
let Some(new_last_modified) = last_modified_from_path(path) else {
|
||||
info!(
|
||||
"revalidation for {} failed because new last modified time \
|
||||
is unavailable",
|
||||
path.display(),
|
||||
);
|
||||
return false;
|
||||
};
|
||||
// We consider any change to invalidate cache.
|
||||
if old_last_modified != new_last_modified {
|
||||
info!(
|
||||
"revalidation for {} failed because last modified times \
|
||||
do not match: old = {} != {} = new",
|
||||
path.display(),
|
||||
old_last_modified,
|
||||
new_last_modified,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
trace!(
|
||||
"revalidation for {} succeeded because last modified times \
|
||||
match: old = {} == {} = new",
|
||||
path.display(),
|
||||
old_last_modified,
|
||||
new_last_modified,
|
||||
);
|
||||
self.expiration = Expiration::after(self.ttl);
|
||||
true
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.expiration = Expiration::expired();
|
||||
}
|
||||
}
|
||||
|
||||
/// A little helper for representation expiration time.
|
||||
///
|
||||
/// An overflowing expiration time is treated identically to a time that is
|
||||
/// always expired.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Expiration(Option<MonotonicInstant>);
|
||||
|
||||
impl Expiration {
|
||||
/// Returns an expiration time for which `is_expired` returns true after
|
||||
/// the given duration has elapsed from this instant.
|
||||
fn after(ttl: Duration) -> Expiration {
|
||||
Expiration(MonotonicInstant::now().checked_add(ttl))
|
||||
}
|
||||
|
||||
/// Returns an expiration time for which `is_expired` always returns true.
|
||||
fn expired() -> Expiration {
|
||||
Expiration(None)
|
||||
}
|
||||
|
||||
/// Whether expiration has occurred or not.
|
||||
fn is_expired(self) -> bool {
|
||||
self.0.map_or(true, |t| MonotonicInstant::now() > t)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the last modified time for the given file path as a Jiff Instant.
|
||||
///
|
||||
/// If there was a problem accessing the last modified time or if it could not
|
||||
/// fit in a Jiff instant, then a warning message is logged and `None` is
|
||||
/// returned.
|
||||
fn last_modified_from_path(path: &Path) -> Option<Instant> {
|
||||
let file = match File::open(path) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"failed to open file to get last modified time {}: {err}",
|
||||
path.display(),
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
last_modified_from_file(path, &file)
|
||||
}
|
||||
|
||||
/// Returns the last modified time for the given file as a Jiff Instant.
|
||||
///
|
||||
/// If there was a problem accessing the last modified time or if it could not
|
||||
/// fit in a Jiff instant, then a warning message is logged and `None` is
|
||||
/// returned.
|
||||
///
|
||||
/// The path given should be the path to the given file. It is used for
|
||||
/// diagnostic purposes.
|
||||
fn last_modified_from_file(path: &Path, file: &File) -> Option<Instant> {
|
||||
let md = match file.metadata() {
|
||||
Ok(md) => md,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"failed to get metadata (for last modified time) \
|
||||
for {}: {err}",
|
||||
path.display(),
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let systime = match md.modified() {
|
||||
Ok(systime) => systime,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"failed to get last modified time for {}: {err}",
|
||||
path.display()
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let instant = match Instant::try_from(systime) {
|
||||
Ok(instant) => instant,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"system time {systime:?} out of bounds \
|
||||
for Jiff Instant for last modified time \
|
||||
from {}: {err}",
|
||||
path.display(),
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
Some(instant)
|
||||
}
|
||||
|
||||
/// Recursively walks the given directory and returns the names of all time
|
||||
/// zones found.
|
||||
///
|
||||
/// This is guaranteed to return either one or more time zone names OR an
|
||||
/// error. That is, `Ok(vec![])` is an impossible result.
|
||||
///
|
||||
/// This will attempt to collect as many names as possible, even if some I/O
|
||||
/// operations fail.
|
||||
///
|
||||
/// The names returned are sorted in lexicographic order according to the
|
||||
/// lowercase form of each name.
|
||||
fn walk(start: &Path) -> Result<Vec<ZoneInfoName>, Error> {
|
||||
let mut first_err: Option<Error> = None;
|
||||
let mut seterr = |path: &Path, err: Error| {
|
||||
if first_err.is_none() {
|
||||
first_err = Some(err.path(path));
|
||||
}
|
||||
};
|
||||
|
||||
let mut names = vec![];
|
||||
let mut stack = vec![start.to_path_buf()];
|
||||
while let Some(dir) = stack.pop() {
|
||||
let readdir = match dir.read_dir() {
|
||||
Ok(readdir) => readdir,
|
||||
Err(err) => {
|
||||
info!(
|
||||
"error when reading {} as a directory: {err}",
|
||||
dir.display()
|
||||
);
|
||||
seterr(&dir, Error::io(err));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
for result in readdir {
|
||||
let dent = match result {
|
||||
Ok(dent) => dent,
|
||||
Err(err) => {
|
||||
info!(
|
||||
"error when reading directory entry from {}: {err}",
|
||||
dir.display()
|
||||
);
|
||||
seterr(&dir, Error::io(err));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let file_type = match dent.file_type() {
|
||||
Ok(file_type) => file_type,
|
||||
Err(err) => {
|
||||
let path = dent.path();
|
||||
info!(
|
||||
"error when reading file type from {}: {err}",
|
||||
path.display()
|
||||
);
|
||||
seterr(&path, Error::io(err));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let path = dent.path();
|
||||
if file_type.is_dir() {
|
||||
stack.push(path);
|
||||
continue;
|
||||
}
|
||||
// We assume symlinks are files, although this may not be
|
||||
// appropriate. If we need to also handle the case when they're
|
||||
// directories, then we'll need to add symlink loop detection.
|
||||
//
|
||||
// Otherwise, at this point, we peek at the first few bytes of a
|
||||
// file to do a low false positive and never false negative check
|
||||
// for a TZif file.
|
||||
|
||||
let mut f = match File::open(&path) {
|
||||
Ok(f) => f,
|
||||
Err(err) => {
|
||||
info!("failed to open {}: {err}", path.display());
|
||||
seterr(&path, Error::io(err));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let mut buf = [0; 4];
|
||||
if let Err(err) = f.read_exact(&mut buf) {
|
||||
info!(
|
||||
"failed to read first 4 bytes of {}: {err}",
|
||||
path.display()
|
||||
);
|
||||
seterr(&path, Error::io(err));
|
||||
continue;
|
||||
}
|
||||
if !is_possibly_tzif(&buf) {
|
||||
// This is a trace because it's perfectly normal for a
|
||||
// non-TZif file to be in a zoneinfo directory. But it could
|
||||
// still be potentially useful debugging info.
|
||||
trace!(
|
||||
"found file {} that isn't TZif since its first \
|
||||
four bytes are {:?}",
|
||||
path.display(),
|
||||
Bytes(&buf),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
let time_zone_name = match path.strip_prefix(start) {
|
||||
Ok(time_zone_name) => time_zone_name,
|
||||
Err(err) => {
|
||||
info!(
|
||||
"failed to extract time zone name from {} \
|
||||
using {} as a base: {err}",
|
||||
path.display(),
|
||||
start.display(),
|
||||
);
|
||||
// FIXME: Set an `Error` here instead.
|
||||
seterr(&path, Error::adhoc(err.to_string()));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let zone_info_name =
|
||||
match ZoneInfoName::new(&start, time_zone_name) {
|
||||
Ok(zone_info_name) => zone_info_name,
|
||||
Err(err) => {
|
||||
seterr(&path, err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
names.push(zone_info_name);
|
||||
}
|
||||
}
|
||||
if names.is_empty() {
|
||||
let err = first_err
|
||||
.take()
|
||||
.unwrap_or_else(|| err!("{}: no TZif files", start.display()));
|
||||
Err(err)
|
||||
} else {
|
||||
// If we found at least one valid name, then we declare success and
|
||||
// drop any error we might have found. They do all get logged above
|
||||
// though.
|
||||
names.sort();
|
||||
Ok(names)
|
||||
}
|
||||
}
|
||||
|
||||
/// Like std's `eq_ignore_ascii_case`, but returns a full `Ordering`.
|
||||
fn cmp_ignore_ascii_case(s1: &str, s2: &str) -> core::cmp::Ordering {
|
||||
let it1 = s1.as_bytes().iter().map(|&b| b.to_ascii_lowercase());
|
||||
let it2 = s2.as_bytes().iter().map(|&b| b.to_ascii_lowercase());
|
||||
it1.cmp(it2)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// DEBUG COMMAND
|
||||
///
|
||||
/// Takes environment variable `JIFF_DEBUG_ZONEINFO_DIR` as input and
|
||||
/// prints a list of all time zone names in the directory (one per line).
|
||||
///
|
||||
/// Callers may also set `RUST_LOG` to get extra debugging output.
|
||||
#[test]
|
||||
fn debug_zoneinfo_walk() -> anyhow::Result<()> {
|
||||
use anyhow::Context;
|
||||
|
||||
let _ = env_logger::try_init();
|
||||
|
||||
const ENV: &str = "JIFF_DEBUG_ZONEINFO_DIR";
|
||||
let Some(val) = std::env::var_os(ENV) else { return Ok(()) };
|
||||
let dir = PathBuf::from(val);
|
||||
let names = walk(&dir)?;
|
||||
for n in names {
|
||||
std::eprintln!("{}", n.inner.original);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
1455
src/tz/mod.rs
Normal file
1455
src/tz/mod.rs
Normal file
File diff suppressed because it is too large
Load diff
893
src/tz/offset.rs
Normal file
893
src/tz/offset.rs
Normal file
|
|
@ -0,0 +1,893 @@
|
|||
use core::ops::{Add, AddAssign, Neg, Sub, SubAssign};
|
||||
|
||||
use crate::{
|
||||
civil::DateTime,
|
||||
error::Error,
|
||||
instant::{Instant, TimeScale, Unix},
|
||||
span::{Span, TimeDuration},
|
||||
util::{
|
||||
rangeint::{RFrom, RInto, TryRFrom},
|
||||
t::{self, C},
|
||||
},
|
||||
};
|
||||
|
||||
/// An enum indicating whether a particular datetime or instant is in DST or
|
||||
/// not.
|
||||
///
|
||||
/// DST stands for "daylight savings time." It is a label used to apply to
|
||||
/// points in time as a way to contrast it with "standard time." DST is
|
||||
/// usually, but not always, one hour ahead of standard time. When DST takes
|
||||
/// effect is usually determined by governments, and the rules can vary
|
||||
/// depending on the location. DST is typically used as a means to maximize
|
||||
/// "sunlight" time during typical working hours, and as a cost cutting measure
|
||||
/// by reducing energy consumption. (The effectiveness of DST and whether it
|
||||
/// is overall worth it is a separate question entirely.)
|
||||
///
|
||||
/// In general, most users should never need to deal with this type. But it can
|
||||
/// be occasionally useful in circumstances where callers need to know whether
|
||||
/// DST is active or not for a particular point in time.
|
||||
///
|
||||
/// This type has a `From<bool>` trait implementation, where the bool is
|
||||
/// interpreted as being `true` when DST is active.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Dst {
|
||||
/// DST is not in effect. In other words, standard time is in effect.
|
||||
No,
|
||||
/// DST is in effect.
|
||||
Yes,
|
||||
}
|
||||
|
||||
impl Dst {
|
||||
/// Returns true when this value is equal to `Dst::Yes`.
|
||||
pub fn is_dst(self) -> bool {
|
||||
matches!(self, Dst::Yes)
|
||||
}
|
||||
|
||||
/// Returns true when this value is equal to `Dst::No`.
|
||||
///
|
||||
/// `std` in this context refers to "standard time." That is, it is the
|
||||
/// offset from UTC used when DST is not in effect.
|
||||
pub fn is_std(self) -> bool {
|
||||
matches!(self, Dst::No)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Dst {
|
||||
fn from(is_dst: bool) -> Dst {
|
||||
if is_dst {
|
||||
Dst::Yes
|
||||
} else {
|
||||
Dst::No
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a fixed time zone offset.
|
||||
///
|
||||
/// Negative offsets correspond to time zones west of the prime meridian, while
|
||||
/// positive offsets correspond to time zones east of the prime meridian.
|
||||
/// Equivalently, in all cases, `civil-time - offset = UTC`.
|
||||
///
|
||||
/// # Display format
|
||||
///
|
||||
/// This type implements the `std::fmt::Display` trait. It
|
||||
/// will convert the offset to a string format in the form
|
||||
/// `{sign}{hours}[:{minutes}[:{seconds}]]`, where `minutes` and `seconds` are
|
||||
/// only present when non-zero. For example:
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::tz::Offset;
|
||||
///
|
||||
/// let o = Offset::constant(-5);
|
||||
/// assert_eq!(o.to_string(), "-05");
|
||||
/// let o = Offset::constant_seconds(-18_000);
|
||||
/// assert_eq!(o.to_string(), "-05");
|
||||
/// let o = Offset::constant_seconds(-18_060);
|
||||
/// assert_eq!(o.to_string(), "-05:01");
|
||||
/// let o = Offset::constant_seconds(-18_062);
|
||||
/// assert_eq!(o.to_string(), "-05:01:02");
|
||||
///
|
||||
/// // The min value.
|
||||
/// let o = Offset::constant_seconds(-93_599);
|
||||
/// assert_eq!(o.to_string(), "-25:59:59");
|
||||
/// // The max value.
|
||||
/// let o = Offset::constant_seconds(93_599);
|
||||
/// assert_eq!(o.to_string(), "+25:59:59");
|
||||
/// // No offset.
|
||||
/// let o = Offset::constant(0);
|
||||
/// assert_eq!(o.to_string(), "+00");
|
||||
/// ```
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// TODO: Write some examples here using them with real times.
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub struct Offset {
|
||||
span: t::SpanZoneOffset,
|
||||
}
|
||||
|
||||
impl Offset {
|
||||
/// The minimum possible time zone offset.
|
||||
///
|
||||
/// This corresponds to the offset `-25:59:59`.
|
||||
pub const MIN: Offset = Offset { span: t::SpanZoneOffset::MIN_SELF };
|
||||
|
||||
/// The maximum possible time zone offset.
|
||||
///
|
||||
/// This corresponds to the offset `25:59:59`.
|
||||
pub const MAX: Offset = Offset { span: t::SpanZoneOffset::MAX_SELF };
|
||||
|
||||
/// The offset corresponding to UTC. That is, no offset at all.
|
||||
///
|
||||
/// This is defined to always be equivalent to `Offset::ZERO`, but it is
|
||||
/// semantically distinct. This ought to be used when UTC is desired
|
||||
/// specifically, while `Offset::ZERO` ought to be used when one wants to
|
||||
/// express "no offset." For example, when adding offsets, `Offset::ZERO`
|
||||
/// corresponds to the identity.
|
||||
pub const UTC: Offset = Offset::ZERO;
|
||||
|
||||
/// The offset corresponding to no offset at all.
|
||||
///
|
||||
/// This is defined to always be equivalent to `Offset::UTC`, but it is
|
||||
/// semantically distinct. This ought to be used when a zero offset is
|
||||
/// desired specifically, while `Offset::UTC` ought to be used when one
|
||||
/// wants to express UTC. For example, when adding offsets, `Offset::ZERO`
|
||||
/// corresponds to the identity.
|
||||
pub const ZERO: Offset = Offset::constant(0);
|
||||
|
||||
/// Creates a new time zone offset in a `const` context from a given number
|
||||
/// of hours.
|
||||
///
|
||||
/// Negative offsets correspond to time zones west of the prime meridian,
|
||||
/// while positive offsets correspond to time zones east of the prime
|
||||
/// meridian. Equivalently, in all cases, `civil-time - offset = UTC`.
|
||||
///
|
||||
/// The fallible non-const version of this constructor is [`Offset::new`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This routine panics when the given number of hours is out of range.
|
||||
/// Namely, `hours` must be in the range `-25..=25`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::tz::Offset;
|
||||
///
|
||||
/// let o = Offset::constant(-5);
|
||||
/// assert_eq!(o.seconds(), -18_000);
|
||||
/// let o = Offset::constant(5);
|
||||
/// assert_eq!(o.seconds(), 18_000);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub const fn constant(hours: i8) -> Offset {
|
||||
if !t::SpanZoneOffsetHours::contains(hours) {
|
||||
panic!("invalid time zone offset hours")
|
||||
}
|
||||
Offset::constant_seconds((hours as i32) * 60 * 60)
|
||||
}
|
||||
|
||||
/// Creates a new time zone offset in a `const` context from a given number
|
||||
/// of seconds.
|
||||
///
|
||||
/// Negative offsets correspond to time zones west of the prime meridian,
|
||||
/// while positive offsets correspond to time zones east of the prime
|
||||
/// meridian. Equivalently, in all cases, `civil-time - offset = UTC`.
|
||||
///
|
||||
/// The fallible non-const version of this constructor is
|
||||
/// [`Offset::new_seconds`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This routine panics when the given number of seconds is out of range.
|
||||
/// The range corresponds to the offsets `-25:59:59..=25:59:59`. In units
|
||||
/// of seconds, that corresponds to `-93,599..=93,599`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::tz::Offset;
|
||||
///
|
||||
/// let o = Offset::constant_seconds(-18_000);
|
||||
/// assert_eq!(o.seconds(), -18_000);
|
||||
/// let o = Offset::constant_seconds(18_000);
|
||||
/// assert_eq!(o.seconds(), 18_000);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub const fn constant_seconds(seconds: i32) -> Offset {
|
||||
if !t::SpanZoneOffset::contains(seconds) {
|
||||
panic!("invalid time zone offset seconds")
|
||||
}
|
||||
Offset { span: t::SpanZoneOffset::new_unchecked(seconds) }
|
||||
}
|
||||
|
||||
/// Creates a new time zone offset from a given number of hours.
|
||||
///
|
||||
/// Negative offsets correspond to time zones west of the prime meridian,
|
||||
/// while positive offsets correspond to time zones east of the prime
|
||||
/// meridian. Equivalently, in all cases, `civil-time - offset = UTC`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This routine returns an error when the given number of hours is out of
|
||||
/// range. Namely, `hours` must be in the range `-25..=25`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::tz::Offset;
|
||||
///
|
||||
/// let o = Offset::new(-5)?;
|
||||
/// assert_eq!(o.seconds(), -18_000);
|
||||
/// let o = Offset::new(5)?;
|
||||
/// assert_eq!(o.seconds(), 18_000);
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn new(hours: i8) -> Result<Offset, Error> {
|
||||
let hours = t::SpanZoneOffsetHours::try_new("offset-hours", hours)?;
|
||||
Ok(Offset::new_ranged(hours))
|
||||
}
|
||||
|
||||
/// Creates a new time zone offset in a `const` context from a given number
|
||||
/// of seconds.
|
||||
///
|
||||
/// Negative offsets correspond to time zones west of the prime meridian,
|
||||
/// while positive offsets correspond to time zones east of the prime
|
||||
/// meridian. Equivalently, in all cases, `civil-time - offset = UTC`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This routine returns an error when the given number of seconds is out
|
||||
/// of range. The range corresponds to the offsets `-25:59:59..=25:59:59`.
|
||||
/// In units of seconds, that corresponds to `-93,599..=93,599`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::tz::Offset;
|
||||
///
|
||||
/// let o = Offset::new_seconds(-18_000)?;
|
||||
/// assert_eq!(o.seconds(), -18_000);
|
||||
/// let o = Offset::new_seconds(18_000)?;
|
||||
/// assert_eq!(o.seconds(), 18_000);
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn new_seconds(seconds: i32) -> Result<Offset, Error> {
|
||||
let seconds = t::SpanZoneOffset::try_new("offset-seconds", seconds)?;
|
||||
Ok(Offset::new_seconds_ranged(seconds))
|
||||
}
|
||||
|
||||
/// Returns the total number of seconds in this offset.
|
||||
///
|
||||
/// The value returned is guaranteed to represent an offset in the range
|
||||
/// `-25:59:59..=25:59:59`. Or more precisely, the value will be in units
|
||||
/// of seconds in the range `-93,599..=93,599`.
|
||||
///
|
||||
/// Negative offsets correspond to time zones west of the prime meridian,
|
||||
/// while positive offsets correspond to time zones east of the prime
|
||||
/// meridian. Equivalently, in all cases, `civil-time - offset = UTC`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::tz::Offset;
|
||||
///
|
||||
/// let o = Offset::constant(-5);
|
||||
/// assert_eq!(o.seconds(), -18_000);
|
||||
/// let o = Offset::constant(5);
|
||||
/// assert_eq!(o.seconds(), 18_000);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn seconds(self) -> i32 {
|
||||
self.seconds_ranged().get()
|
||||
}
|
||||
|
||||
/// Returns the negation of this offset.
|
||||
///
|
||||
/// A negative offset will become positive and vice versa. This is a no-op
|
||||
/// if the offset is zero.
|
||||
///
|
||||
/// This never panics.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::tz::Offset;
|
||||
///
|
||||
/// assert_eq!(Offset::constant(-5).negate(), Offset::constant(5));
|
||||
/// // It's also available via the `-` operator:
|
||||
/// assert_eq!(-Offset::constant(-5), Offset::constant(5));
|
||||
/// ```
|
||||
pub fn negate(self) -> Offset {
|
||||
Offset { span: -self.span }
|
||||
}
|
||||
|
||||
/// Returns true if and only if this offset is less than zero.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::tz::Offset;
|
||||
///
|
||||
/// assert!(!Offset::constant(5).is_negative());
|
||||
/// assert!(!Offset::constant(0).is_negative());
|
||||
/// assert!(Offset::constant(-5).is_negative());
|
||||
/// ```
|
||||
pub fn is_negative(self) -> bool {
|
||||
self.seconds_ranged() < 0
|
||||
}
|
||||
|
||||
/// Converts the given instant to a civil datetime using this offset.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{civil::DateTime, tz::Offset, Instant};
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// Offset::constant(-8).to_datetime(Instant::UNIX_EPOCH),
|
||||
/// DateTime::constant(1969, 12, 31, 16, 0, 0, 0),
|
||||
/// );
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn to_datetime<S: TimeScale>(self, instant: Instant<S>) -> DateTime {
|
||||
instant.to_datetime_with_offset(self)
|
||||
}
|
||||
|
||||
/// Converts the given civil datetime to an instant using this offset.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This returns an error if this would have returned an instant outside
|
||||
/// of its minimum and maximum values.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// This example shows how to find the instant corresponding to
|
||||
/// `1969-12-31T16:00:00-08`.
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{civil::DateTime, tz::Offset, Instant};
|
||||
///
|
||||
/// let dt = DateTime::constant(1969, 12, 31, 16, 0, 0, 0);
|
||||
/// assert_eq!(
|
||||
/// Offset::constant(-8).to_instant(dt).unwrap(),
|
||||
/// Instant::UNIX_EPOCH,
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// This example shows some maximum boundary conditions where this routine
|
||||
/// will fail:
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{civil::DateTime, tz::Offset, Instant, ToSpan};
|
||||
///
|
||||
/// let dt = DateTime::constant(9999, 12, 31, 23, 0, 0, 0);
|
||||
/// assert!(Offset::constant(-8).to_instant(dt).is_err());
|
||||
///
|
||||
/// // If the offset is big enough, then converting it to a UTC
|
||||
/// // instant will fit, even when using the maximum civil datetime.
|
||||
/// let dt = DateTime::constant(9999, 12, 31, 23, 59, 59, 999_999_999);
|
||||
/// assert_eq!(Offset::MAX.to_instant(dt).unwrap(), Instant::MAX);
|
||||
/// // But adjust the offset down 1 second is enough to go out-of-bounds.
|
||||
/// assert!((Offset::MAX - 1.seconds()).to_instant(dt).is_err());
|
||||
/// ```
|
||||
///
|
||||
/// Same as above, but for minimum values:
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{civil::DateTime, tz::Offset, Instant, ToSpan};
|
||||
///
|
||||
/// let dt = DateTime::constant(-9999, 1, 1, 1, 0, 0, 0);
|
||||
/// assert!(Offset::constant(8).to_instant(dt).is_err());
|
||||
///
|
||||
/// // If the offset is small enough, then converting it to a UTC
|
||||
/// // instant will fit, even when using the minimum civil datetime.
|
||||
/// let dt = DateTime::constant(-9999, 1, 1, 0, 0, 0, 0);
|
||||
/// assert_eq!(Offset::MIN.to_instant(dt).unwrap(), Instant::MIN);
|
||||
/// // But adjust the offset up 1 second is enough to go out-of-bounds.
|
||||
/// assert!((Offset::MIN + 1.seconds()).to_instant(dt).is_err());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn to_instant(self, dt: DateTime) -> Result<Instant, Error> {
|
||||
self.to_instant_with_scale(dt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_instant_with_scale<S: TimeScale>(
|
||||
self,
|
||||
dt: DateTime,
|
||||
) -> Result<Instant<S>, Error> {
|
||||
Instant::from_datetime_zulu_ranged(dt)?.checked_sub(self.to_span())
|
||||
}
|
||||
|
||||
/// Returns the span of time since the other offset given from this offset.
|
||||
///
|
||||
/// When the `other` is more east (i.e., more positive) of the prime
|
||||
/// meridian than this offset, then the span returned will be negative.
|
||||
///
|
||||
/// # Properties
|
||||
///
|
||||
/// Adding the span returned to the `other` offset will always equal this
|
||||
/// offset.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{tz::Offset, ToSpan};
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// Offset::UTC.since(Offset::constant(-5)),
|
||||
/// (5 * 60 * 60).seconds(),
|
||||
/// );
|
||||
/// // Flipping the operands in this case results in a negative span.
|
||||
/// assert_eq!(
|
||||
/// Offset::constant(-5).since(Offset::UTC),
|
||||
/// -(5 * 60 * 60).seconds(),
|
||||
/// );
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn since(self, other: Offset) -> Span {
|
||||
self.until(other).negate()
|
||||
}
|
||||
|
||||
/// Returns the span of time from this offset until the other given.
|
||||
///
|
||||
/// When the `other` offset is more west (i.e., more negative) of the prime
|
||||
/// meridian than this offset, then the span returned will be negative.
|
||||
///
|
||||
/// # Properties
|
||||
///
|
||||
/// Adding the span returned to this offset will always equal the `other`
|
||||
/// offset given.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{tz::Offset, ToSpan};
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// Offset::constant(-5).until(Offset::UTC),
|
||||
/// (5 * 60 * 60).seconds(),
|
||||
/// );
|
||||
/// // Flipping the operands in this case results in a negative span.
|
||||
/// assert_eq!(
|
||||
/// Offset::UTC.until(Offset::constant(-5)),
|
||||
/// -(5 * 60 * 60).seconds(),
|
||||
/// );
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn until(self, other: Offset) -> Span {
|
||||
Span::new()
|
||||
.seconds_ranged(other.seconds_ranged() - self.seconds_ranged())
|
||||
}
|
||||
|
||||
/// Adds the given span of time to this offset.
|
||||
///
|
||||
/// Since time zone offsets have second resolution, any fractional seconds
|
||||
/// in the span given are ignored.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This returns an error if the result of adding the given span would
|
||||
/// exceed the minimum or maximum allowed `Offset` value.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// This example shows how to add one hour to an offset (if the offset
|
||||
/// corresponds to standard time, then adding an hour will usually give
|
||||
/// you DST time):
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{tz::Offset, ToSpan};
|
||||
///
|
||||
/// let off = Offset::constant(-5);
|
||||
/// assert_eq!(off.checked_add(1.hours()).unwrap(), Offset::constant(-4));
|
||||
/// ```
|
||||
///
|
||||
/// While unusual, adding a full day to an offset is allowed as long as it
|
||||
/// doesn't overflow.
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{tz::Offset, ToSpan};
|
||||
///
|
||||
/// let off = Offset::constant(-5);
|
||||
///
|
||||
/// assert_eq!(off.checked_add(1.days()).unwrap(), Offset::constant(19));
|
||||
/// // Adding 1 day is always the same as adding 24 hours.
|
||||
/// assert_eq!(off.checked_add(24.hours()).unwrap(), Offset::constant(19));
|
||||
/// ```
|
||||
///
|
||||
/// And note that while fractional seconds are ignored, units less than
|
||||
/// seconds aren't ignored if they sum up to a duration at least as big
|
||||
/// as one second:
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{tz::Offset, ToSpan};
|
||||
///
|
||||
/// let off = Offset::constant(5);
|
||||
/// let span = 900.milliseconds()
|
||||
/// .microseconds(50_000)
|
||||
/// .nanoseconds(50_000_000);
|
||||
/// assert_eq!(
|
||||
/// off.checked_add(span).unwrap(),
|
||||
/// Offset::constant_seconds((5 * 60 * 60) + 1),
|
||||
/// );
|
||||
/// // Any leftover fractional part is ignored.
|
||||
/// let span = 901.milliseconds()
|
||||
/// .microseconds(50_001)
|
||||
/// .nanoseconds(50_000_001);
|
||||
/// assert_eq!(
|
||||
/// off.checked_add(span).unwrap(),
|
||||
/// Offset::constant_seconds((5 * 60 * 60) + 1),
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// This example shows some cases where checked addition will fail.
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{tz::Offset, ToSpan};
|
||||
///
|
||||
/// // Adding units above 'day' always results in an error.
|
||||
/// assert!(Offset::UTC.checked_add(1.weeks()).is_err());
|
||||
/// assert!(Offset::UTC.checked_add(1.months()).is_err());
|
||||
/// assert!(Offset::UTC.checked_add(1.years()).is_err());
|
||||
///
|
||||
/// // Adding even 1 second to the max, or subtracting 1 from the min,
|
||||
/// // will result in overflow and thus an error will be returned.
|
||||
/// assert!(Offset::MIN.checked_add(-1.seconds()).is_err());
|
||||
/// assert!(Offset::MAX.checked_add(1.seconds()).is_err());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn checked_add(self, span: Span) -> Result<Offset, Error> {
|
||||
let td = span.time_civil_day_parts_to_duration()?;
|
||||
// A non-zero number of weeks will always lead to overflow, but I found
|
||||
// it clearer to just do the math here and let it bubble an error.
|
||||
let span_weeks = span
|
||||
.get_weeks_ranged()
|
||||
.try_checked_mul("weeks-as-seconds", t::SECONDS_PER_CIVIL_WEEK)?;
|
||||
let span_days = span
|
||||
.get_days_ranged()
|
||||
.try_checked_mul("days-as-seconds", t::SECONDS_PER_CIVIL_DAY)?;
|
||||
let span_seconds =
|
||||
t::SpanZoneOffset::try_rfrom("span-as-seconds", td.seconds())?
|
||||
.try_checked_add("weeks", span_weeks)?
|
||||
.try_checked_add("days", span_days)?;
|
||||
let seconds = self
|
||||
.seconds_ranged()
|
||||
.try_checked_add("offset-as-seconds", span_seconds)?;
|
||||
Ok(Offset::new_seconds_ranged(seconds))
|
||||
}
|
||||
|
||||
/// Subtracts the given span of time from this offset.
|
||||
///
|
||||
/// Since time zone offsets have second resolution, any fractional seconds
|
||||
/// in the span given are ignored.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This returns an error if the result of subtracting the given span would
|
||||
/// exceed the minimum or maximum allowed `Offset` value.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// This example shows how to subtract one hour to an offset (if the offset
|
||||
/// corresponds to DST, then subtracting an hour will usually give you
|
||||
/// standard time):
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{tz::Offset, ToSpan};
|
||||
///
|
||||
/// let off = Offset::constant(-4);
|
||||
/// assert_eq!(off.checked_sub(1.hours()).unwrap(), Offset::constant(-5));
|
||||
/// ```
|
||||
///
|
||||
/// While unusual, subtracting a full day from an offset is allowed as long
|
||||
/// as it doesn't overflow.
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{tz::Offset, ToSpan};
|
||||
///
|
||||
/// let off = Offset::constant(5);
|
||||
///
|
||||
/// assert_eq!(off.checked_sub(1.days()).unwrap(), Offset::constant(-19));
|
||||
/// // Subtracting 1 day is always the same as subtracting 24 hours.
|
||||
/// assert_eq!(off.checked_sub(24.hours()).unwrap(), Offset::constant(-19));
|
||||
/// ```
|
||||
///
|
||||
/// And note that while fractional seconds are ignored, units less than
|
||||
/// seconds aren't ignored if they sum up to a duration at least as big
|
||||
/// as one second:
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{tz::Offset, ToSpan};
|
||||
///
|
||||
/// let off = Offset::constant(5);
|
||||
/// let span = 900.milliseconds()
|
||||
/// .microseconds(50_000)
|
||||
/// .nanoseconds(50_000_000);
|
||||
/// assert_eq!(
|
||||
/// off.checked_sub(span).unwrap(),
|
||||
/// Offset::constant_seconds((5 * 60 * 60) - 1),
|
||||
/// );
|
||||
/// // Any leftover fractional part is ignored.
|
||||
/// let span = 901.milliseconds()
|
||||
/// .microseconds(50_001)
|
||||
/// .nanoseconds(50_000_001);
|
||||
/// assert_eq!(
|
||||
/// off.checked_sub(span).unwrap(),
|
||||
/// Offset::constant_seconds((5 * 60 * 60) - 1),
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// This example shows some cases where checked subtraction will fail.
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{tz::Offset, ToSpan};
|
||||
///
|
||||
/// // Subtracting units above 'day' always results in an error.
|
||||
/// assert!(Offset::UTC.checked_sub(1.weeks()).is_err());
|
||||
/// assert!(Offset::UTC.checked_sub(1.months()).is_err());
|
||||
/// assert!(Offset::UTC.checked_sub(1.years()).is_err());
|
||||
///
|
||||
/// // Adding even 1 second to the max, or subtracting 1 from the min,
|
||||
/// // will result in overflow and thus an error will be returned.
|
||||
/// assert!(Offset::MIN.checked_sub(1.seconds()).is_err());
|
||||
/// assert!(Offset::MAX.checked_sub(-1.seconds()).is_err());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn checked_sub(self, span: Span) -> Result<Offset, Error> {
|
||||
self.checked_add(span.negate())
|
||||
}
|
||||
|
||||
/// Adds the given span of time to this offset, saturating on overflow.
|
||||
///
|
||||
/// Since time zone offsets have second resolution, any fractional seconds
|
||||
/// in the span given are ignored.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// This example shows some cases where saturation will occur.
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{tz::Offset, ToSpan};
|
||||
///
|
||||
/// // Adding units above 'day' always results in saturation.
|
||||
/// assert_eq!(Offset::UTC.saturating_add(1.weeks()), Offset::MAX);
|
||||
/// assert_eq!(Offset::UTC.saturating_add(1.months()), Offset::MAX);
|
||||
/// assert_eq!(Offset::UTC.saturating_add(1.years()), Offset::MAX);
|
||||
///
|
||||
/// // Adding even 1 second to the max, or subtracting 1 from the min,
|
||||
/// // will result in saturationg.
|
||||
/// assert_eq!(Offset::MIN.saturating_add(-1.seconds()), Offset::MIN);
|
||||
/// assert_eq!(Offset::MAX.saturating_add(1.seconds()), Offset::MAX);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn saturating_add(self, span: Span) -> Offset {
|
||||
self.checked_add(span).unwrap_or_else(|_| {
|
||||
if span.is_negative() {
|
||||
Offset::MIN
|
||||
} else {
|
||||
Offset::MAX
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Subtracts the given span of time from this offset, saturating on
|
||||
/// overflow.
|
||||
///
|
||||
/// Since time zone offsets have second resolution, any fractional seconds
|
||||
/// in the span given are ignored.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// This example shows some cases where saturation will occur.
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{tz::Offset, ToSpan};
|
||||
///
|
||||
/// // Adding units above 'day' always results in saturation.
|
||||
/// assert_eq!(Offset::UTC.saturating_sub(1.weeks()), Offset::MIN);
|
||||
/// assert_eq!(Offset::UTC.saturating_sub(1.months()), Offset::MIN);
|
||||
/// assert_eq!(Offset::UTC.saturating_sub(1.years()), Offset::MIN);
|
||||
///
|
||||
/// // Adding even 1 second to the max, or subtracting 1 from the min,
|
||||
/// // will result in saturationg.
|
||||
/// assert_eq!(Offset::MIN.saturating_sub(1.seconds()), Offset::MIN);
|
||||
/// assert_eq!(Offset::MAX.saturating_sub(-1.seconds()), Offset::MAX);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn saturating_sub(self, span: Span) -> Offset {
|
||||
self.saturating_add(span.negate())
|
||||
}
|
||||
|
||||
/// Returns this offset as a [`Span`].
|
||||
#[inline]
|
||||
pub(crate) fn to_span(self) -> Span {
|
||||
Span::new().seconds_ranged(self.seconds_ranged())
|
||||
}
|
||||
|
||||
/// Returns this offset as a [`TimeDuration`].
|
||||
#[inline]
|
||||
pub(crate) fn to_time_duration(self) -> TimeDuration {
|
||||
TimeDuration::new(self.seconds_ranged(), C(0))
|
||||
}
|
||||
}
|
||||
|
||||
impl Offset {
|
||||
/// This creates an `Offset` via hours/minutes/seconds components.
|
||||
///
|
||||
/// Currently, it exists because it's convenient for use in tests.
|
||||
///
|
||||
/// I originally wanted to expose this in the public API, but I couldn't
|
||||
/// decide on how I wanted to treat signedness. There are a variety of
|
||||
/// choices:
|
||||
///
|
||||
/// * Require all values to be positive, and ask the caller to use
|
||||
/// `-offset` to negate it.
|
||||
/// * Require all values to have the same sign. If any differs, either
|
||||
/// panic or return an error.
|
||||
/// * If any have a negative sign, then behave as if all have a negative
|
||||
/// sign.
|
||||
/// * Permit any combination of sign and combine them correctly. Similar
|
||||
/// to how `TimeDuration::new(-1s, 1ns)` is turned into `-999,999,999ns`.
|
||||
///
|
||||
/// I think the last option is probably the right behavior, but also the
|
||||
/// most annoying to implement. But if someone wants to take a crack at it,
|
||||
/// a PR is welcome.
|
||||
#[cfg(test)]
|
||||
#[inline]
|
||||
pub(crate) const fn hms(hours: i8, minutes: i8, seconds: i8) -> Offset {
|
||||
let total = (hours as i32 * 60 * 60)
|
||||
+ (minutes as i32 * 60)
|
||||
+ (seconds as i32);
|
||||
Offset { span: t::SpanZoneOffset::new_unchecked(total) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn new_ranged(
|
||||
hours: impl RInto<t::SpanZoneOffsetHours>,
|
||||
) -> Offset {
|
||||
let hours: t::SpanZoneOffset = hours.rinto().rinto();
|
||||
Offset::new_seconds_ranged(hours * t::SECONDS_PER_HOUR)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn new_seconds_ranged(
|
||||
seconds: impl RInto<t::SpanZoneOffset>,
|
||||
) -> Offset {
|
||||
Offset { span: seconds.rinto() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn seconds_ranged(self) -> t::SpanZoneOffset {
|
||||
self.span
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn part_hours_ranged(self) -> t::SpanZoneOffsetHours {
|
||||
self.span.div_ceil(t::SECONDS_PER_HOUR).rinto()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn part_minutes_ranged(self) -> t::SpanZoneOffsetMinutes {
|
||||
self.span
|
||||
.div_ceil(t::SECONDS_PER_MINUTE)
|
||||
.rem_ceil(t::MINUTES_PER_HOUR)
|
||||
.rinto()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn part_seconds_ranged(self) -> t::SpanZoneOffsetSeconds {
|
||||
self.span.rem_ceil(t::SECONDS_PER_MINUTE).rinto()
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for Offset {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
let sign = if self.seconds_ranged() < 0 { "-" } else { "" };
|
||||
write!(
|
||||
f,
|
||||
"Offset({sign}{:02}:{:02}:{:02})",
|
||||
self.part_hours_ranged().abs(),
|
||||
self.part_minutes_ranged().abs(),
|
||||
self.part_seconds_ranged().abs(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for Offset {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
let sign = if self.span < 0 { "-" } else { "+" };
|
||||
let hours = self.part_hours_ranged().abs().get();
|
||||
let minutes = self.part_minutes_ranged().abs().get();
|
||||
let seconds = self.part_seconds_ranged().abs().get();
|
||||
if hours == 0 && minutes == 0 && seconds == 0 {
|
||||
write!(f, "+00")
|
||||
} else if hours != 0 && minutes == 0 && seconds == 0 {
|
||||
write!(f, "{sign}{hours:02}")
|
||||
} else if minutes != 0 && seconds == 0 {
|
||||
write!(f, "{sign}{hours:02}:{minutes:02}")
|
||||
} else {
|
||||
write!(f, "{sign}{hours:02}:{minutes:02}:{seconds:02}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a span of time to an offset. This panics on overflow.
|
||||
///
|
||||
/// For checked arithmetic, see [`Offset::checked_add`].
|
||||
impl Add<Span> for Offset {
|
||||
type Output = Offset;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: Span) -> Offset {
|
||||
self.checked_add(rhs)
|
||||
.expect("adding span to offset should not overflow")
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a span of time to an offset in place. This panics on overflow.
|
||||
///
|
||||
/// For checked arithmetic, see [`Offset::checked_add`].
|
||||
impl AddAssign<Span> for Offset {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: Span) {
|
||||
*self = self.add(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
/// Subtracts a span of time from an offset. This panics on overflow.
|
||||
///
|
||||
/// For checked arithmetic, see [`Offset::checked_sub`].
|
||||
impl Sub<Span> for Offset {
|
||||
type Output = Offset;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Span) -> Offset {
|
||||
self.checked_sub(rhs)
|
||||
.expect("subtracting span from offsetsshould not overflow")
|
||||
}
|
||||
}
|
||||
|
||||
/// Subtracts a span of time from an offset in place. This panics on overflow.
|
||||
///
|
||||
/// For checked arithmetic, see [`Offset::checked_sub`].
|
||||
impl SubAssign<Span> for Offset {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: Span) {
|
||||
*self = self.sub(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the span of time between two offsets.
|
||||
///
|
||||
/// This will return a negative span when the offset being subtracted is
|
||||
/// greater (i.e., more east with respect to the prime meridian).
|
||||
impl Sub for Offset {
|
||||
type Output = Span;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Offset) -> Span {
|
||||
self.since(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
/// Negate this offset.
|
||||
///
|
||||
/// A positive offset becomes negative and vice versa. This is a no-op for the
|
||||
/// zero offset.
|
||||
///
|
||||
/// This never panics.
|
||||
impl Neg for Offset {
|
||||
type Output = Offset;
|
||||
|
||||
#[inline]
|
||||
fn neg(self) -> Offset {
|
||||
self.negate()
|
||||
}
|
||||
}
|
||||
3242
src/tz/posix.rs
Normal file
3242
src/tz/posix.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,251 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse_v1())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
America/New_York
|
||||
LOCAL TIME TYPES
|
||||
000: offset=-04:56:02 designation=LMT indicator=local/wall
|
||||
001: offset=-04 designation=EDT dst indicator=local/wall
|
||||
002: offset=-05 designation=EST indicator=local/wall
|
||||
003: offset=-05 designation=EST indicator=ut/std
|
||||
004: offset=-04 designation=EWT dst indicator=local/wall
|
||||
005: offset=-04 designation=EPT dst indicator=ut/std
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-01T21:03:57 unambiguous type=0 -04:56:02 LMT
|
||||
0001: 1901-12-13T20:45:52Z unix=-2147483648 wall=1901-12-13T15:45:52 fold-until(1901-12-13T15:49:50) type=3 -05 EST
|
||||
0002: 1918-03-31T07:00:00Z unix=-1633280400 wall=1918-03-31T02:00:00 gap-until(1918-03-31T03:00:00) type=1 -04 EDT dst
|
||||
0003: 1918-10-27T06:00:00Z unix=-1615140000 wall=1918-10-27T01:00:00 fold-until(1918-10-27T02:00:00) type=2 -05 EST
|
||||
0004: 1919-03-30T07:00:00Z unix=-1601830800 wall=1919-03-30T02:00:00 gap-until(1919-03-30T03:00:00) type=1 -04 EDT dst
|
||||
0005: 1919-10-26T06:00:00Z unix=-1583690400 wall=1919-10-26T01:00:00 fold-until(1919-10-26T02:00:00) type=2 -05 EST
|
||||
0006: 1920-03-28T07:00:00Z unix=-1570381200 wall=1920-03-28T02:00:00 gap-until(1920-03-28T03:00:00) type=1 -04 EDT dst
|
||||
0007: 1920-10-31T06:00:00Z unix=-1551636000 wall=1920-10-31T01:00:00 fold-until(1920-10-31T02:00:00) type=2 -05 EST
|
||||
0008: 1921-04-24T07:00:00Z unix=-1536512400 wall=1921-04-24T02:00:00 gap-until(1921-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0009: 1921-09-25T06:00:00Z unix=-1523210400 wall=1921-09-25T01:00:00 fold-until(1921-09-25T02:00:00) type=2 -05 EST
|
||||
0010: 1922-04-30T07:00:00Z unix=-1504458000 wall=1922-04-30T02:00:00 gap-until(1922-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0011: 1922-09-24T06:00:00Z unix=-1491760800 wall=1922-09-24T01:00:00 fold-until(1922-09-24T02:00:00) type=2 -05 EST
|
||||
0012: 1923-04-29T07:00:00Z unix=-1473008400 wall=1923-04-29T02:00:00 gap-until(1923-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0013: 1923-09-30T06:00:00Z unix=-1459706400 wall=1923-09-30T01:00:00 fold-until(1923-09-30T02:00:00) type=2 -05 EST
|
||||
0014: 1924-04-27T07:00:00Z unix=-1441558800 wall=1924-04-27T02:00:00 gap-until(1924-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0015: 1924-09-28T06:00:00Z unix=-1428256800 wall=1924-09-28T01:00:00 fold-until(1924-09-28T02:00:00) type=2 -05 EST
|
||||
0016: 1925-04-26T07:00:00Z unix=-1410109200 wall=1925-04-26T02:00:00 gap-until(1925-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0017: 1925-09-27T06:00:00Z unix=-1396807200 wall=1925-09-27T01:00:00 fold-until(1925-09-27T02:00:00) type=2 -05 EST
|
||||
0018: 1926-04-25T07:00:00Z unix=-1378659600 wall=1926-04-25T02:00:00 gap-until(1926-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0019: 1926-09-26T06:00:00Z unix=-1365357600 wall=1926-09-26T01:00:00 fold-until(1926-09-26T02:00:00) type=2 -05 EST
|
||||
0020: 1927-04-24T07:00:00Z unix=-1347210000 wall=1927-04-24T02:00:00 gap-until(1927-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0021: 1927-09-25T06:00:00Z unix=-1333908000 wall=1927-09-25T01:00:00 fold-until(1927-09-25T02:00:00) type=2 -05 EST
|
||||
0022: 1928-04-29T07:00:00Z unix=-1315155600 wall=1928-04-29T02:00:00 gap-until(1928-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0023: 1928-09-30T06:00:00Z unix=-1301853600 wall=1928-09-30T01:00:00 fold-until(1928-09-30T02:00:00) type=2 -05 EST
|
||||
0024: 1929-04-28T07:00:00Z unix=-1283706000 wall=1929-04-28T02:00:00 gap-until(1929-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0025: 1929-09-29T06:00:00Z unix=-1270404000 wall=1929-09-29T01:00:00 fold-until(1929-09-29T02:00:00) type=2 -05 EST
|
||||
0026: 1930-04-27T07:00:00Z unix=-1252256400 wall=1930-04-27T02:00:00 gap-until(1930-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0027: 1930-09-28T06:00:00Z unix=-1238954400 wall=1930-09-28T01:00:00 fold-until(1930-09-28T02:00:00) type=2 -05 EST
|
||||
0028: 1931-04-26T07:00:00Z unix=-1220806800 wall=1931-04-26T02:00:00 gap-until(1931-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0029: 1931-09-27T06:00:00Z unix=-1207504800 wall=1931-09-27T01:00:00 fold-until(1931-09-27T02:00:00) type=2 -05 EST
|
||||
0030: 1932-04-24T07:00:00Z unix=-1189357200 wall=1932-04-24T02:00:00 gap-until(1932-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0031: 1932-09-25T06:00:00Z unix=-1176055200 wall=1932-09-25T01:00:00 fold-until(1932-09-25T02:00:00) type=2 -05 EST
|
||||
0032: 1933-04-30T07:00:00Z unix=-1157302800 wall=1933-04-30T02:00:00 gap-until(1933-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0033: 1933-09-24T06:00:00Z unix=-1144605600 wall=1933-09-24T01:00:00 fold-until(1933-09-24T02:00:00) type=2 -05 EST
|
||||
0034: 1934-04-29T07:00:00Z unix=-1125853200 wall=1934-04-29T02:00:00 gap-until(1934-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0035: 1934-09-30T06:00:00Z unix=-1112551200 wall=1934-09-30T01:00:00 fold-until(1934-09-30T02:00:00) type=2 -05 EST
|
||||
0036: 1935-04-28T07:00:00Z unix=-1094403600 wall=1935-04-28T02:00:00 gap-until(1935-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0037: 1935-09-29T06:00:00Z unix=-1081101600 wall=1935-09-29T01:00:00 fold-until(1935-09-29T02:00:00) type=2 -05 EST
|
||||
0038: 1936-04-26T07:00:00Z unix=-1062954000 wall=1936-04-26T02:00:00 gap-until(1936-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0039: 1936-09-27T06:00:00Z unix=-1049652000 wall=1936-09-27T01:00:00 fold-until(1936-09-27T02:00:00) type=2 -05 EST
|
||||
0040: 1937-04-25T07:00:00Z unix=-1031504400 wall=1937-04-25T02:00:00 gap-until(1937-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0041: 1937-09-26T06:00:00Z unix=-1018202400 wall=1937-09-26T01:00:00 fold-until(1937-09-26T02:00:00) type=2 -05 EST
|
||||
0042: 1938-04-24T07:00:00Z unix=-1000054800 wall=1938-04-24T02:00:00 gap-until(1938-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0043: 1938-09-25T06:00:00Z unix=-986752800 wall=1938-09-25T01:00:00 fold-until(1938-09-25T02:00:00) type=2 -05 EST
|
||||
0044: 1939-04-30T07:00:00Z unix=-968000400 wall=1939-04-30T02:00:00 gap-until(1939-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0045: 1939-09-24T06:00:00Z unix=-955303200 wall=1939-09-24T01:00:00 fold-until(1939-09-24T02:00:00) type=2 -05 EST
|
||||
0046: 1940-04-28T07:00:00Z unix=-936550800 wall=1940-04-28T02:00:00 gap-until(1940-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0047: 1940-09-29T06:00:00Z unix=-923248800 wall=1940-09-29T01:00:00 fold-until(1940-09-29T02:00:00) type=2 -05 EST
|
||||
0048: 1941-04-27T07:00:00Z unix=-905101200 wall=1941-04-27T02:00:00 gap-until(1941-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0049: 1941-09-28T06:00:00Z unix=-891799200 wall=1941-09-28T01:00:00 fold-until(1941-09-28T02:00:00) type=2 -05 EST
|
||||
0050: 1942-02-09T07:00:00Z unix=-880218000 wall=1942-02-09T02:00:00 gap-until(1942-02-09T03:00:00) type=4 -04 EWT dst
|
||||
0051: 1945-08-14T23:00:00Z unix=-769395600 wall=1945-08-14T19:00:00 unambiguous type=5 -04 EPT dst
|
||||
0052: 1945-09-30T06:00:00Z unix=-765396000 wall=1945-09-30T01:00:00 fold-until(1945-09-30T02:00:00) type=2 -05 EST
|
||||
0053: 1946-04-28T07:00:00Z unix=-747248400 wall=1946-04-28T02:00:00 gap-until(1946-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0054: 1946-09-29T06:00:00Z unix=-733946400 wall=1946-09-29T01:00:00 fold-until(1946-09-29T02:00:00) type=2 -05 EST
|
||||
0055: 1947-04-27T07:00:00Z unix=-715798800 wall=1947-04-27T02:00:00 gap-until(1947-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0056: 1947-09-28T06:00:00Z unix=-702496800 wall=1947-09-28T01:00:00 fold-until(1947-09-28T02:00:00) type=2 -05 EST
|
||||
0057: 1948-04-25T07:00:00Z unix=-684349200 wall=1948-04-25T02:00:00 gap-until(1948-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0058: 1948-09-26T06:00:00Z unix=-671047200 wall=1948-09-26T01:00:00 fold-until(1948-09-26T02:00:00) type=2 -05 EST
|
||||
0059: 1949-04-24T07:00:00Z unix=-652899600 wall=1949-04-24T02:00:00 gap-until(1949-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0060: 1949-09-25T06:00:00Z unix=-639597600 wall=1949-09-25T01:00:00 fold-until(1949-09-25T02:00:00) type=2 -05 EST
|
||||
0061: 1950-04-30T07:00:00Z unix=-620845200 wall=1950-04-30T02:00:00 gap-until(1950-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0062: 1950-09-24T06:00:00Z unix=-608148000 wall=1950-09-24T01:00:00 fold-until(1950-09-24T02:00:00) type=2 -05 EST
|
||||
0063: 1951-04-29T07:00:00Z unix=-589395600 wall=1951-04-29T02:00:00 gap-until(1951-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0064: 1951-09-30T06:00:00Z unix=-576093600 wall=1951-09-30T01:00:00 fold-until(1951-09-30T02:00:00) type=2 -05 EST
|
||||
0065: 1952-04-27T07:00:00Z unix=-557946000 wall=1952-04-27T02:00:00 gap-until(1952-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0066: 1952-09-28T06:00:00Z unix=-544644000 wall=1952-09-28T01:00:00 fold-until(1952-09-28T02:00:00) type=2 -05 EST
|
||||
0067: 1953-04-26T07:00:00Z unix=-526496400 wall=1953-04-26T02:00:00 gap-until(1953-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0068: 1953-09-27T06:00:00Z unix=-513194400 wall=1953-09-27T01:00:00 fold-until(1953-09-27T02:00:00) type=2 -05 EST
|
||||
0069: 1954-04-25T07:00:00Z unix=-495046800 wall=1954-04-25T02:00:00 gap-until(1954-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0070: 1954-09-26T06:00:00Z unix=-481744800 wall=1954-09-26T01:00:00 fold-until(1954-09-26T02:00:00) type=2 -05 EST
|
||||
0071: 1955-04-24T07:00:00Z unix=-463597200 wall=1955-04-24T02:00:00 gap-until(1955-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0072: 1955-10-30T06:00:00Z unix=-447271200 wall=1955-10-30T01:00:00 fold-until(1955-10-30T02:00:00) type=2 -05 EST
|
||||
0073: 1956-04-29T07:00:00Z unix=-431542800 wall=1956-04-29T02:00:00 gap-until(1956-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0074: 1956-10-28T06:00:00Z unix=-415821600 wall=1956-10-28T01:00:00 fold-until(1956-10-28T02:00:00) type=2 -05 EST
|
||||
0075: 1957-04-28T07:00:00Z unix=-400093200 wall=1957-04-28T02:00:00 gap-until(1957-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0076: 1957-10-27T06:00:00Z unix=-384372000 wall=1957-10-27T01:00:00 fold-until(1957-10-27T02:00:00) type=2 -05 EST
|
||||
0077: 1958-04-27T07:00:00Z unix=-368643600 wall=1958-04-27T02:00:00 gap-until(1958-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0078: 1958-10-26T06:00:00Z unix=-352922400 wall=1958-10-26T01:00:00 fold-until(1958-10-26T02:00:00) type=2 -05 EST
|
||||
0079: 1959-04-26T07:00:00Z unix=-337194000 wall=1959-04-26T02:00:00 gap-until(1959-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0080: 1959-10-25T06:00:00Z unix=-321472800 wall=1959-10-25T01:00:00 fold-until(1959-10-25T02:00:00) type=2 -05 EST
|
||||
0081: 1960-04-24T07:00:00Z unix=-305744400 wall=1960-04-24T02:00:00 gap-until(1960-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0082: 1960-10-30T06:00:00Z unix=-289418400 wall=1960-10-30T01:00:00 fold-until(1960-10-30T02:00:00) type=2 -05 EST
|
||||
0083: 1961-04-30T07:00:00Z unix=-273690000 wall=1961-04-30T02:00:00 gap-until(1961-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0084: 1961-10-29T06:00:00Z unix=-257968800 wall=1961-10-29T01:00:00 fold-until(1961-10-29T02:00:00) type=2 -05 EST
|
||||
0085: 1962-04-29T07:00:00Z unix=-242240400 wall=1962-04-29T02:00:00 gap-until(1962-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0086: 1962-10-28T06:00:00Z unix=-226519200 wall=1962-10-28T01:00:00 fold-until(1962-10-28T02:00:00) type=2 -05 EST
|
||||
0087: 1963-04-28T07:00:00Z unix=-210790800 wall=1963-04-28T02:00:00 gap-until(1963-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0088: 1963-10-27T06:00:00Z unix=-195069600 wall=1963-10-27T01:00:00 fold-until(1963-10-27T02:00:00) type=2 -05 EST
|
||||
0089: 1964-04-26T07:00:00Z unix=-179341200 wall=1964-04-26T02:00:00 gap-until(1964-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0090: 1964-10-25T06:00:00Z unix=-163620000 wall=1964-10-25T01:00:00 fold-until(1964-10-25T02:00:00) type=2 -05 EST
|
||||
0091: 1965-04-25T07:00:00Z unix=-147891600 wall=1965-04-25T02:00:00 gap-until(1965-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0092: 1965-10-31T06:00:00Z unix=-131565600 wall=1965-10-31T01:00:00 fold-until(1965-10-31T02:00:00) type=2 -05 EST
|
||||
0093: 1966-04-24T07:00:00Z unix=-116442000 wall=1966-04-24T02:00:00 gap-until(1966-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0094: 1966-10-30T06:00:00Z unix=-100116000 wall=1966-10-30T01:00:00 fold-until(1966-10-30T02:00:00) type=2 -05 EST
|
||||
0095: 1967-04-30T07:00:00Z unix=-84387600 wall=1967-04-30T02:00:00 gap-until(1967-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0096: 1967-10-29T06:00:00Z unix=-68666400 wall=1967-10-29T01:00:00 fold-until(1967-10-29T02:00:00) type=2 -05 EST
|
||||
0097: 1968-04-28T07:00:00Z unix=-52938000 wall=1968-04-28T02:00:00 gap-until(1968-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0098: 1968-10-27T06:00:00Z unix=-37216800 wall=1968-10-27T01:00:00 fold-until(1968-10-27T02:00:00) type=2 -05 EST
|
||||
0099: 1969-04-27T07:00:00Z unix=-21488400 wall=1969-04-27T02:00:00 gap-until(1969-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0100: 1969-10-26T06:00:00Z unix=-5767200 wall=1969-10-26T01:00:00 fold-until(1969-10-26T02:00:00) type=2 -05 EST
|
||||
0101: 1970-04-26T07:00:00Z unix=9961200 wall=1970-04-26T02:00:00 gap-until(1970-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0102: 1970-10-25T06:00:00Z unix=25682400 wall=1970-10-25T01:00:00 fold-until(1970-10-25T02:00:00) type=2 -05 EST
|
||||
0103: 1971-04-25T07:00:00Z unix=41410800 wall=1971-04-25T02:00:00 gap-until(1971-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0104: 1971-10-31T06:00:00Z unix=57736800 wall=1971-10-31T01:00:00 fold-until(1971-10-31T02:00:00) type=2 -05 EST
|
||||
0105: 1972-04-30T07:00:00Z unix=73465200 wall=1972-04-30T02:00:00 gap-until(1972-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0106: 1972-10-29T06:00:00Z unix=89186400 wall=1972-10-29T01:00:00 fold-until(1972-10-29T02:00:00) type=2 -05 EST
|
||||
0107: 1973-04-29T07:00:00Z unix=104914800 wall=1973-04-29T02:00:00 gap-until(1973-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0108: 1973-10-28T06:00:00Z unix=120636000 wall=1973-10-28T01:00:00 fold-until(1973-10-28T02:00:00) type=2 -05 EST
|
||||
0109: 1974-01-06T07:00:00Z unix=126687600 wall=1974-01-06T02:00:00 gap-until(1974-01-06T03:00:00) type=1 -04 EDT dst
|
||||
0110: 1974-10-27T06:00:00Z unix=152085600 wall=1974-10-27T01:00:00 fold-until(1974-10-27T02:00:00) type=2 -05 EST
|
||||
0111: 1975-02-23T07:00:00Z unix=162370800 wall=1975-02-23T02:00:00 gap-until(1975-02-23T03:00:00) type=1 -04 EDT dst
|
||||
0112: 1975-10-26T06:00:00Z unix=183535200 wall=1975-10-26T01:00:00 fold-until(1975-10-26T02:00:00) type=2 -05 EST
|
||||
0113: 1976-04-25T07:00:00Z unix=199263600 wall=1976-04-25T02:00:00 gap-until(1976-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0114: 1976-10-31T06:00:00Z unix=215589600 wall=1976-10-31T01:00:00 fold-until(1976-10-31T02:00:00) type=2 -05 EST
|
||||
0115: 1977-04-24T07:00:00Z unix=230713200 wall=1977-04-24T02:00:00 gap-until(1977-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0116: 1977-10-30T06:00:00Z unix=247039200 wall=1977-10-30T01:00:00 fold-until(1977-10-30T02:00:00) type=2 -05 EST
|
||||
0117: 1978-04-30T07:00:00Z unix=262767600 wall=1978-04-30T02:00:00 gap-until(1978-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0118: 1978-10-29T06:00:00Z unix=278488800 wall=1978-10-29T01:00:00 fold-until(1978-10-29T02:00:00) type=2 -05 EST
|
||||
0119: 1979-04-29T07:00:00Z unix=294217200 wall=1979-04-29T02:00:00 gap-until(1979-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0120: 1979-10-28T06:00:00Z unix=309938400 wall=1979-10-28T01:00:00 fold-until(1979-10-28T02:00:00) type=2 -05 EST
|
||||
0121: 1980-04-27T07:00:00Z unix=325666800 wall=1980-04-27T02:00:00 gap-until(1980-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0122: 1980-10-26T06:00:00Z unix=341388000 wall=1980-10-26T01:00:00 fold-until(1980-10-26T02:00:00) type=2 -05 EST
|
||||
0123: 1981-04-26T07:00:00Z unix=357116400 wall=1981-04-26T02:00:00 gap-until(1981-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0124: 1981-10-25T06:00:00Z unix=372837600 wall=1981-10-25T01:00:00 fold-until(1981-10-25T02:00:00) type=2 -05 EST
|
||||
0125: 1982-04-25T07:00:00Z unix=388566000 wall=1982-04-25T02:00:00 gap-until(1982-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0126: 1982-10-31T06:00:00Z unix=404892000 wall=1982-10-31T01:00:00 fold-until(1982-10-31T02:00:00) type=2 -05 EST
|
||||
0127: 1983-04-24T07:00:00Z unix=420015600 wall=1983-04-24T02:00:00 gap-until(1983-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0128: 1983-10-30T06:00:00Z unix=436341600 wall=1983-10-30T01:00:00 fold-until(1983-10-30T02:00:00) type=2 -05 EST
|
||||
0129: 1984-04-29T07:00:00Z unix=452070000 wall=1984-04-29T02:00:00 gap-until(1984-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0130: 1984-10-28T06:00:00Z unix=467791200 wall=1984-10-28T01:00:00 fold-until(1984-10-28T02:00:00) type=2 -05 EST
|
||||
0131: 1985-04-28T07:00:00Z unix=483519600 wall=1985-04-28T02:00:00 gap-until(1985-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0132: 1985-10-27T06:00:00Z unix=499240800 wall=1985-10-27T01:00:00 fold-until(1985-10-27T02:00:00) type=2 -05 EST
|
||||
0133: 1986-04-27T07:00:00Z unix=514969200 wall=1986-04-27T02:00:00 gap-until(1986-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0134: 1986-10-26T06:00:00Z unix=530690400 wall=1986-10-26T01:00:00 fold-until(1986-10-26T02:00:00) type=2 -05 EST
|
||||
0135: 1987-04-05T07:00:00Z unix=544604400 wall=1987-04-05T02:00:00 gap-until(1987-04-05T03:00:00) type=1 -04 EDT dst
|
||||
0136: 1987-10-25T06:00:00Z unix=562140000 wall=1987-10-25T01:00:00 fold-until(1987-10-25T02:00:00) type=2 -05 EST
|
||||
0137: 1988-04-03T07:00:00Z unix=576054000 wall=1988-04-03T02:00:00 gap-until(1988-04-03T03:00:00) type=1 -04 EDT dst
|
||||
0138: 1988-10-30T06:00:00Z unix=594194400 wall=1988-10-30T01:00:00 fold-until(1988-10-30T02:00:00) type=2 -05 EST
|
||||
0139: 1989-04-02T07:00:00Z unix=607503600 wall=1989-04-02T02:00:00 gap-until(1989-04-02T03:00:00) type=1 -04 EDT dst
|
||||
0140: 1989-10-29T06:00:00Z unix=625644000 wall=1989-10-29T01:00:00 fold-until(1989-10-29T02:00:00) type=2 -05 EST
|
||||
0141: 1990-04-01T07:00:00Z unix=638953200 wall=1990-04-01T02:00:00 gap-until(1990-04-01T03:00:00) type=1 -04 EDT dst
|
||||
0142: 1990-10-28T06:00:00Z unix=657093600 wall=1990-10-28T01:00:00 fold-until(1990-10-28T02:00:00) type=2 -05 EST
|
||||
0143: 1991-04-07T07:00:00Z unix=671007600 wall=1991-04-07T02:00:00 gap-until(1991-04-07T03:00:00) type=1 -04 EDT dst
|
||||
0144: 1991-10-27T06:00:00Z unix=688543200 wall=1991-10-27T01:00:00 fold-until(1991-10-27T02:00:00) type=2 -05 EST
|
||||
0145: 1992-04-05T07:00:00Z unix=702457200 wall=1992-04-05T02:00:00 gap-until(1992-04-05T03:00:00) type=1 -04 EDT dst
|
||||
0146: 1992-10-25T06:00:00Z unix=719992800 wall=1992-10-25T01:00:00 fold-until(1992-10-25T02:00:00) type=2 -05 EST
|
||||
0147: 1993-04-04T07:00:00Z unix=733906800 wall=1993-04-04T02:00:00 gap-until(1993-04-04T03:00:00) type=1 -04 EDT dst
|
||||
0148: 1993-10-31T06:00:00Z unix=752047200 wall=1993-10-31T01:00:00 fold-until(1993-10-31T02:00:00) type=2 -05 EST
|
||||
0149: 1994-04-03T07:00:00Z unix=765356400 wall=1994-04-03T02:00:00 gap-until(1994-04-03T03:00:00) type=1 -04 EDT dst
|
||||
0150: 1994-10-30T06:00:00Z unix=783496800 wall=1994-10-30T01:00:00 fold-until(1994-10-30T02:00:00) type=2 -05 EST
|
||||
0151: 1995-04-02T07:00:00Z unix=796806000 wall=1995-04-02T02:00:00 gap-until(1995-04-02T03:00:00) type=1 -04 EDT dst
|
||||
0152: 1995-10-29T06:00:00Z unix=814946400 wall=1995-10-29T01:00:00 fold-until(1995-10-29T02:00:00) type=2 -05 EST
|
||||
0153: 1996-04-07T07:00:00Z unix=828860400 wall=1996-04-07T02:00:00 gap-until(1996-04-07T03:00:00) type=1 -04 EDT dst
|
||||
0154: 1996-10-27T06:00:00Z unix=846396000 wall=1996-10-27T01:00:00 fold-until(1996-10-27T02:00:00) type=2 -05 EST
|
||||
0155: 1997-04-06T07:00:00Z unix=860310000 wall=1997-04-06T02:00:00 gap-until(1997-04-06T03:00:00) type=1 -04 EDT dst
|
||||
0156: 1997-10-26T06:00:00Z unix=877845600 wall=1997-10-26T01:00:00 fold-until(1997-10-26T02:00:00) type=2 -05 EST
|
||||
0157: 1998-04-05T07:00:00Z unix=891759600 wall=1998-04-05T02:00:00 gap-until(1998-04-05T03:00:00) type=1 -04 EDT dst
|
||||
0158: 1998-10-25T06:00:00Z unix=909295200 wall=1998-10-25T01:00:00 fold-until(1998-10-25T02:00:00) type=2 -05 EST
|
||||
0159: 1999-04-04T07:00:00Z unix=923209200 wall=1999-04-04T02:00:00 gap-until(1999-04-04T03:00:00) type=1 -04 EDT dst
|
||||
0160: 1999-10-31T06:00:00Z unix=941349600 wall=1999-10-31T01:00:00 fold-until(1999-10-31T02:00:00) type=2 -05 EST
|
||||
0161: 2000-04-02T07:00:00Z unix=954658800 wall=2000-04-02T02:00:00 gap-until(2000-04-02T03:00:00) type=1 -04 EDT dst
|
||||
0162: 2000-10-29T06:00:00Z unix=972799200 wall=2000-10-29T01:00:00 fold-until(2000-10-29T02:00:00) type=2 -05 EST
|
||||
0163: 2001-04-01T07:00:00Z unix=986108400 wall=2001-04-01T02:00:00 gap-until(2001-04-01T03:00:00) type=1 -04 EDT dst
|
||||
0164: 2001-10-28T06:00:00Z unix=1004248800 wall=2001-10-28T01:00:00 fold-until(2001-10-28T02:00:00) type=2 -05 EST
|
||||
0165: 2002-04-07T07:00:00Z unix=1018162800 wall=2002-04-07T02:00:00 gap-until(2002-04-07T03:00:00) type=1 -04 EDT dst
|
||||
0166: 2002-10-27T06:00:00Z unix=1035698400 wall=2002-10-27T01:00:00 fold-until(2002-10-27T02:00:00) type=2 -05 EST
|
||||
0167: 2003-04-06T07:00:00Z unix=1049612400 wall=2003-04-06T02:00:00 gap-until(2003-04-06T03:00:00) type=1 -04 EDT dst
|
||||
0168: 2003-10-26T06:00:00Z unix=1067148000 wall=2003-10-26T01:00:00 fold-until(2003-10-26T02:00:00) type=2 -05 EST
|
||||
0169: 2004-04-04T07:00:00Z unix=1081062000 wall=2004-04-04T02:00:00 gap-until(2004-04-04T03:00:00) type=1 -04 EDT dst
|
||||
0170: 2004-10-31T06:00:00Z unix=1099202400 wall=2004-10-31T01:00:00 fold-until(2004-10-31T02:00:00) type=2 -05 EST
|
||||
0171: 2005-04-03T07:00:00Z unix=1112511600 wall=2005-04-03T02:00:00 gap-until(2005-04-03T03:00:00) type=1 -04 EDT dst
|
||||
0172: 2005-10-30T06:00:00Z unix=1130652000 wall=2005-10-30T01:00:00 fold-until(2005-10-30T02:00:00) type=2 -05 EST
|
||||
0173: 2006-04-02T07:00:00Z unix=1143961200 wall=2006-04-02T02:00:00 gap-until(2006-04-02T03:00:00) type=1 -04 EDT dst
|
||||
0174: 2006-10-29T06:00:00Z unix=1162101600 wall=2006-10-29T01:00:00 fold-until(2006-10-29T02:00:00) type=2 -05 EST
|
||||
0175: 2007-03-11T07:00:00Z unix=1173596400 wall=2007-03-11T02:00:00 gap-until(2007-03-11T03:00:00) type=1 -04 EDT dst
|
||||
0176: 2007-11-04T06:00:00Z unix=1194156000 wall=2007-11-04T01:00:00 fold-until(2007-11-04T02:00:00) type=2 -05 EST
|
||||
0177: 2008-03-09T07:00:00Z unix=1205046000 wall=2008-03-09T02:00:00 gap-until(2008-03-09T03:00:00) type=1 -04 EDT dst
|
||||
0178: 2008-11-02T06:00:00Z unix=1225605600 wall=2008-11-02T01:00:00 fold-until(2008-11-02T02:00:00) type=2 -05 EST
|
||||
0179: 2009-03-08T07:00:00Z unix=1236495600 wall=2009-03-08T02:00:00 gap-until(2009-03-08T03:00:00) type=1 -04 EDT dst
|
||||
0180: 2009-11-01T06:00:00Z unix=1257055200 wall=2009-11-01T01:00:00 fold-until(2009-11-01T02:00:00) type=2 -05 EST
|
||||
0181: 2010-03-14T07:00:00Z unix=1268550000 wall=2010-03-14T02:00:00 gap-until(2010-03-14T03:00:00) type=1 -04 EDT dst
|
||||
0182: 2010-11-07T06:00:00Z unix=1289109600 wall=2010-11-07T01:00:00 fold-until(2010-11-07T02:00:00) type=2 -05 EST
|
||||
0183: 2011-03-13T07:00:00Z unix=1299999600 wall=2011-03-13T02:00:00 gap-until(2011-03-13T03:00:00) type=1 -04 EDT dst
|
||||
0184: 2011-11-06T06:00:00Z unix=1320559200 wall=2011-11-06T01:00:00 fold-until(2011-11-06T02:00:00) type=2 -05 EST
|
||||
0185: 2012-03-11T07:00:00Z unix=1331449200 wall=2012-03-11T02:00:00 gap-until(2012-03-11T03:00:00) type=1 -04 EDT dst
|
||||
0186: 2012-11-04T06:00:00Z unix=1352008800 wall=2012-11-04T01:00:00 fold-until(2012-11-04T02:00:00) type=2 -05 EST
|
||||
0187: 2013-03-10T07:00:00Z unix=1362898800 wall=2013-03-10T02:00:00 gap-until(2013-03-10T03:00:00) type=1 -04 EDT dst
|
||||
0188: 2013-11-03T06:00:00Z unix=1383458400 wall=2013-11-03T01:00:00 fold-until(2013-11-03T02:00:00) type=2 -05 EST
|
||||
0189: 2014-03-09T07:00:00Z unix=1394348400 wall=2014-03-09T02:00:00 gap-until(2014-03-09T03:00:00) type=1 -04 EDT dst
|
||||
0190: 2014-11-02T06:00:00Z unix=1414908000 wall=2014-11-02T01:00:00 fold-until(2014-11-02T02:00:00) type=2 -05 EST
|
||||
0191: 2015-03-08T07:00:00Z unix=1425798000 wall=2015-03-08T02:00:00 gap-until(2015-03-08T03:00:00) type=1 -04 EDT dst
|
||||
0192: 2015-11-01T06:00:00Z unix=1446357600 wall=2015-11-01T01:00:00 fold-until(2015-11-01T02:00:00) type=2 -05 EST
|
||||
0193: 2016-03-13T07:00:00Z unix=1457852400 wall=2016-03-13T02:00:00 gap-until(2016-03-13T03:00:00) type=1 -04 EDT dst
|
||||
0194: 2016-11-06T06:00:00Z unix=1478412000 wall=2016-11-06T01:00:00 fold-until(2016-11-06T02:00:00) type=2 -05 EST
|
||||
0195: 2017-03-12T07:00:00Z unix=1489302000 wall=2017-03-12T02:00:00 gap-until(2017-03-12T03:00:00) type=1 -04 EDT dst
|
||||
0196: 2017-11-05T06:00:00Z unix=1509861600 wall=2017-11-05T01:00:00 fold-until(2017-11-05T02:00:00) type=2 -05 EST
|
||||
0197: 2018-03-11T07:00:00Z unix=1520751600 wall=2018-03-11T02:00:00 gap-until(2018-03-11T03:00:00) type=1 -04 EDT dst
|
||||
0198: 2018-11-04T06:00:00Z unix=1541311200 wall=2018-11-04T01:00:00 fold-until(2018-11-04T02:00:00) type=2 -05 EST
|
||||
0199: 2019-03-10T07:00:00Z unix=1552201200 wall=2019-03-10T02:00:00 gap-until(2019-03-10T03:00:00) type=1 -04 EDT dst
|
||||
0200: 2019-11-03T06:00:00Z unix=1572760800 wall=2019-11-03T01:00:00 fold-until(2019-11-03T02:00:00) type=2 -05 EST
|
||||
0201: 2020-03-08T07:00:00Z unix=1583650800 wall=2020-03-08T02:00:00 gap-until(2020-03-08T03:00:00) type=1 -04 EDT dst
|
||||
0202: 2020-11-01T06:00:00Z unix=1604210400 wall=2020-11-01T01:00:00 fold-until(2020-11-01T02:00:00) type=2 -05 EST
|
||||
0203: 2021-03-14T07:00:00Z unix=1615705200 wall=2021-03-14T02:00:00 gap-until(2021-03-14T03:00:00) type=1 -04 EDT dst
|
||||
0204: 2021-11-07T06:00:00Z unix=1636264800 wall=2021-11-07T01:00:00 fold-until(2021-11-07T02:00:00) type=2 -05 EST
|
||||
0205: 2022-03-13T07:00:00Z unix=1647154800 wall=2022-03-13T02:00:00 gap-until(2022-03-13T03:00:00) type=1 -04 EDT dst
|
||||
0206: 2022-11-06T06:00:00Z unix=1667714400 wall=2022-11-06T01:00:00 fold-until(2022-11-06T02:00:00) type=2 -05 EST
|
||||
0207: 2023-03-12T07:00:00Z unix=1678604400 wall=2023-03-12T02:00:00 gap-until(2023-03-12T03:00:00) type=1 -04 EDT dst
|
||||
0208: 2023-11-05T06:00:00Z unix=1699164000 wall=2023-11-05T01:00:00 fold-until(2023-11-05T02:00:00) type=2 -05 EST
|
||||
0209: 2024-03-10T07:00:00Z unix=1710054000 wall=2024-03-10T02:00:00 gap-until(2024-03-10T03:00:00) type=1 -04 EDT dst
|
||||
0210: 2024-11-03T06:00:00Z unix=1730613600 wall=2024-11-03T01:00:00 fold-until(2024-11-03T02:00:00) type=2 -05 EST
|
||||
0211: 2025-03-09T07:00:00Z unix=1741503600 wall=2025-03-09T02:00:00 gap-until(2025-03-09T03:00:00) type=1 -04 EDT dst
|
||||
0212: 2025-11-02T06:00:00Z unix=1762063200 wall=2025-11-02T01:00:00 fold-until(2025-11-02T02:00:00) type=2 -05 EST
|
||||
0213: 2026-03-08T07:00:00Z unix=1772953200 wall=2026-03-08T02:00:00 gap-until(2026-03-08T03:00:00) type=1 -04 EDT dst
|
||||
0214: 2026-11-01T06:00:00Z unix=1793512800 wall=2026-11-01T01:00:00 fold-until(2026-11-01T02:00:00) type=2 -05 EST
|
||||
0215: 2027-03-14T07:00:00Z unix=1805007600 wall=2027-03-14T02:00:00 gap-until(2027-03-14T03:00:00) type=1 -04 EDT dst
|
||||
0216: 2027-11-07T06:00:00Z unix=1825567200 wall=2027-11-07T01:00:00 fold-until(2027-11-07T02:00:00) type=2 -05 EST
|
||||
0217: 2028-03-12T07:00:00Z unix=1836457200 wall=2028-03-12T02:00:00 gap-until(2028-03-12T03:00:00) type=1 -04 EDT dst
|
||||
0218: 2028-11-05T06:00:00Z unix=1857016800 wall=2028-11-05T01:00:00 fold-until(2028-11-05T02:00:00) type=2 -05 EST
|
||||
0219: 2029-03-11T07:00:00Z unix=1867906800 wall=2029-03-11T02:00:00 gap-until(2029-03-11T03:00:00) type=1 -04 EDT dst
|
||||
0220: 2029-11-04T06:00:00Z unix=1888466400 wall=2029-11-04T01:00:00 fold-until(2029-11-04T02:00:00) type=2 -05 EST
|
||||
0221: 2030-03-10T07:00:00Z unix=1899356400 wall=2030-03-10T02:00:00 gap-until(2030-03-10T03:00:00) type=1 -04 EDT dst
|
||||
0222: 2030-11-03T06:00:00Z unix=1919916000 wall=2030-11-03T01:00:00 fold-until(2030-11-03T02:00:00) type=2 -05 EST
|
||||
0223: 2031-03-09T07:00:00Z unix=1930806000 wall=2031-03-09T02:00:00 gap-until(2031-03-09T03:00:00) type=1 -04 EDT dst
|
||||
0224: 2031-11-02T06:00:00Z unix=1951365600 wall=2031-11-02T01:00:00 fold-until(2031-11-02T02:00:00) type=2 -05 EST
|
||||
0225: 2032-03-14T07:00:00Z unix=1962860400 wall=2032-03-14T02:00:00 gap-until(2032-03-14T03:00:00) type=1 -04 EDT dst
|
||||
0226: 2032-11-07T06:00:00Z unix=1983420000 wall=2032-11-07T01:00:00 fold-until(2032-11-07T02:00:00) type=2 -05 EST
|
||||
0227: 2033-03-13T07:00:00Z unix=1994310000 wall=2033-03-13T02:00:00 gap-until(2033-03-13T03:00:00) type=1 -04 EDT dst
|
||||
0228: 2033-11-06T06:00:00Z unix=2014869600 wall=2033-11-06T01:00:00 fold-until(2033-11-06T02:00:00) type=2 -05 EST
|
||||
0229: 2034-03-12T07:00:00Z unix=2025759600 wall=2034-03-12T02:00:00 gap-until(2034-03-12T03:00:00) type=1 -04 EDT dst
|
||||
0230: 2034-11-05T06:00:00Z unix=2046319200 wall=2034-11-05T01:00:00 fold-until(2034-11-05T02:00:00) type=2 -05 EST
|
||||
0231: 2035-03-11T07:00:00Z unix=2057209200 wall=2035-03-11T02:00:00 gap-until(2035-03-11T03:00:00) type=1 -04 EDT dst
|
||||
0232: 2035-11-04T06:00:00Z unix=2077768800 wall=2035-11-04T01:00:00 fold-until(2035-11-04T02:00:00) type=2 -05 EST
|
||||
0233: 2036-03-09T07:00:00Z unix=2088658800 wall=2036-03-09T02:00:00 gap-until(2036-03-09T03:00:00) type=1 -04 EDT dst
|
||||
0234: 2036-11-02T06:00:00Z unix=2109218400 wall=2036-11-02T01:00:00 fold-until(2036-11-02T02:00:00) type=2 -05 EST
|
||||
0235: 2037-03-08T07:00:00Z unix=2120108400 wall=2037-03-08T02:00:00 gap-until(2037-03-08T03:00:00) type=1 -04 EDT dst
|
||||
0236: 2037-11-01T06:00:00Z unix=2140668000 wall=2037-11-01T01:00:00 fold-until(2037-11-01T02:00:00) type=2 -05 EST
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
America/New_York
|
||||
LOCAL TIME TYPES
|
||||
000: offset=-04:56:02 designation=LMT indicator=local/wall
|
||||
001: offset=-04 designation=EDT dst indicator=local/wall
|
||||
002: offset=-05 designation=EST indicator=local/wall
|
||||
003: offset=-05 designation=EST indicator=ut/std
|
||||
004: offset=-04 designation=EWT dst indicator=local/wall
|
||||
005: offset=-04 designation=EPT dst indicator=ut/std
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-01T21:03:57 unambiguous type=0 -04:56:02 LMT
|
||||
0001: 1883-11-18T17:00:00Z unix=-2717650800 wall=1883-11-18T12:00:00 fold-until(1883-11-18T12:03:58) type=3 -05 EST
|
||||
0002: 1918-03-31T07:00:00Z unix=-1633280400 wall=1918-03-31T02:00:00 gap-until(1918-03-31T03:00:00) type=1 -04 EDT dst
|
||||
0003: 1918-10-27T06:00:00Z unix=-1615140000 wall=1918-10-27T01:00:00 fold-until(1918-10-27T02:00:00) type=2 -05 EST
|
||||
0004: 1919-03-30T07:00:00Z unix=-1601830800 wall=1919-03-30T02:00:00 gap-until(1919-03-30T03:00:00) type=1 -04 EDT dst
|
||||
0005: 1919-10-26T06:00:00Z unix=-1583690400 wall=1919-10-26T01:00:00 fold-until(1919-10-26T02:00:00) type=2 -05 EST
|
||||
0006: 1920-03-28T07:00:00Z unix=-1570381200 wall=1920-03-28T02:00:00 gap-until(1920-03-28T03:00:00) type=1 -04 EDT dst
|
||||
0007: 1920-10-31T06:00:00Z unix=-1551636000 wall=1920-10-31T01:00:00 fold-until(1920-10-31T02:00:00) type=2 -05 EST
|
||||
0008: 1921-04-24T07:00:00Z unix=-1536512400 wall=1921-04-24T02:00:00 gap-until(1921-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0009: 1921-09-25T06:00:00Z unix=-1523210400 wall=1921-09-25T01:00:00 fold-until(1921-09-25T02:00:00) type=2 -05 EST
|
||||
0010: 1922-04-30T07:00:00Z unix=-1504458000 wall=1922-04-30T02:00:00 gap-until(1922-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0011: 1922-09-24T06:00:00Z unix=-1491760800 wall=1922-09-24T01:00:00 fold-until(1922-09-24T02:00:00) type=2 -05 EST
|
||||
0012: 1923-04-29T07:00:00Z unix=-1473008400 wall=1923-04-29T02:00:00 gap-until(1923-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0013: 1923-09-30T06:00:00Z unix=-1459706400 wall=1923-09-30T01:00:00 fold-until(1923-09-30T02:00:00) type=2 -05 EST
|
||||
0014: 1924-04-27T07:00:00Z unix=-1441558800 wall=1924-04-27T02:00:00 gap-until(1924-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0015: 1924-09-28T06:00:00Z unix=-1428256800 wall=1924-09-28T01:00:00 fold-until(1924-09-28T02:00:00) type=2 -05 EST
|
||||
0016: 1925-04-26T07:00:00Z unix=-1410109200 wall=1925-04-26T02:00:00 gap-until(1925-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0017: 1925-09-27T06:00:00Z unix=-1396807200 wall=1925-09-27T01:00:00 fold-until(1925-09-27T02:00:00) type=2 -05 EST
|
||||
0018: 1926-04-25T07:00:00Z unix=-1378659600 wall=1926-04-25T02:00:00 gap-until(1926-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0019: 1926-09-26T06:00:00Z unix=-1365357600 wall=1926-09-26T01:00:00 fold-until(1926-09-26T02:00:00) type=2 -05 EST
|
||||
0020: 1927-04-24T07:00:00Z unix=-1347210000 wall=1927-04-24T02:00:00 gap-until(1927-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0021: 1927-09-25T06:00:00Z unix=-1333908000 wall=1927-09-25T01:00:00 fold-until(1927-09-25T02:00:00) type=2 -05 EST
|
||||
0022: 1928-04-29T07:00:00Z unix=-1315155600 wall=1928-04-29T02:00:00 gap-until(1928-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0023: 1928-09-30T06:00:00Z unix=-1301853600 wall=1928-09-30T01:00:00 fold-until(1928-09-30T02:00:00) type=2 -05 EST
|
||||
0024: 1929-04-28T07:00:00Z unix=-1283706000 wall=1929-04-28T02:00:00 gap-until(1929-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0025: 1929-09-29T06:00:00Z unix=-1270404000 wall=1929-09-29T01:00:00 fold-until(1929-09-29T02:00:00) type=2 -05 EST
|
||||
0026: 1930-04-27T07:00:00Z unix=-1252256400 wall=1930-04-27T02:00:00 gap-until(1930-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0027: 1930-09-28T06:00:00Z unix=-1238954400 wall=1930-09-28T01:00:00 fold-until(1930-09-28T02:00:00) type=2 -05 EST
|
||||
0028: 1931-04-26T07:00:00Z unix=-1220806800 wall=1931-04-26T02:00:00 gap-until(1931-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0029: 1931-09-27T06:00:00Z unix=-1207504800 wall=1931-09-27T01:00:00 fold-until(1931-09-27T02:00:00) type=2 -05 EST
|
||||
0030: 1932-04-24T07:00:00Z unix=-1189357200 wall=1932-04-24T02:00:00 gap-until(1932-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0031: 1932-09-25T06:00:00Z unix=-1176055200 wall=1932-09-25T01:00:00 fold-until(1932-09-25T02:00:00) type=2 -05 EST
|
||||
0032: 1933-04-30T07:00:00Z unix=-1157302800 wall=1933-04-30T02:00:00 gap-until(1933-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0033: 1933-09-24T06:00:00Z unix=-1144605600 wall=1933-09-24T01:00:00 fold-until(1933-09-24T02:00:00) type=2 -05 EST
|
||||
0034: 1934-04-29T07:00:00Z unix=-1125853200 wall=1934-04-29T02:00:00 gap-until(1934-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0035: 1934-09-30T06:00:00Z unix=-1112551200 wall=1934-09-30T01:00:00 fold-until(1934-09-30T02:00:00) type=2 -05 EST
|
||||
0036: 1935-04-28T07:00:00Z unix=-1094403600 wall=1935-04-28T02:00:00 gap-until(1935-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0037: 1935-09-29T06:00:00Z unix=-1081101600 wall=1935-09-29T01:00:00 fold-until(1935-09-29T02:00:00) type=2 -05 EST
|
||||
0038: 1936-04-26T07:00:00Z unix=-1062954000 wall=1936-04-26T02:00:00 gap-until(1936-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0039: 1936-09-27T06:00:00Z unix=-1049652000 wall=1936-09-27T01:00:00 fold-until(1936-09-27T02:00:00) type=2 -05 EST
|
||||
0040: 1937-04-25T07:00:00Z unix=-1031504400 wall=1937-04-25T02:00:00 gap-until(1937-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0041: 1937-09-26T06:00:00Z unix=-1018202400 wall=1937-09-26T01:00:00 fold-until(1937-09-26T02:00:00) type=2 -05 EST
|
||||
0042: 1938-04-24T07:00:00Z unix=-1000054800 wall=1938-04-24T02:00:00 gap-until(1938-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0043: 1938-09-25T06:00:00Z unix=-986752800 wall=1938-09-25T01:00:00 fold-until(1938-09-25T02:00:00) type=2 -05 EST
|
||||
0044: 1939-04-30T07:00:00Z unix=-968000400 wall=1939-04-30T02:00:00 gap-until(1939-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0045: 1939-09-24T06:00:00Z unix=-955303200 wall=1939-09-24T01:00:00 fold-until(1939-09-24T02:00:00) type=2 -05 EST
|
||||
0046: 1940-04-28T07:00:00Z unix=-936550800 wall=1940-04-28T02:00:00 gap-until(1940-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0047: 1940-09-29T06:00:00Z unix=-923248800 wall=1940-09-29T01:00:00 fold-until(1940-09-29T02:00:00) type=2 -05 EST
|
||||
0048: 1941-04-27T07:00:00Z unix=-905101200 wall=1941-04-27T02:00:00 gap-until(1941-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0049: 1941-09-28T06:00:00Z unix=-891799200 wall=1941-09-28T01:00:00 fold-until(1941-09-28T02:00:00) type=2 -05 EST
|
||||
0050: 1942-02-09T07:00:00Z unix=-880218000 wall=1942-02-09T02:00:00 gap-until(1942-02-09T03:00:00) type=4 -04 EWT dst
|
||||
0051: 1945-08-14T23:00:00Z unix=-769395600 wall=1945-08-14T19:00:00 unambiguous type=5 -04 EPT dst
|
||||
0052: 1945-09-30T06:00:00Z unix=-765396000 wall=1945-09-30T01:00:00 fold-until(1945-09-30T02:00:00) type=2 -05 EST
|
||||
0053: 1946-04-28T07:00:00Z unix=-747248400 wall=1946-04-28T02:00:00 gap-until(1946-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0054: 1946-09-29T06:00:00Z unix=-733946400 wall=1946-09-29T01:00:00 fold-until(1946-09-29T02:00:00) type=2 -05 EST
|
||||
0055: 1947-04-27T07:00:00Z unix=-715798800 wall=1947-04-27T02:00:00 gap-until(1947-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0056: 1947-09-28T06:00:00Z unix=-702496800 wall=1947-09-28T01:00:00 fold-until(1947-09-28T02:00:00) type=2 -05 EST
|
||||
0057: 1948-04-25T07:00:00Z unix=-684349200 wall=1948-04-25T02:00:00 gap-until(1948-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0058: 1948-09-26T06:00:00Z unix=-671047200 wall=1948-09-26T01:00:00 fold-until(1948-09-26T02:00:00) type=2 -05 EST
|
||||
0059: 1949-04-24T07:00:00Z unix=-652899600 wall=1949-04-24T02:00:00 gap-until(1949-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0060: 1949-09-25T06:00:00Z unix=-639597600 wall=1949-09-25T01:00:00 fold-until(1949-09-25T02:00:00) type=2 -05 EST
|
||||
0061: 1950-04-30T07:00:00Z unix=-620845200 wall=1950-04-30T02:00:00 gap-until(1950-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0062: 1950-09-24T06:00:00Z unix=-608148000 wall=1950-09-24T01:00:00 fold-until(1950-09-24T02:00:00) type=2 -05 EST
|
||||
0063: 1951-04-29T07:00:00Z unix=-589395600 wall=1951-04-29T02:00:00 gap-until(1951-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0064: 1951-09-30T06:00:00Z unix=-576093600 wall=1951-09-30T01:00:00 fold-until(1951-09-30T02:00:00) type=2 -05 EST
|
||||
0065: 1952-04-27T07:00:00Z unix=-557946000 wall=1952-04-27T02:00:00 gap-until(1952-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0066: 1952-09-28T06:00:00Z unix=-544644000 wall=1952-09-28T01:00:00 fold-until(1952-09-28T02:00:00) type=2 -05 EST
|
||||
0067: 1953-04-26T07:00:00Z unix=-526496400 wall=1953-04-26T02:00:00 gap-until(1953-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0068: 1953-09-27T06:00:00Z unix=-513194400 wall=1953-09-27T01:00:00 fold-until(1953-09-27T02:00:00) type=2 -05 EST
|
||||
0069: 1954-04-25T07:00:00Z unix=-495046800 wall=1954-04-25T02:00:00 gap-until(1954-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0070: 1954-09-26T06:00:00Z unix=-481744800 wall=1954-09-26T01:00:00 fold-until(1954-09-26T02:00:00) type=2 -05 EST
|
||||
0071: 1955-04-24T07:00:00Z unix=-463597200 wall=1955-04-24T02:00:00 gap-until(1955-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0072: 1955-10-30T06:00:00Z unix=-447271200 wall=1955-10-30T01:00:00 fold-until(1955-10-30T02:00:00) type=2 -05 EST
|
||||
0073: 1956-04-29T07:00:00Z unix=-431542800 wall=1956-04-29T02:00:00 gap-until(1956-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0074: 1956-10-28T06:00:00Z unix=-415821600 wall=1956-10-28T01:00:00 fold-until(1956-10-28T02:00:00) type=2 -05 EST
|
||||
0075: 1957-04-28T07:00:00Z unix=-400093200 wall=1957-04-28T02:00:00 gap-until(1957-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0076: 1957-10-27T06:00:00Z unix=-384372000 wall=1957-10-27T01:00:00 fold-until(1957-10-27T02:00:00) type=2 -05 EST
|
||||
0077: 1958-04-27T07:00:00Z unix=-368643600 wall=1958-04-27T02:00:00 gap-until(1958-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0078: 1958-10-26T06:00:00Z unix=-352922400 wall=1958-10-26T01:00:00 fold-until(1958-10-26T02:00:00) type=2 -05 EST
|
||||
0079: 1959-04-26T07:00:00Z unix=-337194000 wall=1959-04-26T02:00:00 gap-until(1959-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0080: 1959-10-25T06:00:00Z unix=-321472800 wall=1959-10-25T01:00:00 fold-until(1959-10-25T02:00:00) type=2 -05 EST
|
||||
0081: 1960-04-24T07:00:00Z unix=-305744400 wall=1960-04-24T02:00:00 gap-until(1960-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0082: 1960-10-30T06:00:00Z unix=-289418400 wall=1960-10-30T01:00:00 fold-until(1960-10-30T02:00:00) type=2 -05 EST
|
||||
0083: 1961-04-30T07:00:00Z unix=-273690000 wall=1961-04-30T02:00:00 gap-until(1961-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0084: 1961-10-29T06:00:00Z unix=-257968800 wall=1961-10-29T01:00:00 fold-until(1961-10-29T02:00:00) type=2 -05 EST
|
||||
0085: 1962-04-29T07:00:00Z unix=-242240400 wall=1962-04-29T02:00:00 gap-until(1962-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0086: 1962-10-28T06:00:00Z unix=-226519200 wall=1962-10-28T01:00:00 fold-until(1962-10-28T02:00:00) type=2 -05 EST
|
||||
0087: 1963-04-28T07:00:00Z unix=-210790800 wall=1963-04-28T02:00:00 gap-until(1963-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0088: 1963-10-27T06:00:00Z unix=-195069600 wall=1963-10-27T01:00:00 fold-until(1963-10-27T02:00:00) type=2 -05 EST
|
||||
0089: 1964-04-26T07:00:00Z unix=-179341200 wall=1964-04-26T02:00:00 gap-until(1964-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0090: 1964-10-25T06:00:00Z unix=-163620000 wall=1964-10-25T01:00:00 fold-until(1964-10-25T02:00:00) type=2 -05 EST
|
||||
0091: 1965-04-25T07:00:00Z unix=-147891600 wall=1965-04-25T02:00:00 gap-until(1965-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0092: 1965-10-31T06:00:00Z unix=-131565600 wall=1965-10-31T01:00:00 fold-until(1965-10-31T02:00:00) type=2 -05 EST
|
||||
0093: 1966-04-24T07:00:00Z unix=-116442000 wall=1966-04-24T02:00:00 gap-until(1966-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0094: 1966-10-30T06:00:00Z unix=-100116000 wall=1966-10-30T01:00:00 fold-until(1966-10-30T02:00:00) type=2 -05 EST
|
||||
0095: 1967-04-30T07:00:00Z unix=-84387600 wall=1967-04-30T02:00:00 gap-until(1967-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0096: 1967-10-29T06:00:00Z unix=-68666400 wall=1967-10-29T01:00:00 fold-until(1967-10-29T02:00:00) type=2 -05 EST
|
||||
0097: 1968-04-28T07:00:00Z unix=-52938000 wall=1968-04-28T02:00:00 gap-until(1968-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0098: 1968-10-27T06:00:00Z unix=-37216800 wall=1968-10-27T01:00:00 fold-until(1968-10-27T02:00:00) type=2 -05 EST
|
||||
0099: 1969-04-27T07:00:00Z unix=-21488400 wall=1969-04-27T02:00:00 gap-until(1969-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0100: 1969-10-26T06:00:00Z unix=-5767200 wall=1969-10-26T01:00:00 fold-until(1969-10-26T02:00:00) type=2 -05 EST
|
||||
0101: 1970-04-26T07:00:00Z unix=9961200 wall=1970-04-26T02:00:00 gap-until(1970-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0102: 1970-10-25T06:00:00Z unix=25682400 wall=1970-10-25T01:00:00 fold-until(1970-10-25T02:00:00) type=2 -05 EST
|
||||
0103: 1971-04-25T07:00:00Z unix=41410800 wall=1971-04-25T02:00:00 gap-until(1971-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0104: 1971-10-31T06:00:00Z unix=57736800 wall=1971-10-31T01:00:00 fold-until(1971-10-31T02:00:00) type=2 -05 EST
|
||||
0105: 1972-04-30T07:00:00Z unix=73465200 wall=1972-04-30T02:00:00 gap-until(1972-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0106: 1972-10-29T06:00:00Z unix=89186400 wall=1972-10-29T01:00:00 fold-until(1972-10-29T02:00:00) type=2 -05 EST
|
||||
0107: 1973-04-29T07:00:00Z unix=104914800 wall=1973-04-29T02:00:00 gap-until(1973-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0108: 1973-10-28T06:00:00Z unix=120636000 wall=1973-10-28T01:00:00 fold-until(1973-10-28T02:00:00) type=2 -05 EST
|
||||
0109: 1974-01-06T07:00:00Z unix=126687600 wall=1974-01-06T02:00:00 gap-until(1974-01-06T03:00:00) type=1 -04 EDT dst
|
||||
0110: 1974-10-27T06:00:00Z unix=152085600 wall=1974-10-27T01:00:00 fold-until(1974-10-27T02:00:00) type=2 -05 EST
|
||||
0111: 1975-02-23T07:00:00Z unix=162370800 wall=1975-02-23T02:00:00 gap-until(1975-02-23T03:00:00) type=1 -04 EDT dst
|
||||
0112: 1975-10-26T06:00:00Z unix=183535200 wall=1975-10-26T01:00:00 fold-until(1975-10-26T02:00:00) type=2 -05 EST
|
||||
0113: 1976-04-25T07:00:00Z unix=199263600 wall=1976-04-25T02:00:00 gap-until(1976-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0114: 1976-10-31T06:00:00Z unix=215589600 wall=1976-10-31T01:00:00 fold-until(1976-10-31T02:00:00) type=2 -05 EST
|
||||
0115: 1977-04-24T07:00:00Z unix=230713200 wall=1977-04-24T02:00:00 gap-until(1977-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0116: 1977-10-30T06:00:00Z unix=247039200 wall=1977-10-30T01:00:00 fold-until(1977-10-30T02:00:00) type=2 -05 EST
|
||||
0117: 1978-04-30T07:00:00Z unix=262767600 wall=1978-04-30T02:00:00 gap-until(1978-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0118: 1978-10-29T06:00:00Z unix=278488800 wall=1978-10-29T01:00:00 fold-until(1978-10-29T02:00:00) type=2 -05 EST
|
||||
0119: 1979-04-29T07:00:00Z unix=294217200 wall=1979-04-29T02:00:00 gap-until(1979-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0120: 1979-10-28T06:00:00Z unix=309938400 wall=1979-10-28T01:00:00 fold-until(1979-10-28T02:00:00) type=2 -05 EST
|
||||
0121: 1980-04-27T07:00:00Z unix=325666800 wall=1980-04-27T02:00:00 gap-until(1980-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0122: 1980-10-26T06:00:00Z unix=341388000 wall=1980-10-26T01:00:00 fold-until(1980-10-26T02:00:00) type=2 -05 EST
|
||||
0123: 1981-04-26T07:00:00Z unix=357116400 wall=1981-04-26T02:00:00 gap-until(1981-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0124: 1981-10-25T06:00:00Z unix=372837600 wall=1981-10-25T01:00:00 fold-until(1981-10-25T02:00:00) type=2 -05 EST
|
||||
0125: 1982-04-25T07:00:00Z unix=388566000 wall=1982-04-25T02:00:00 gap-until(1982-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0126: 1982-10-31T06:00:00Z unix=404892000 wall=1982-10-31T01:00:00 fold-until(1982-10-31T02:00:00) type=2 -05 EST
|
||||
0127: 1983-04-24T07:00:00Z unix=420015600 wall=1983-04-24T02:00:00 gap-until(1983-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0128: 1983-10-30T06:00:00Z unix=436341600 wall=1983-10-30T01:00:00 fold-until(1983-10-30T02:00:00) type=2 -05 EST
|
||||
0129: 1984-04-29T07:00:00Z unix=452070000 wall=1984-04-29T02:00:00 gap-until(1984-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0130: 1984-10-28T06:00:00Z unix=467791200 wall=1984-10-28T01:00:00 fold-until(1984-10-28T02:00:00) type=2 -05 EST
|
||||
0131: 1985-04-28T07:00:00Z unix=483519600 wall=1985-04-28T02:00:00 gap-until(1985-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0132: 1985-10-27T06:00:00Z unix=499240800 wall=1985-10-27T01:00:00 fold-until(1985-10-27T02:00:00) type=2 -05 EST
|
||||
0133: 1986-04-27T07:00:00Z unix=514969200 wall=1986-04-27T02:00:00 gap-until(1986-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0134: 1986-10-26T06:00:00Z unix=530690400 wall=1986-10-26T01:00:00 fold-until(1986-10-26T02:00:00) type=2 -05 EST
|
||||
0135: 1987-04-05T07:00:00Z unix=544604400 wall=1987-04-05T02:00:00 gap-until(1987-04-05T03:00:00) type=1 -04 EDT dst
|
||||
0136: 1987-10-25T06:00:00Z unix=562140000 wall=1987-10-25T01:00:00 fold-until(1987-10-25T02:00:00) type=2 -05 EST
|
||||
0137: 1988-04-03T07:00:00Z unix=576054000 wall=1988-04-03T02:00:00 gap-until(1988-04-03T03:00:00) type=1 -04 EDT dst
|
||||
0138: 1988-10-30T06:00:00Z unix=594194400 wall=1988-10-30T01:00:00 fold-until(1988-10-30T02:00:00) type=2 -05 EST
|
||||
0139: 1989-04-02T07:00:00Z unix=607503600 wall=1989-04-02T02:00:00 gap-until(1989-04-02T03:00:00) type=1 -04 EDT dst
|
||||
0140: 1989-10-29T06:00:00Z unix=625644000 wall=1989-10-29T01:00:00 fold-until(1989-10-29T02:00:00) type=2 -05 EST
|
||||
0141: 1990-04-01T07:00:00Z unix=638953200 wall=1990-04-01T02:00:00 gap-until(1990-04-01T03:00:00) type=1 -04 EDT dst
|
||||
0142: 1990-10-28T06:00:00Z unix=657093600 wall=1990-10-28T01:00:00 fold-until(1990-10-28T02:00:00) type=2 -05 EST
|
||||
0143: 1991-04-07T07:00:00Z unix=671007600 wall=1991-04-07T02:00:00 gap-until(1991-04-07T03:00:00) type=1 -04 EDT dst
|
||||
0144: 1991-10-27T06:00:00Z unix=688543200 wall=1991-10-27T01:00:00 fold-until(1991-10-27T02:00:00) type=2 -05 EST
|
||||
0145: 1992-04-05T07:00:00Z unix=702457200 wall=1992-04-05T02:00:00 gap-until(1992-04-05T03:00:00) type=1 -04 EDT dst
|
||||
0146: 1992-10-25T06:00:00Z unix=719992800 wall=1992-10-25T01:00:00 fold-until(1992-10-25T02:00:00) type=2 -05 EST
|
||||
0147: 1993-04-04T07:00:00Z unix=733906800 wall=1993-04-04T02:00:00 gap-until(1993-04-04T03:00:00) type=1 -04 EDT dst
|
||||
0148: 1993-10-31T06:00:00Z unix=752047200 wall=1993-10-31T01:00:00 fold-until(1993-10-31T02:00:00) type=2 -05 EST
|
||||
0149: 1994-04-03T07:00:00Z unix=765356400 wall=1994-04-03T02:00:00 gap-until(1994-04-03T03:00:00) type=1 -04 EDT dst
|
||||
0150: 1994-10-30T06:00:00Z unix=783496800 wall=1994-10-30T01:00:00 fold-until(1994-10-30T02:00:00) type=2 -05 EST
|
||||
0151: 1995-04-02T07:00:00Z unix=796806000 wall=1995-04-02T02:00:00 gap-until(1995-04-02T03:00:00) type=1 -04 EDT dst
|
||||
0152: 1995-10-29T06:00:00Z unix=814946400 wall=1995-10-29T01:00:00 fold-until(1995-10-29T02:00:00) type=2 -05 EST
|
||||
0153: 1996-04-07T07:00:00Z unix=828860400 wall=1996-04-07T02:00:00 gap-until(1996-04-07T03:00:00) type=1 -04 EDT dst
|
||||
0154: 1996-10-27T06:00:00Z unix=846396000 wall=1996-10-27T01:00:00 fold-until(1996-10-27T02:00:00) type=2 -05 EST
|
||||
0155: 1997-04-06T07:00:00Z unix=860310000 wall=1997-04-06T02:00:00 gap-until(1997-04-06T03:00:00) type=1 -04 EDT dst
|
||||
0156: 1997-10-26T06:00:00Z unix=877845600 wall=1997-10-26T01:00:00 fold-until(1997-10-26T02:00:00) type=2 -05 EST
|
||||
0157: 1998-04-05T07:00:00Z unix=891759600 wall=1998-04-05T02:00:00 gap-until(1998-04-05T03:00:00) type=1 -04 EDT dst
|
||||
0158: 1998-10-25T06:00:00Z unix=909295200 wall=1998-10-25T01:00:00 fold-until(1998-10-25T02:00:00) type=2 -05 EST
|
||||
0159: 1999-04-04T07:00:00Z unix=923209200 wall=1999-04-04T02:00:00 gap-until(1999-04-04T03:00:00) type=1 -04 EDT dst
|
||||
0160: 1999-10-31T06:00:00Z unix=941349600 wall=1999-10-31T01:00:00 fold-until(1999-10-31T02:00:00) type=2 -05 EST
|
||||
0161: 2000-04-02T07:00:00Z unix=954658800 wall=2000-04-02T02:00:00 gap-until(2000-04-02T03:00:00) type=1 -04 EDT dst
|
||||
0162: 2000-10-29T06:00:00Z unix=972799200 wall=2000-10-29T01:00:00 fold-until(2000-10-29T02:00:00) type=2 -05 EST
|
||||
0163: 2001-04-01T07:00:00Z unix=986108400 wall=2001-04-01T02:00:00 gap-until(2001-04-01T03:00:00) type=1 -04 EDT dst
|
||||
0164: 2001-10-28T06:00:00Z unix=1004248800 wall=2001-10-28T01:00:00 fold-until(2001-10-28T02:00:00) type=2 -05 EST
|
||||
0165: 2002-04-07T07:00:00Z unix=1018162800 wall=2002-04-07T02:00:00 gap-until(2002-04-07T03:00:00) type=1 -04 EDT dst
|
||||
0166: 2002-10-27T06:00:00Z unix=1035698400 wall=2002-10-27T01:00:00 fold-until(2002-10-27T02:00:00) type=2 -05 EST
|
||||
0167: 2003-04-06T07:00:00Z unix=1049612400 wall=2003-04-06T02:00:00 gap-until(2003-04-06T03:00:00) type=1 -04 EDT dst
|
||||
0168: 2003-10-26T06:00:00Z unix=1067148000 wall=2003-10-26T01:00:00 fold-until(2003-10-26T02:00:00) type=2 -05 EST
|
||||
0169: 2004-04-04T07:00:00Z unix=1081062000 wall=2004-04-04T02:00:00 gap-until(2004-04-04T03:00:00) type=1 -04 EDT dst
|
||||
0170: 2004-10-31T06:00:00Z unix=1099202400 wall=2004-10-31T01:00:00 fold-until(2004-10-31T02:00:00) type=2 -05 EST
|
||||
0171: 2005-04-03T07:00:00Z unix=1112511600 wall=2005-04-03T02:00:00 gap-until(2005-04-03T03:00:00) type=1 -04 EDT dst
|
||||
0172: 2005-10-30T06:00:00Z unix=1130652000 wall=2005-10-30T01:00:00 fold-until(2005-10-30T02:00:00) type=2 -05 EST
|
||||
0173: 2006-04-02T07:00:00Z unix=1143961200 wall=2006-04-02T02:00:00 gap-until(2006-04-02T03:00:00) type=1 -04 EDT dst
|
||||
0174: 2006-10-29T06:00:00Z unix=1162101600 wall=2006-10-29T01:00:00 fold-until(2006-10-29T02:00:00) type=2 -05 EST
|
||||
0175: 2007-03-11T07:00:00Z unix=1173596400 wall=2007-03-11T02:00:00 gap-until(2007-03-11T03:00:00) type=1 -04 EDT dst
|
||||
0176: 2007-11-04T06:00:00Z unix=1194156000 wall=2007-11-04T01:00:00 fold-until(2007-11-04T02:00:00) type=2 -05 EST
|
||||
0177: 2008-03-09T07:00:00Z unix=1205046000 wall=2008-03-09T02:00:00 gap-until(2008-03-09T03:00:00) type=1 -04 EDT dst
|
||||
0178: 2008-11-02T06:00:00Z unix=1225605600 wall=2008-11-02T01:00:00 fold-until(2008-11-02T02:00:00) type=2 -05 EST
|
||||
0179: 2009-03-08T07:00:00Z unix=1236495600 wall=2009-03-08T02:00:00 gap-until(2009-03-08T03:00:00) type=1 -04 EDT dst
|
||||
0180: 2009-11-01T06:00:00Z unix=1257055200 wall=2009-11-01T01:00:00 fold-until(2009-11-01T02:00:00) type=2 -05 EST
|
||||
0181: 2010-03-14T07:00:00Z unix=1268550000 wall=2010-03-14T02:00:00 gap-until(2010-03-14T03:00:00) type=1 -04 EDT dst
|
||||
0182: 2010-11-07T06:00:00Z unix=1289109600 wall=2010-11-07T01:00:00 fold-until(2010-11-07T02:00:00) type=2 -05 EST
|
||||
0183: 2011-03-13T07:00:00Z unix=1299999600 wall=2011-03-13T02:00:00 gap-until(2011-03-13T03:00:00) type=1 -04 EDT dst
|
||||
0184: 2011-11-06T06:00:00Z unix=1320559200 wall=2011-11-06T01:00:00 fold-until(2011-11-06T02:00:00) type=2 -05 EST
|
||||
0185: 2012-03-11T07:00:00Z unix=1331449200 wall=2012-03-11T02:00:00 gap-until(2012-03-11T03:00:00) type=1 -04 EDT dst
|
||||
0186: 2012-11-04T06:00:00Z unix=1352008800 wall=2012-11-04T01:00:00 fold-until(2012-11-04T02:00:00) type=2 -05 EST
|
||||
0187: 2013-03-10T07:00:00Z unix=1362898800 wall=2013-03-10T02:00:00 gap-until(2013-03-10T03:00:00) type=1 -04 EDT dst
|
||||
0188: 2013-11-03T06:00:00Z unix=1383458400 wall=2013-11-03T01:00:00 fold-until(2013-11-03T02:00:00) type=2 -05 EST
|
||||
0189: 2014-03-09T07:00:00Z unix=1394348400 wall=2014-03-09T02:00:00 gap-until(2014-03-09T03:00:00) type=1 -04 EDT dst
|
||||
0190: 2014-11-02T06:00:00Z unix=1414908000 wall=2014-11-02T01:00:00 fold-until(2014-11-02T02:00:00) type=2 -05 EST
|
||||
0191: 2015-03-08T07:00:00Z unix=1425798000 wall=2015-03-08T02:00:00 gap-until(2015-03-08T03:00:00) type=1 -04 EDT dst
|
||||
0192: 2015-11-01T06:00:00Z unix=1446357600 wall=2015-11-01T01:00:00 fold-until(2015-11-01T02:00:00) type=2 -05 EST
|
||||
0193: 2016-03-13T07:00:00Z unix=1457852400 wall=2016-03-13T02:00:00 gap-until(2016-03-13T03:00:00) type=1 -04 EDT dst
|
||||
0194: 2016-11-06T06:00:00Z unix=1478412000 wall=2016-11-06T01:00:00 fold-until(2016-11-06T02:00:00) type=2 -05 EST
|
||||
0195: 2017-03-12T07:00:00Z unix=1489302000 wall=2017-03-12T02:00:00 gap-until(2017-03-12T03:00:00) type=1 -04 EDT dst
|
||||
0196: 2017-11-05T06:00:00Z unix=1509861600 wall=2017-11-05T01:00:00 fold-until(2017-11-05T02:00:00) type=2 -05 EST
|
||||
0197: 2018-03-11T07:00:00Z unix=1520751600 wall=2018-03-11T02:00:00 gap-until(2018-03-11T03:00:00) type=1 -04 EDT dst
|
||||
0198: 2018-11-04T06:00:00Z unix=1541311200 wall=2018-11-04T01:00:00 fold-until(2018-11-04T02:00:00) type=2 -05 EST
|
||||
0199: 2019-03-10T07:00:00Z unix=1552201200 wall=2019-03-10T02:00:00 gap-until(2019-03-10T03:00:00) type=1 -04 EDT dst
|
||||
0200: 2019-11-03T06:00:00Z unix=1572760800 wall=2019-11-03T01:00:00 fold-until(2019-11-03T02:00:00) type=2 -05 EST
|
||||
0201: 2020-03-08T07:00:00Z unix=1583650800 wall=2020-03-08T02:00:00 gap-until(2020-03-08T03:00:00) type=1 -04 EDT dst
|
||||
0202: 2020-11-01T06:00:00Z unix=1604210400 wall=2020-11-01T01:00:00 fold-until(2020-11-01T02:00:00) type=2 -05 EST
|
||||
0203: 2021-03-14T07:00:00Z unix=1615705200 wall=2021-03-14T02:00:00 gap-until(2021-03-14T03:00:00) type=1 -04 EDT dst
|
||||
0204: 2021-11-07T06:00:00Z unix=1636264800 wall=2021-11-07T01:00:00 fold-until(2021-11-07T02:00:00) type=2 -05 EST
|
||||
0205: 2022-03-13T07:00:00Z unix=1647154800 wall=2022-03-13T02:00:00 gap-until(2022-03-13T03:00:00) type=1 -04 EDT dst
|
||||
0206: 2022-11-06T06:00:00Z unix=1667714400 wall=2022-11-06T01:00:00 fold-until(2022-11-06T02:00:00) type=2 -05 EST
|
||||
0207: 2023-03-12T07:00:00Z unix=1678604400 wall=2023-03-12T02:00:00 gap-until(2023-03-12T03:00:00) type=1 -04 EDT dst
|
||||
0208: 2023-11-05T06:00:00Z unix=1699164000 wall=2023-11-05T01:00:00 fold-until(2023-11-05T02:00:00) type=2 -05 EST
|
||||
0209: 2024-03-10T07:00:00Z unix=1710054000 wall=2024-03-10T02:00:00 gap-until(2024-03-10T03:00:00) type=1 -04 EDT dst
|
||||
0210: 2024-11-03T06:00:00Z unix=1730613600 wall=2024-11-03T01:00:00 fold-until(2024-11-03T02:00:00) type=2 -05 EST
|
||||
0211: 2025-03-09T07:00:00Z unix=1741503600 wall=2025-03-09T02:00:00 gap-until(2025-03-09T03:00:00) type=1 -04 EDT dst
|
||||
0212: 2025-11-02T06:00:00Z unix=1762063200 wall=2025-11-02T01:00:00 fold-until(2025-11-02T02:00:00) type=2 -05 EST
|
||||
0213: 2026-03-08T07:00:00Z unix=1772953200 wall=2026-03-08T02:00:00 gap-until(2026-03-08T03:00:00) type=1 -04 EDT dst
|
||||
0214: 2026-11-01T06:00:00Z unix=1793512800 wall=2026-11-01T01:00:00 fold-until(2026-11-01T02:00:00) type=2 -05 EST
|
||||
0215: 2027-03-14T07:00:00Z unix=1805007600 wall=2027-03-14T02:00:00 gap-until(2027-03-14T03:00:00) type=1 -04 EDT dst
|
||||
0216: 2027-11-07T06:00:00Z unix=1825567200 wall=2027-11-07T01:00:00 fold-until(2027-11-07T02:00:00) type=2 -05 EST
|
||||
0217: 2028-03-12T07:00:00Z unix=1836457200 wall=2028-03-12T02:00:00 gap-until(2028-03-12T03:00:00) type=1 -04 EDT dst
|
||||
0218: 2028-11-05T06:00:00Z unix=1857016800 wall=2028-11-05T01:00:00 fold-until(2028-11-05T02:00:00) type=2 -05 EST
|
||||
0219: 2029-03-11T07:00:00Z unix=1867906800 wall=2029-03-11T02:00:00 gap-until(2029-03-11T03:00:00) type=1 -04 EDT dst
|
||||
0220: 2029-11-04T06:00:00Z unix=1888466400 wall=2029-11-04T01:00:00 fold-until(2029-11-04T02:00:00) type=2 -05 EST
|
||||
0221: 2030-03-10T07:00:00Z unix=1899356400 wall=2030-03-10T02:00:00 gap-until(2030-03-10T03:00:00) type=1 -04 EDT dst
|
||||
0222: 2030-11-03T06:00:00Z unix=1919916000 wall=2030-11-03T01:00:00 fold-until(2030-11-03T02:00:00) type=2 -05 EST
|
||||
0223: 2031-03-09T07:00:00Z unix=1930806000 wall=2031-03-09T02:00:00 gap-until(2031-03-09T03:00:00) type=1 -04 EDT dst
|
||||
0224: 2031-11-02T06:00:00Z unix=1951365600 wall=2031-11-02T01:00:00 fold-until(2031-11-02T02:00:00) type=2 -05 EST
|
||||
0225: 2032-03-14T07:00:00Z unix=1962860400 wall=2032-03-14T02:00:00 gap-until(2032-03-14T03:00:00) type=1 -04 EDT dst
|
||||
0226: 2032-11-07T06:00:00Z unix=1983420000 wall=2032-11-07T01:00:00 fold-until(2032-11-07T02:00:00) type=2 -05 EST
|
||||
0227: 2033-03-13T07:00:00Z unix=1994310000 wall=2033-03-13T02:00:00 gap-until(2033-03-13T03:00:00) type=1 -04 EDT dst
|
||||
0228: 2033-11-06T06:00:00Z unix=2014869600 wall=2033-11-06T01:00:00 fold-until(2033-11-06T02:00:00) type=2 -05 EST
|
||||
0229: 2034-03-12T07:00:00Z unix=2025759600 wall=2034-03-12T02:00:00 gap-until(2034-03-12T03:00:00) type=1 -04 EDT dst
|
||||
0230: 2034-11-05T06:00:00Z unix=2046319200 wall=2034-11-05T01:00:00 fold-until(2034-11-05T02:00:00) type=2 -05 EST
|
||||
0231: 2035-03-11T07:00:00Z unix=2057209200 wall=2035-03-11T02:00:00 gap-until(2035-03-11T03:00:00) type=1 -04 EDT dst
|
||||
0232: 2035-11-04T06:00:00Z unix=2077768800 wall=2035-11-04T01:00:00 fold-until(2035-11-04T02:00:00) type=2 -05 EST
|
||||
0233: 2036-03-09T07:00:00Z unix=2088658800 wall=2036-03-09T02:00:00 gap-until(2036-03-09T03:00:00) type=1 -04 EDT dst
|
||||
0234: 2036-11-02T06:00:00Z unix=2109218400 wall=2036-11-02T01:00:00 fold-until(2036-11-02T02:00:00) type=2 -05 EST
|
||||
0235: 2037-03-08T07:00:00Z unix=2120108400 wall=2037-03-08T02:00:00 gap-until(2037-03-08T03:00:00) type=1 -04 EDT dst
|
||||
0236: 2037-11-01T06:00:00Z unix=2140668000 wall=2037-11-01T01:00:00 fold-until(2037-11-01T02:00:00) type=2 -05 EST
|
||||
POSIX TIME ZONE STRING
|
||||
EST5EDT,M3.2.0,M11.1.0
|
||||
160
src/tz/snapshots/jiff__tz__tzif__tests__America__Sitka_v1.snap
Normal file
160
src/tz/snapshots/jiff__tz__tzif__tests__America__Sitka_v1.snap
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse_v1())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
America/Sitka
|
||||
LOCAL TIME TYPES
|
||||
000: offset=+14:58:47 designation=LMT indicator=local/wall
|
||||
001: offset=-08 designation=PST indicator=local/wall
|
||||
002: offset=-07 designation=PWT dst indicator=local/wall
|
||||
003: offset=-07 designation=PPT dst indicator=ut/std
|
||||
004: offset=-07 designation=PDT dst indicator=local/wall
|
||||
005: offset=-09 designation=YST indicator=local/wall
|
||||
006: offset=-08 designation=AKDT dst indicator=local/wall
|
||||
007: offset=-09 designation=AKST indicator=local/wall
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-02T16:58:46 unambiguous type=0 +14:58:47 LMT
|
||||
0001: 1901-12-13T20:45:52Z unix=-2147483648 wall=1901-12-13T12:45:52 fold-until(1901-12-14T11:44:39) type=1 -08 PST
|
||||
0002: 1942-02-09T10:00:00Z unix=-880207200 wall=1942-02-09T02:00:00 gap-until(1942-02-09T03:00:00) type=2 -07 PWT dst
|
||||
0003: 1945-08-14T23:00:00Z unix=-769395600 wall=1945-08-14T16:00:00 unambiguous type=3 -07 PPT dst
|
||||
0004: 1945-09-30T09:00:00Z unix=-765385200 wall=1945-09-30T01:00:00 fold-until(1945-09-30T02:00:00) type=1 -08 PST
|
||||
0005: 1969-04-27T10:00:00Z unix=-21477600 wall=1969-04-27T02:00:00 gap-until(1969-04-27T03:00:00) type=4 -07 PDT dst
|
||||
0006: 1969-10-26T09:00:00Z unix=-5756400 wall=1969-10-26T01:00:00 fold-until(1969-10-26T02:00:00) type=1 -08 PST
|
||||
0007: 1970-04-26T10:00:00Z unix=9972000 wall=1970-04-26T02:00:00 gap-until(1970-04-26T03:00:00) type=4 -07 PDT dst
|
||||
0008: 1970-10-25T09:00:00Z unix=25693200 wall=1970-10-25T01:00:00 fold-until(1970-10-25T02:00:00) type=1 -08 PST
|
||||
0009: 1971-04-25T10:00:00Z unix=41421600 wall=1971-04-25T02:00:00 gap-until(1971-04-25T03:00:00) type=4 -07 PDT dst
|
||||
0010: 1971-10-31T09:00:00Z unix=57747600 wall=1971-10-31T01:00:00 fold-until(1971-10-31T02:00:00) type=1 -08 PST
|
||||
0011: 1972-04-30T10:00:00Z unix=73476000 wall=1972-04-30T02:00:00 gap-until(1972-04-30T03:00:00) type=4 -07 PDT dst
|
||||
0012: 1972-10-29T09:00:00Z unix=89197200 wall=1972-10-29T01:00:00 fold-until(1972-10-29T02:00:00) type=1 -08 PST
|
||||
0013: 1973-04-29T10:00:00Z unix=104925600 wall=1973-04-29T02:00:00 gap-until(1973-04-29T03:00:00) type=4 -07 PDT dst
|
||||
0014: 1973-10-28T09:00:00Z unix=120646800 wall=1973-10-28T01:00:00 fold-until(1973-10-28T02:00:00) type=1 -08 PST
|
||||
0015: 1974-01-06T10:00:00Z unix=126698400 wall=1974-01-06T02:00:00 gap-until(1974-01-06T03:00:00) type=4 -07 PDT dst
|
||||
0016: 1974-10-27T09:00:00Z unix=152096400 wall=1974-10-27T01:00:00 fold-until(1974-10-27T02:00:00) type=1 -08 PST
|
||||
0017: 1975-02-23T10:00:00Z unix=162381600 wall=1975-02-23T02:00:00 gap-until(1975-02-23T03:00:00) type=4 -07 PDT dst
|
||||
0018: 1975-10-26T09:00:00Z unix=183546000 wall=1975-10-26T01:00:00 fold-until(1975-10-26T02:00:00) type=1 -08 PST
|
||||
0019: 1976-04-25T10:00:00Z unix=199274400 wall=1976-04-25T02:00:00 gap-until(1976-04-25T03:00:00) type=4 -07 PDT dst
|
||||
0020: 1976-10-31T09:00:00Z unix=215600400 wall=1976-10-31T01:00:00 fold-until(1976-10-31T02:00:00) type=1 -08 PST
|
||||
0021: 1977-04-24T10:00:00Z unix=230724000 wall=1977-04-24T02:00:00 gap-until(1977-04-24T03:00:00) type=4 -07 PDT dst
|
||||
0022: 1977-10-30T09:00:00Z unix=247050000 wall=1977-10-30T01:00:00 fold-until(1977-10-30T02:00:00) type=1 -08 PST
|
||||
0023: 1978-04-30T10:00:00Z unix=262778400 wall=1978-04-30T02:00:00 gap-until(1978-04-30T03:00:00) type=4 -07 PDT dst
|
||||
0024: 1978-10-29T09:00:00Z unix=278499600 wall=1978-10-29T01:00:00 fold-until(1978-10-29T02:00:00) type=1 -08 PST
|
||||
0025: 1979-04-29T10:00:00Z unix=294228000 wall=1979-04-29T02:00:00 gap-until(1979-04-29T03:00:00) type=4 -07 PDT dst
|
||||
0026: 1979-10-28T09:00:00Z unix=309949200 wall=1979-10-28T01:00:00 fold-until(1979-10-28T02:00:00) type=1 -08 PST
|
||||
0027: 1980-04-27T10:00:00Z unix=325677600 wall=1980-04-27T02:00:00 gap-until(1980-04-27T03:00:00) type=4 -07 PDT dst
|
||||
0028: 1980-10-26T09:00:00Z unix=341398800 wall=1980-10-26T01:00:00 fold-until(1980-10-26T02:00:00) type=1 -08 PST
|
||||
0029: 1981-04-26T10:00:00Z unix=357127200 wall=1981-04-26T02:00:00 gap-until(1981-04-26T03:00:00) type=4 -07 PDT dst
|
||||
0030: 1981-10-25T09:00:00Z unix=372848400 wall=1981-10-25T01:00:00 fold-until(1981-10-25T02:00:00) type=1 -08 PST
|
||||
0031: 1982-04-25T10:00:00Z unix=388576800 wall=1982-04-25T02:00:00 gap-until(1982-04-25T03:00:00) type=4 -07 PDT dst
|
||||
0032: 1982-10-31T09:00:00Z unix=404902800 wall=1982-10-31T01:00:00 fold-until(1982-10-31T02:00:00) type=1 -08 PST
|
||||
0033: 1983-04-24T10:00:00Z unix=420026400 wall=1983-04-24T02:00:00 gap-until(1983-04-24T03:00:00) type=4 -07 PDT dst
|
||||
0034: 1983-10-30T09:00:00Z unix=436352400 wall=1983-10-30T00:00:00 fold-until(1983-10-30T02:00:00) type=5 -09 YST
|
||||
0035: 1983-11-30T09:00:00Z unix=439030800 wall=1983-11-30T00:00:00 unambiguous type=7 -09 AKST
|
||||
0036: 1984-04-29T11:00:00Z unix=452084400 wall=1984-04-29T02:00:00 gap-until(1984-04-29T03:00:00) type=6 -08 AKDT dst
|
||||
0037: 1984-10-28T10:00:00Z unix=467805600 wall=1984-10-28T01:00:00 fold-until(1984-10-28T02:00:00) type=7 -09 AKST
|
||||
0038: 1985-04-28T11:00:00Z unix=483534000 wall=1985-04-28T02:00:00 gap-until(1985-04-28T03:00:00) type=6 -08 AKDT dst
|
||||
0039: 1985-10-27T10:00:00Z unix=499255200 wall=1985-10-27T01:00:00 fold-until(1985-10-27T02:00:00) type=7 -09 AKST
|
||||
0040: 1986-04-27T11:00:00Z unix=514983600 wall=1986-04-27T02:00:00 gap-until(1986-04-27T03:00:00) type=6 -08 AKDT dst
|
||||
0041: 1986-10-26T10:00:00Z unix=530704800 wall=1986-10-26T01:00:00 fold-until(1986-10-26T02:00:00) type=7 -09 AKST
|
||||
0042: 1987-04-05T11:00:00Z unix=544618800 wall=1987-04-05T02:00:00 gap-until(1987-04-05T03:00:00) type=6 -08 AKDT dst
|
||||
0043: 1987-10-25T10:00:00Z unix=562154400 wall=1987-10-25T01:00:00 fold-until(1987-10-25T02:00:00) type=7 -09 AKST
|
||||
0044: 1988-04-03T11:00:00Z unix=576068400 wall=1988-04-03T02:00:00 gap-until(1988-04-03T03:00:00) type=6 -08 AKDT dst
|
||||
0045: 1988-10-30T10:00:00Z unix=594208800 wall=1988-10-30T01:00:00 fold-until(1988-10-30T02:00:00) type=7 -09 AKST
|
||||
0046: 1989-04-02T11:00:00Z unix=607518000 wall=1989-04-02T02:00:00 gap-until(1989-04-02T03:00:00) type=6 -08 AKDT dst
|
||||
0047: 1989-10-29T10:00:00Z unix=625658400 wall=1989-10-29T01:00:00 fold-until(1989-10-29T02:00:00) type=7 -09 AKST
|
||||
0048: 1990-04-01T11:00:00Z unix=638967600 wall=1990-04-01T02:00:00 gap-until(1990-04-01T03:00:00) type=6 -08 AKDT dst
|
||||
0049: 1990-10-28T10:00:00Z unix=657108000 wall=1990-10-28T01:00:00 fold-until(1990-10-28T02:00:00) type=7 -09 AKST
|
||||
0050: 1991-04-07T11:00:00Z unix=671022000 wall=1991-04-07T02:00:00 gap-until(1991-04-07T03:00:00) type=6 -08 AKDT dst
|
||||
0051: 1991-10-27T10:00:00Z unix=688557600 wall=1991-10-27T01:00:00 fold-until(1991-10-27T02:00:00) type=7 -09 AKST
|
||||
0052: 1992-04-05T11:00:00Z unix=702471600 wall=1992-04-05T02:00:00 gap-until(1992-04-05T03:00:00) type=6 -08 AKDT dst
|
||||
0053: 1992-10-25T10:00:00Z unix=720007200 wall=1992-10-25T01:00:00 fold-until(1992-10-25T02:00:00) type=7 -09 AKST
|
||||
0054: 1993-04-04T11:00:00Z unix=733921200 wall=1993-04-04T02:00:00 gap-until(1993-04-04T03:00:00) type=6 -08 AKDT dst
|
||||
0055: 1993-10-31T10:00:00Z unix=752061600 wall=1993-10-31T01:00:00 fold-until(1993-10-31T02:00:00) type=7 -09 AKST
|
||||
0056: 1994-04-03T11:00:00Z unix=765370800 wall=1994-04-03T02:00:00 gap-until(1994-04-03T03:00:00) type=6 -08 AKDT dst
|
||||
0057: 1994-10-30T10:00:00Z unix=783511200 wall=1994-10-30T01:00:00 fold-until(1994-10-30T02:00:00) type=7 -09 AKST
|
||||
0058: 1995-04-02T11:00:00Z unix=796820400 wall=1995-04-02T02:00:00 gap-until(1995-04-02T03:00:00) type=6 -08 AKDT dst
|
||||
0059: 1995-10-29T10:00:00Z unix=814960800 wall=1995-10-29T01:00:00 fold-until(1995-10-29T02:00:00) type=7 -09 AKST
|
||||
0060: 1996-04-07T11:00:00Z unix=828874800 wall=1996-04-07T02:00:00 gap-until(1996-04-07T03:00:00) type=6 -08 AKDT dst
|
||||
0061: 1996-10-27T10:00:00Z unix=846410400 wall=1996-10-27T01:00:00 fold-until(1996-10-27T02:00:00) type=7 -09 AKST
|
||||
0062: 1997-04-06T11:00:00Z unix=860324400 wall=1997-04-06T02:00:00 gap-until(1997-04-06T03:00:00) type=6 -08 AKDT dst
|
||||
0063: 1997-10-26T10:00:00Z unix=877860000 wall=1997-10-26T01:00:00 fold-until(1997-10-26T02:00:00) type=7 -09 AKST
|
||||
0064: 1998-04-05T11:00:00Z unix=891774000 wall=1998-04-05T02:00:00 gap-until(1998-04-05T03:00:00) type=6 -08 AKDT dst
|
||||
0065: 1998-10-25T10:00:00Z unix=909309600 wall=1998-10-25T01:00:00 fold-until(1998-10-25T02:00:00) type=7 -09 AKST
|
||||
0066: 1999-04-04T11:00:00Z unix=923223600 wall=1999-04-04T02:00:00 gap-until(1999-04-04T03:00:00) type=6 -08 AKDT dst
|
||||
0067: 1999-10-31T10:00:00Z unix=941364000 wall=1999-10-31T01:00:00 fold-until(1999-10-31T02:00:00) type=7 -09 AKST
|
||||
0068: 2000-04-02T11:00:00Z unix=954673200 wall=2000-04-02T02:00:00 gap-until(2000-04-02T03:00:00) type=6 -08 AKDT dst
|
||||
0069: 2000-10-29T10:00:00Z unix=972813600 wall=2000-10-29T01:00:00 fold-until(2000-10-29T02:00:00) type=7 -09 AKST
|
||||
0070: 2001-04-01T11:00:00Z unix=986122800 wall=2001-04-01T02:00:00 gap-until(2001-04-01T03:00:00) type=6 -08 AKDT dst
|
||||
0071: 2001-10-28T10:00:00Z unix=1004263200 wall=2001-10-28T01:00:00 fold-until(2001-10-28T02:00:00) type=7 -09 AKST
|
||||
0072: 2002-04-07T11:00:00Z unix=1018177200 wall=2002-04-07T02:00:00 gap-until(2002-04-07T03:00:00) type=6 -08 AKDT dst
|
||||
0073: 2002-10-27T10:00:00Z unix=1035712800 wall=2002-10-27T01:00:00 fold-until(2002-10-27T02:00:00) type=7 -09 AKST
|
||||
0074: 2003-04-06T11:00:00Z unix=1049626800 wall=2003-04-06T02:00:00 gap-until(2003-04-06T03:00:00) type=6 -08 AKDT dst
|
||||
0075: 2003-10-26T10:00:00Z unix=1067162400 wall=2003-10-26T01:00:00 fold-until(2003-10-26T02:00:00) type=7 -09 AKST
|
||||
0076: 2004-04-04T11:00:00Z unix=1081076400 wall=2004-04-04T02:00:00 gap-until(2004-04-04T03:00:00) type=6 -08 AKDT dst
|
||||
0077: 2004-10-31T10:00:00Z unix=1099216800 wall=2004-10-31T01:00:00 fold-until(2004-10-31T02:00:00) type=7 -09 AKST
|
||||
0078: 2005-04-03T11:00:00Z unix=1112526000 wall=2005-04-03T02:00:00 gap-until(2005-04-03T03:00:00) type=6 -08 AKDT dst
|
||||
0079: 2005-10-30T10:00:00Z unix=1130666400 wall=2005-10-30T01:00:00 fold-until(2005-10-30T02:00:00) type=7 -09 AKST
|
||||
0080: 2006-04-02T11:00:00Z unix=1143975600 wall=2006-04-02T02:00:00 gap-until(2006-04-02T03:00:00) type=6 -08 AKDT dst
|
||||
0081: 2006-10-29T10:00:00Z unix=1162116000 wall=2006-10-29T01:00:00 fold-until(2006-10-29T02:00:00) type=7 -09 AKST
|
||||
0082: 2007-03-11T11:00:00Z unix=1173610800 wall=2007-03-11T02:00:00 gap-until(2007-03-11T03:00:00) type=6 -08 AKDT dst
|
||||
0083: 2007-11-04T10:00:00Z unix=1194170400 wall=2007-11-04T01:00:00 fold-until(2007-11-04T02:00:00) type=7 -09 AKST
|
||||
0084: 2008-03-09T11:00:00Z unix=1205060400 wall=2008-03-09T02:00:00 gap-until(2008-03-09T03:00:00) type=6 -08 AKDT dst
|
||||
0085: 2008-11-02T10:00:00Z unix=1225620000 wall=2008-11-02T01:00:00 fold-until(2008-11-02T02:00:00) type=7 -09 AKST
|
||||
0086: 2009-03-08T11:00:00Z unix=1236510000 wall=2009-03-08T02:00:00 gap-until(2009-03-08T03:00:00) type=6 -08 AKDT dst
|
||||
0087: 2009-11-01T10:00:00Z unix=1257069600 wall=2009-11-01T01:00:00 fold-until(2009-11-01T02:00:00) type=7 -09 AKST
|
||||
0088: 2010-03-14T11:00:00Z unix=1268564400 wall=2010-03-14T02:00:00 gap-until(2010-03-14T03:00:00) type=6 -08 AKDT dst
|
||||
0089: 2010-11-07T10:00:00Z unix=1289124000 wall=2010-11-07T01:00:00 fold-until(2010-11-07T02:00:00) type=7 -09 AKST
|
||||
0090: 2011-03-13T11:00:00Z unix=1300014000 wall=2011-03-13T02:00:00 gap-until(2011-03-13T03:00:00) type=6 -08 AKDT dst
|
||||
0091: 2011-11-06T10:00:00Z unix=1320573600 wall=2011-11-06T01:00:00 fold-until(2011-11-06T02:00:00) type=7 -09 AKST
|
||||
0092: 2012-03-11T11:00:00Z unix=1331463600 wall=2012-03-11T02:00:00 gap-until(2012-03-11T03:00:00) type=6 -08 AKDT dst
|
||||
0093: 2012-11-04T10:00:00Z unix=1352023200 wall=2012-11-04T01:00:00 fold-until(2012-11-04T02:00:00) type=7 -09 AKST
|
||||
0094: 2013-03-10T11:00:00Z unix=1362913200 wall=2013-03-10T02:00:00 gap-until(2013-03-10T03:00:00) type=6 -08 AKDT dst
|
||||
0095: 2013-11-03T10:00:00Z unix=1383472800 wall=2013-11-03T01:00:00 fold-until(2013-11-03T02:00:00) type=7 -09 AKST
|
||||
0096: 2014-03-09T11:00:00Z unix=1394362800 wall=2014-03-09T02:00:00 gap-until(2014-03-09T03:00:00) type=6 -08 AKDT dst
|
||||
0097: 2014-11-02T10:00:00Z unix=1414922400 wall=2014-11-02T01:00:00 fold-until(2014-11-02T02:00:00) type=7 -09 AKST
|
||||
0098: 2015-03-08T11:00:00Z unix=1425812400 wall=2015-03-08T02:00:00 gap-until(2015-03-08T03:00:00) type=6 -08 AKDT dst
|
||||
0099: 2015-11-01T10:00:00Z unix=1446372000 wall=2015-11-01T01:00:00 fold-until(2015-11-01T02:00:00) type=7 -09 AKST
|
||||
0100: 2016-03-13T11:00:00Z unix=1457866800 wall=2016-03-13T02:00:00 gap-until(2016-03-13T03:00:00) type=6 -08 AKDT dst
|
||||
0101: 2016-11-06T10:00:00Z unix=1478426400 wall=2016-11-06T01:00:00 fold-until(2016-11-06T02:00:00) type=7 -09 AKST
|
||||
0102: 2017-03-12T11:00:00Z unix=1489316400 wall=2017-03-12T02:00:00 gap-until(2017-03-12T03:00:00) type=6 -08 AKDT dst
|
||||
0103: 2017-11-05T10:00:00Z unix=1509876000 wall=2017-11-05T01:00:00 fold-until(2017-11-05T02:00:00) type=7 -09 AKST
|
||||
0104: 2018-03-11T11:00:00Z unix=1520766000 wall=2018-03-11T02:00:00 gap-until(2018-03-11T03:00:00) type=6 -08 AKDT dst
|
||||
0105: 2018-11-04T10:00:00Z unix=1541325600 wall=2018-11-04T01:00:00 fold-until(2018-11-04T02:00:00) type=7 -09 AKST
|
||||
0106: 2019-03-10T11:00:00Z unix=1552215600 wall=2019-03-10T02:00:00 gap-until(2019-03-10T03:00:00) type=6 -08 AKDT dst
|
||||
0107: 2019-11-03T10:00:00Z unix=1572775200 wall=2019-11-03T01:00:00 fold-until(2019-11-03T02:00:00) type=7 -09 AKST
|
||||
0108: 2020-03-08T11:00:00Z unix=1583665200 wall=2020-03-08T02:00:00 gap-until(2020-03-08T03:00:00) type=6 -08 AKDT dst
|
||||
0109: 2020-11-01T10:00:00Z unix=1604224800 wall=2020-11-01T01:00:00 fold-until(2020-11-01T02:00:00) type=7 -09 AKST
|
||||
0110: 2021-03-14T11:00:00Z unix=1615719600 wall=2021-03-14T02:00:00 gap-until(2021-03-14T03:00:00) type=6 -08 AKDT dst
|
||||
0111: 2021-11-07T10:00:00Z unix=1636279200 wall=2021-11-07T01:00:00 fold-until(2021-11-07T02:00:00) type=7 -09 AKST
|
||||
0112: 2022-03-13T11:00:00Z unix=1647169200 wall=2022-03-13T02:00:00 gap-until(2022-03-13T03:00:00) type=6 -08 AKDT dst
|
||||
0113: 2022-11-06T10:00:00Z unix=1667728800 wall=2022-11-06T01:00:00 fold-until(2022-11-06T02:00:00) type=7 -09 AKST
|
||||
0114: 2023-03-12T11:00:00Z unix=1678618800 wall=2023-03-12T02:00:00 gap-until(2023-03-12T03:00:00) type=6 -08 AKDT dst
|
||||
0115: 2023-11-05T10:00:00Z unix=1699178400 wall=2023-11-05T01:00:00 fold-until(2023-11-05T02:00:00) type=7 -09 AKST
|
||||
0116: 2024-03-10T11:00:00Z unix=1710068400 wall=2024-03-10T02:00:00 gap-until(2024-03-10T03:00:00) type=6 -08 AKDT dst
|
||||
0117: 2024-11-03T10:00:00Z unix=1730628000 wall=2024-11-03T01:00:00 fold-until(2024-11-03T02:00:00) type=7 -09 AKST
|
||||
0118: 2025-03-09T11:00:00Z unix=1741518000 wall=2025-03-09T02:00:00 gap-until(2025-03-09T03:00:00) type=6 -08 AKDT dst
|
||||
0119: 2025-11-02T10:00:00Z unix=1762077600 wall=2025-11-02T01:00:00 fold-until(2025-11-02T02:00:00) type=7 -09 AKST
|
||||
0120: 2026-03-08T11:00:00Z unix=1772967600 wall=2026-03-08T02:00:00 gap-until(2026-03-08T03:00:00) type=6 -08 AKDT dst
|
||||
0121: 2026-11-01T10:00:00Z unix=1793527200 wall=2026-11-01T01:00:00 fold-until(2026-11-01T02:00:00) type=7 -09 AKST
|
||||
0122: 2027-03-14T11:00:00Z unix=1805022000 wall=2027-03-14T02:00:00 gap-until(2027-03-14T03:00:00) type=6 -08 AKDT dst
|
||||
0123: 2027-11-07T10:00:00Z unix=1825581600 wall=2027-11-07T01:00:00 fold-until(2027-11-07T02:00:00) type=7 -09 AKST
|
||||
0124: 2028-03-12T11:00:00Z unix=1836471600 wall=2028-03-12T02:00:00 gap-until(2028-03-12T03:00:00) type=6 -08 AKDT dst
|
||||
0125: 2028-11-05T10:00:00Z unix=1857031200 wall=2028-11-05T01:00:00 fold-until(2028-11-05T02:00:00) type=7 -09 AKST
|
||||
0126: 2029-03-11T11:00:00Z unix=1867921200 wall=2029-03-11T02:00:00 gap-until(2029-03-11T03:00:00) type=6 -08 AKDT dst
|
||||
0127: 2029-11-04T10:00:00Z unix=1888480800 wall=2029-11-04T01:00:00 fold-until(2029-11-04T02:00:00) type=7 -09 AKST
|
||||
0128: 2030-03-10T11:00:00Z unix=1899370800 wall=2030-03-10T02:00:00 gap-until(2030-03-10T03:00:00) type=6 -08 AKDT dst
|
||||
0129: 2030-11-03T10:00:00Z unix=1919930400 wall=2030-11-03T01:00:00 fold-until(2030-11-03T02:00:00) type=7 -09 AKST
|
||||
0130: 2031-03-09T11:00:00Z unix=1930820400 wall=2031-03-09T02:00:00 gap-until(2031-03-09T03:00:00) type=6 -08 AKDT dst
|
||||
0131: 2031-11-02T10:00:00Z unix=1951380000 wall=2031-11-02T01:00:00 fold-until(2031-11-02T02:00:00) type=7 -09 AKST
|
||||
0132: 2032-03-14T11:00:00Z unix=1962874800 wall=2032-03-14T02:00:00 gap-until(2032-03-14T03:00:00) type=6 -08 AKDT dst
|
||||
0133: 2032-11-07T10:00:00Z unix=1983434400 wall=2032-11-07T01:00:00 fold-until(2032-11-07T02:00:00) type=7 -09 AKST
|
||||
0134: 2033-03-13T11:00:00Z unix=1994324400 wall=2033-03-13T02:00:00 gap-until(2033-03-13T03:00:00) type=6 -08 AKDT dst
|
||||
0135: 2033-11-06T10:00:00Z unix=2014884000 wall=2033-11-06T01:00:00 fold-until(2033-11-06T02:00:00) type=7 -09 AKST
|
||||
0136: 2034-03-12T11:00:00Z unix=2025774000 wall=2034-03-12T02:00:00 gap-until(2034-03-12T03:00:00) type=6 -08 AKDT dst
|
||||
0137: 2034-11-05T10:00:00Z unix=2046333600 wall=2034-11-05T01:00:00 fold-until(2034-11-05T02:00:00) type=7 -09 AKST
|
||||
0138: 2035-03-11T11:00:00Z unix=2057223600 wall=2035-03-11T02:00:00 gap-until(2035-03-11T03:00:00) type=6 -08 AKDT dst
|
||||
0139: 2035-11-04T10:00:00Z unix=2077783200 wall=2035-11-04T01:00:00 fold-until(2035-11-04T02:00:00) type=7 -09 AKST
|
||||
0140: 2036-03-09T11:00:00Z unix=2088673200 wall=2036-03-09T02:00:00 gap-until(2036-03-09T03:00:00) type=6 -08 AKDT dst
|
||||
0141: 2036-11-02T10:00:00Z unix=2109232800 wall=2036-11-02T01:00:00 fold-until(2036-11-02T02:00:00) type=7 -09 AKST
|
||||
0142: 2037-03-08T11:00:00Z unix=2120122800 wall=2037-03-08T02:00:00 gap-until(2037-03-08T03:00:00) type=6 -08 AKDT dst
|
||||
0143: 2037-11-01T10:00:00Z unix=2140682400 wall=2037-11-01T01:00:00 fold-until(2037-11-01T02:00:00) type=7 -09 AKST
|
||||
164
src/tz/snapshots/jiff__tz__tzif__tests__America__Sitka_v2+.snap
Normal file
164
src/tz/snapshots/jiff__tz__tzif__tests__America__Sitka_v2+.snap
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
America/Sitka
|
||||
LOCAL TIME TYPES
|
||||
000: offset=+14:58:47 designation=LMT indicator=local/wall
|
||||
001: offset=-09:01:13 designation=LMT indicator=local/wall
|
||||
002: offset=-08 designation=PST indicator=local/wall
|
||||
003: offset=-07 designation=PWT dst indicator=local/wall
|
||||
004: offset=-07 designation=PPT dst indicator=ut/std
|
||||
005: offset=-07 designation=PDT dst indicator=local/wall
|
||||
006: offset=-09 designation=YST indicator=local/wall
|
||||
007: offset=-08 designation=AKDT dst indicator=local/wall
|
||||
008: offset=-09 designation=AKST indicator=local/wall
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-02T16:58:46 unambiguous type=0 +14:58:47 LMT
|
||||
0001: 1867-10-19T00:31:13Z unix=-3225223727 wall=1867-10-18T15:30:00 fold-until(1867-10-19T15:30:00) type=1 -09:01:13 LMT
|
||||
0002: 1900-08-20T21:01:13Z unix=-2188954727 wall=1900-08-20T12:00:00 gap-until(1900-08-20T13:01:13) type=2 -08 PST
|
||||
0003: 1942-02-09T10:00:00Z unix=-880207200 wall=1942-02-09T02:00:00 gap-until(1942-02-09T03:00:00) type=3 -07 PWT dst
|
||||
0004: 1945-08-14T23:00:00Z unix=-769395600 wall=1945-08-14T16:00:00 unambiguous type=4 -07 PPT dst
|
||||
0005: 1945-09-30T09:00:00Z unix=-765385200 wall=1945-09-30T01:00:00 fold-until(1945-09-30T02:00:00) type=2 -08 PST
|
||||
0006: 1969-04-27T10:00:00Z unix=-21477600 wall=1969-04-27T02:00:00 gap-until(1969-04-27T03:00:00) type=5 -07 PDT dst
|
||||
0007: 1969-10-26T09:00:00Z unix=-5756400 wall=1969-10-26T01:00:00 fold-until(1969-10-26T02:00:00) type=2 -08 PST
|
||||
0008: 1970-04-26T10:00:00Z unix=9972000 wall=1970-04-26T02:00:00 gap-until(1970-04-26T03:00:00) type=5 -07 PDT dst
|
||||
0009: 1970-10-25T09:00:00Z unix=25693200 wall=1970-10-25T01:00:00 fold-until(1970-10-25T02:00:00) type=2 -08 PST
|
||||
0010: 1971-04-25T10:00:00Z unix=41421600 wall=1971-04-25T02:00:00 gap-until(1971-04-25T03:00:00) type=5 -07 PDT dst
|
||||
0011: 1971-10-31T09:00:00Z unix=57747600 wall=1971-10-31T01:00:00 fold-until(1971-10-31T02:00:00) type=2 -08 PST
|
||||
0012: 1972-04-30T10:00:00Z unix=73476000 wall=1972-04-30T02:00:00 gap-until(1972-04-30T03:00:00) type=5 -07 PDT dst
|
||||
0013: 1972-10-29T09:00:00Z unix=89197200 wall=1972-10-29T01:00:00 fold-until(1972-10-29T02:00:00) type=2 -08 PST
|
||||
0014: 1973-04-29T10:00:00Z unix=104925600 wall=1973-04-29T02:00:00 gap-until(1973-04-29T03:00:00) type=5 -07 PDT dst
|
||||
0015: 1973-10-28T09:00:00Z unix=120646800 wall=1973-10-28T01:00:00 fold-until(1973-10-28T02:00:00) type=2 -08 PST
|
||||
0016: 1974-01-06T10:00:00Z unix=126698400 wall=1974-01-06T02:00:00 gap-until(1974-01-06T03:00:00) type=5 -07 PDT dst
|
||||
0017: 1974-10-27T09:00:00Z unix=152096400 wall=1974-10-27T01:00:00 fold-until(1974-10-27T02:00:00) type=2 -08 PST
|
||||
0018: 1975-02-23T10:00:00Z unix=162381600 wall=1975-02-23T02:00:00 gap-until(1975-02-23T03:00:00) type=5 -07 PDT dst
|
||||
0019: 1975-10-26T09:00:00Z unix=183546000 wall=1975-10-26T01:00:00 fold-until(1975-10-26T02:00:00) type=2 -08 PST
|
||||
0020: 1976-04-25T10:00:00Z unix=199274400 wall=1976-04-25T02:00:00 gap-until(1976-04-25T03:00:00) type=5 -07 PDT dst
|
||||
0021: 1976-10-31T09:00:00Z unix=215600400 wall=1976-10-31T01:00:00 fold-until(1976-10-31T02:00:00) type=2 -08 PST
|
||||
0022: 1977-04-24T10:00:00Z unix=230724000 wall=1977-04-24T02:00:00 gap-until(1977-04-24T03:00:00) type=5 -07 PDT dst
|
||||
0023: 1977-10-30T09:00:00Z unix=247050000 wall=1977-10-30T01:00:00 fold-until(1977-10-30T02:00:00) type=2 -08 PST
|
||||
0024: 1978-04-30T10:00:00Z unix=262778400 wall=1978-04-30T02:00:00 gap-until(1978-04-30T03:00:00) type=5 -07 PDT dst
|
||||
0025: 1978-10-29T09:00:00Z unix=278499600 wall=1978-10-29T01:00:00 fold-until(1978-10-29T02:00:00) type=2 -08 PST
|
||||
0026: 1979-04-29T10:00:00Z unix=294228000 wall=1979-04-29T02:00:00 gap-until(1979-04-29T03:00:00) type=5 -07 PDT dst
|
||||
0027: 1979-10-28T09:00:00Z unix=309949200 wall=1979-10-28T01:00:00 fold-until(1979-10-28T02:00:00) type=2 -08 PST
|
||||
0028: 1980-04-27T10:00:00Z unix=325677600 wall=1980-04-27T02:00:00 gap-until(1980-04-27T03:00:00) type=5 -07 PDT dst
|
||||
0029: 1980-10-26T09:00:00Z unix=341398800 wall=1980-10-26T01:00:00 fold-until(1980-10-26T02:00:00) type=2 -08 PST
|
||||
0030: 1981-04-26T10:00:00Z unix=357127200 wall=1981-04-26T02:00:00 gap-until(1981-04-26T03:00:00) type=5 -07 PDT dst
|
||||
0031: 1981-10-25T09:00:00Z unix=372848400 wall=1981-10-25T01:00:00 fold-until(1981-10-25T02:00:00) type=2 -08 PST
|
||||
0032: 1982-04-25T10:00:00Z unix=388576800 wall=1982-04-25T02:00:00 gap-until(1982-04-25T03:00:00) type=5 -07 PDT dst
|
||||
0033: 1982-10-31T09:00:00Z unix=404902800 wall=1982-10-31T01:00:00 fold-until(1982-10-31T02:00:00) type=2 -08 PST
|
||||
0034: 1983-04-24T10:00:00Z unix=420026400 wall=1983-04-24T02:00:00 gap-until(1983-04-24T03:00:00) type=5 -07 PDT dst
|
||||
0035: 1983-10-30T09:00:00Z unix=436352400 wall=1983-10-30T00:00:00 fold-until(1983-10-30T02:00:00) type=6 -09 YST
|
||||
0036: 1983-11-30T09:00:00Z unix=439030800 wall=1983-11-30T00:00:00 unambiguous type=8 -09 AKST
|
||||
0037: 1984-04-29T11:00:00Z unix=452084400 wall=1984-04-29T02:00:00 gap-until(1984-04-29T03:00:00) type=7 -08 AKDT dst
|
||||
0038: 1984-10-28T10:00:00Z unix=467805600 wall=1984-10-28T01:00:00 fold-until(1984-10-28T02:00:00) type=8 -09 AKST
|
||||
0039: 1985-04-28T11:00:00Z unix=483534000 wall=1985-04-28T02:00:00 gap-until(1985-04-28T03:00:00) type=7 -08 AKDT dst
|
||||
0040: 1985-10-27T10:00:00Z unix=499255200 wall=1985-10-27T01:00:00 fold-until(1985-10-27T02:00:00) type=8 -09 AKST
|
||||
0041: 1986-04-27T11:00:00Z unix=514983600 wall=1986-04-27T02:00:00 gap-until(1986-04-27T03:00:00) type=7 -08 AKDT dst
|
||||
0042: 1986-10-26T10:00:00Z unix=530704800 wall=1986-10-26T01:00:00 fold-until(1986-10-26T02:00:00) type=8 -09 AKST
|
||||
0043: 1987-04-05T11:00:00Z unix=544618800 wall=1987-04-05T02:00:00 gap-until(1987-04-05T03:00:00) type=7 -08 AKDT dst
|
||||
0044: 1987-10-25T10:00:00Z unix=562154400 wall=1987-10-25T01:00:00 fold-until(1987-10-25T02:00:00) type=8 -09 AKST
|
||||
0045: 1988-04-03T11:00:00Z unix=576068400 wall=1988-04-03T02:00:00 gap-until(1988-04-03T03:00:00) type=7 -08 AKDT dst
|
||||
0046: 1988-10-30T10:00:00Z unix=594208800 wall=1988-10-30T01:00:00 fold-until(1988-10-30T02:00:00) type=8 -09 AKST
|
||||
0047: 1989-04-02T11:00:00Z unix=607518000 wall=1989-04-02T02:00:00 gap-until(1989-04-02T03:00:00) type=7 -08 AKDT dst
|
||||
0048: 1989-10-29T10:00:00Z unix=625658400 wall=1989-10-29T01:00:00 fold-until(1989-10-29T02:00:00) type=8 -09 AKST
|
||||
0049: 1990-04-01T11:00:00Z unix=638967600 wall=1990-04-01T02:00:00 gap-until(1990-04-01T03:00:00) type=7 -08 AKDT dst
|
||||
0050: 1990-10-28T10:00:00Z unix=657108000 wall=1990-10-28T01:00:00 fold-until(1990-10-28T02:00:00) type=8 -09 AKST
|
||||
0051: 1991-04-07T11:00:00Z unix=671022000 wall=1991-04-07T02:00:00 gap-until(1991-04-07T03:00:00) type=7 -08 AKDT dst
|
||||
0052: 1991-10-27T10:00:00Z unix=688557600 wall=1991-10-27T01:00:00 fold-until(1991-10-27T02:00:00) type=8 -09 AKST
|
||||
0053: 1992-04-05T11:00:00Z unix=702471600 wall=1992-04-05T02:00:00 gap-until(1992-04-05T03:00:00) type=7 -08 AKDT dst
|
||||
0054: 1992-10-25T10:00:00Z unix=720007200 wall=1992-10-25T01:00:00 fold-until(1992-10-25T02:00:00) type=8 -09 AKST
|
||||
0055: 1993-04-04T11:00:00Z unix=733921200 wall=1993-04-04T02:00:00 gap-until(1993-04-04T03:00:00) type=7 -08 AKDT dst
|
||||
0056: 1993-10-31T10:00:00Z unix=752061600 wall=1993-10-31T01:00:00 fold-until(1993-10-31T02:00:00) type=8 -09 AKST
|
||||
0057: 1994-04-03T11:00:00Z unix=765370800 wall=1994-04-03T02:00:00 gap-until(1994-04-03T03:00:00) type=7 -08 AKDT dst
|
||||
0058: 1994-10-30T10:00:00Z unix=783511200 wall=1994-10-30T01:00:00 fold-until(1994-10-30T02:00:00) type=8 -09 AKST
|
||||
0059: 1995-04-02T11:00:00Z unix=796820400 wall=1995-04-02T02:00:00 gap-until(1995-04-02T03:00:00) type=7 -08 AKDT dst
|
||||
0060: 1995-10-29T10:00:00Z unix=814960800 wall=1995-10-29T01:00:00 fold-until(1995-10-29T02:00:00) type=8 -09 AKST
|
||||
0061: 1996-04-07T11:00:00Z unix=828874800 wall=1996-04-07T02:00:00 gap-until(1996-04-07T03:00:00) type=7 -08 AKDT dst
|
||||
0062: 1996-10-27T10:00:00Z unix=846410400 wall=1996-10-27T01:00:00 fold-until(1996-10-27T02:00:00) type=8 -09 AKST
|
||||
0063: 1997-04-06T11:00:00Z unix=860324400 wall=1997-04-06T02:00:00 gap-until(1997-04-06T03:00:00) type=7 -08 AKDT dst
|
||||
0064: 1997-10-26T10:00:00Z unix=877860000 wall=1997-10-26T01:00:00 fold-until(1997-10-26T02:00:00) type=8 -09 AKST
|
||||
0065: 1998-04-05T11:00:00Z unix=891774000 wall=1998-04-05T02:00:00 gap-until(1998-04-05T03:00:00) type=7 -08 AKDT dst
|
||||
0066: 1998-10-25T10:00:00Z unix=909309600 wall=1998-10-25T01:00:00 fold-until(1998-10-25T02:00:00) type=8 -09 AKST
|
||||
0067: 1999-04-04T11:00:00Z unix=923223600 wall=1999-04-04T02:00:00 gap-until(1999-04-04T03:00:00) type=7 -08 AKDT dst
|
||||
0068: 1999-10-31T10:00:00Z unix=941364000 wall=1999-10-31T01:00:00 fold-until(1999-10-31T02:00:00) type=8 -09 AKST
|
||||
0069: 2000-04-02T11:00:00Z unix=954673200 wall=2000-04-02T02:00:00 gap-until(2000-04-02T03:00:00) type=7 -08 AKDT dst
|
||||
0070: 2000-10-29T10:00:00Z unix=972813600 wall=2000-10-29T01:00:00 fold-until(2000-10-29T02:00:00) type=8 -09 AKST
|
||||
0071: 2001-04-01T11:00:00Z unix=986122800 wall=2001-04-01T02:00:00 gap-until(2001-04-01T03:00:00) type=7 -08 AKDT dst
|
||||
0072: 2001-10-28T10:00:00Z unix=1004263200 wall=2001-10-28T01:00:00 fold-until(2001-10-28T02:00:00) type=8 -09 AKST
|
||||
0073: 2002-04-07T11:00:00Z unix=1018177200 wall=2002-04-07T02:00:00 gap-until(2002-04-07T03:00:00) type=7 -08 AKDT dst
|
||||
0074: 2002-10-27T10:00:00Z unix=1035712800 wall=2002-10-27T01:00:00 fold-until(2002-10-27T02:00:00) type=8 -09 AKST
|
||||
0075: 2003-04-06T11:00:00Z unix=1049626800 wall=2003-04-06T02:00:00 gap-until(2003-04-06T03:00:00) type=7 -08 AKDT dst
|
||||
0076: 2003-10-26T10:00:00Z unix=1067162400 wall=2003-10-26T01:00:00 fold-until(2003-10-26T02:00:00) type=8 -09 AKST
|
||||
0077: 2004-04-04T11:00:00Z unix=1081076400 wall=2004-04-04T02:00:00 gap-until(2004-04-04T03:00:00) type=7 -08 AKDT dst
|
||||
0078: 2004-10-31T10:00:00Z unix=1099216800 wall=2004-10-31T01:00:00 fold-until(2004-10-31T02:00:00) type=8 -09 AKST
|
||||
0079: 2005-04-03T11:00:00Z unix=1112526000 wall=2005-04-03T02:00:00 gap-until(2005-04-03T03:00:00) type=7 -08 AKDT dst
|
||||
0080: 2005-10-30T10:00:00Z unix=1130666400 wall=2005-10-30T01:00:00 fold-until(2005-10-30T02:00:00) type=8 -09 AKST
|
||||
0081: 2006-04-02T11:00:00Z unix=1143975600 wall=2006-04-02T02:00:00 gap-until(2006-04-02T03:00:00) type=7 -08 AKDT dst
|
||||
0082: 2006-10-29T10:00:00Z unix=1162116000 wall=2006-10-29T01:00:00 fold-until(2006-10-29T02:00:00) type=8 -09 AKST
|
||||
0083: 2007-03-11T11:00:00Z unix=1173610800 wall=2007-03-11T02:00:00 gap-until(2007-03-11T03:00:00) type=7 -08 AKDT dst
|
||||
0084: 2007-11-04T10:00:00Z unix=1194170400 wall=2007-11-04T01:00:00 fold-until(2007-11-04T02:00:00) type=8 -09 AKST
|
||||
0085: 2008-03-09T11:00:00Z unix=1205060400 wall=2008-03-09T02:00:00 gap-until(2008-03-09T03:00:00) type=7 -08 AKDT dst
|
||||
0086: 2008-11-02T10:00:00Z unix=1225620000 wall=2008-11-02T01:00:00 fold-until(2008-11-02T02:00:00) type=8 -09 AKST
|
||||
0087: 2009-03-08T11:00:00Z unix=1236510000 wall=2009-03-08T02:00:00 gap-until(2009-03-08T03:00:00) type=7 -08 AKDT dst
|
||||
0088: 2009-11-01T10:00:00Z unix=1257069600 wall=2009-11-01T01:00:00 fold-until(2009-11-01T02:00:00) type=8 -09 AKST
|
||||
0089: 2010-03-14T11:00:00Z unix=1268564400 wall=2010-03-14T02:00:00 gap-until(2010-03-14T03:00:00) type=7 -08 AKDT dst
|
||||
0090: 2010-11-07T10:00:00Z unix=1289124000 wall=2010-11-07T01:00:00 fold-until(2010-11-07T02:00:00) type=8 -09 AKST
|
||||
0091: 2011-03-13T11:00:00Z unix=1300014000 wall=2011-03-13T02:00:00 gap-until(2011-03-13T03:00:00) type=7 -08 AKDT dst
|
||||
0092: 2011-11-06T10:00:00Z unix=1320573600 wall=2011-11-06T01:00:00 fold-until(2011-11-06T02:00:00) type=8 -09 AKST
|
||||
0093: 2012-03-11T11:00:00Z unix=1331463600 wall=2012-03-11T02:00:00 gap-until(2012-03-11T03:00:00) type=7 -08 AKDT dst
|
||||
0094: 2012-11-04T10:00:00Z unix=1352023200 wall=2012-11-04T01:00:00 fold-until(2012-11-04T02:00:00) type=8 -09 AKST
|
||||
0095: 2013-03-10T11:00:00Z unix=1362913200 wall=2013-03-10T02:00:00 gap-until(2013-03-10T03:00:00) type=7 -08 AKDT dst
|
||||
0096: 2013-11-03T10:00:00Z unix=1383472800 wall=2013-11-03T01:00:00 fold-until(2013-11-03T02:00:00) type=8 -09 AKST
|
||||
0097: 2014-03-09T11:00:00Z unix=1394362800 wall=2014-03-09T02:00:00 gap-until(2014-03-09T03:00:00) type=7 -08 AKDT dst
|
||||
0098: 2014-11-02T10:00:00Z unix=1414922400 wall=2014-11-02T01:00:00 fold-until(2014-11-02T02:00:00) type=8 -09 AKST
|
||||
0099: 2015-03-08T11:00:00Z unix=1425812400 wall=2015-03-08T02:00:00 gap-until(2015-03-08T03:00:00) type=7 -08 AKDT dst
|
||||
0100: 2015-11-01T10:00:00Z unix=1446372000 wall=2015-11-01T01:00:00 fold-until(2015-11-01T02:00:00) type=8 -09 AKST
|
||||
0101: 2016-03-13T11:00:00Z unix=1457866800 wall=2016-03-13T02:00:00 gap-until(2016-03-13T03:00:00) type=7 -08 AKDT dst
|
||||
0102: 2016-11-06T10:00:00Z unix=1478426400 wall=2016-11-06T01:00:00 fold-until(2016-11-06T02:00:00) type=8 -09 AKST
|
||||
0103: 2017-03-12T11:00:00Z unix=1489316400 wall=2017-03-12T02:00:00 gap-until(2017-03-12T03:00:00) type=7 -08 AKDT dst
|
||||
0104: 2017-11-05T10:00:00Z unix=1509876000 wall=2017-11-05T01:00:00 fold-until(2017-11-05T02:00:00) type=8 -09 AKST
|
||||
0105: 2018-03-11T11:00:00Z unix=1520766000 wall=2018-03-11T02:00:00 gap-until(2018-03-11T03:00:00) type=7 -08 AKDT dst
|
||||
0106: 2018-11-04T10:00:00Z unix=1541325600 wall=2018-11-04T01:00:00 fold-until(2018-11-04T02:00:00) type=8 -09 AKST
|
||||
0107: 2019-03-10T11:00:00Z unix=1552215600 wall=2019-03-10T02:00:00 gap-until(2019-03-10T03:00:00) type=7 -08 AKDT dst
|
||||
0108: 2019-11-03T10:00:00Z unix=1572775200 wall=2019-11-03T01:00:00 fold-until(2019-11-03T02:00:00) type=8 -09 AKST
|
||||
0109: 2020-03-08T11:00:00Z unix=1583665200 wall=2020-03-08T02:00:00 gap-until(2020-03-08T03:00:00) type=7 -08 AKDT dst
|
||||
0110: 2020-11-01T10:00:00Z unix=1604224800 wall=2020-11-01T01:00:00 fold-until(2020-11-01T02:00:00) type=8 -09 AKST
|
||||
0111: 2021-03-14T11:00:00Z unix=1615719600 wall=2021-03-14T02:00:00 gap-until(2021-03-14T03:00:00) type=7 -08 AKDT dst
|
||||
0112: 2021-11-07T10:00:00Z unix=1636279200 wall=2021-11-07T01:00:00 fold-until(2021-11-07T02:00:00) type=8 -09 AKST
|
||||
0113: 2022-03-13T11:00:00Z unix=1647169200 wall=2022-03-13T02:00:00 gap-until(2022-03-13T03:00:00) type=7 -08 AKDT dst
|
||||
0114: 2022-11-06T10:00:00Z unix=1667728800 wall=2022-11-06T01:00:00 fold-until(2022-11-06T02:00:00) type=8 -09 AKST
|
||||
0115: 2023-03-12T11:00:00Z unix=1678618800 wall=2023-03-12T02:00:00 gap-until(2023-03-12T03:00:00) type=7 -08 AKDT dst
|
||||
0116: 2023-11-05T10:00:00Z unix=1699178400 wall=2023-11-05T01:00:00 fold-until(2023-11-05T02:00:00) type=8 -09 AKST
|
||||
0117: 2024-03-10T11:00:00Z unix=1710068400 wall=2024-03-10T02:00:00 gap-until(2024-03-10T03:00:00) type=7 -08 AKDT dst
|
||||
0118: 2024-11-03T10:00:00Z unix=1730628000 wall=2024-11-03T01:00:00 fold-until(2024-11-03T02:00:00) type=8 -09 AKST
|
||||
0119: 2025-03-09T11:00:00Z unix=1741518000 wall=2025-03-09T02:00:00 gap-until(2025-03-09T03:00:00) type=7 -08 AKDT dst
|
||||
0120: 2025-11-02T10:00:00Z unix=1762077600 wall=2025-11-02T01:00:00 fold-until(2025-11-02T02:00:00) type=8 -09 AKST
|
||||
0121: 2026-03-08T11:00:00Z unix=1772967600 wall=2026-03-08T02:00:00 gap-until(2026-03-08T03:00:00) type=7 -08 AKDT dst
|
||||
0122: 2026-11-01T10:00:00Z unix=1793527200 wall=2026-11-01T01:00:00 fold-until(2026-11-01T02:00:00) type=8 -09 AKST
|
||||
0123: 2027-03-14T11:00:00Z unix=1805022000 wall=2027-03-14T02:00:00 gap-until(2027-03-14T03:00:00) type=7 -08 AKDT dst
|
||||
0124: 2027-11-07T10:00:00Z unix=1825581600 wall=2027-11-07T01:00:00 fold-until(2027-11-07T02:00:00) type=8 -09 AKST
|
||||
0125: 2028-03-12T11:00:00Z unix=1836471600 wall=2028-03-12T02:00:00 gap-until(2028-03-12T03:00:00) type=7 -08 AKDT dst
|
||||
0126: 2028-11-05T10:00:00Z unix=1857031200 wall=2028-11-05T01:00:00 fold-until(2028-11-05T02:00:00) type=8 -09 AKST
|
||||
0127: 2029-03-11T11:00:00Z unix=1867921200 wall=2029-03-11T02:00:00 gap-until(2029-03-11T03:00:00) type=7 -08 AKDT dst
|
||||
0128: 2029-11-04T10:00:00Z unix=1888480800 wall=2029-11-04T01:00:00 fold-until(2029-11-04T02:00:00) type=8 -09 AKST
|
||||
0129: 2030-03-10T11:00:00Z unix=1899370800 wall=2030-03-10T02:00:00 gap-until(2030-03-10T03:00:00) type=7 -08 AKDT dst
|
||||
0130: 2030-11-03T10:00:00Z unix=1919930400 wall=2030-11-03T01:00:00 fold-until(2030-11-03T02:00:00) type=8 -09 AKST
|
||||
0131: 2031-03-09T11:00:00Z unix=1930820400 wall=2031-03-09T02:00:00 gap-until(2031-03-09T03:00:00) type=7 -08 AKDT dst
|
||||
0132: 2031-11-02T10:00:00Z unix=1951380000 wall=2031-11-02T01:00:00 fold-until(2031-11-02T02:00:00) type=8 -09 AKST
|
||||
0133: 2032-03-14T11:00:00Z unix=1962874800 wall=2032-03-14T02:00:00 gap-until(2032-03-14T03:00:00) type=7 -08 AKDT dst
|
||||
0134: 2032-11-07T10:00:00Z unix=1983434400 wall=2032-11-07T01:00:00 fold-until(2032-11-07T02:00:00) type=8 -09 AKST
|
||||
0135: 2033-03-13T11:00:00Z unix=1994324400 wall=2033-03-13T02:00:00 gap-until(2033-03-13T03:00:00) type=7 -08 AKDT dst
|
||||
0136: 2033-11-06T10:00:00Z unix=2014884000 wall=2033-11-06T01:00:00 fold-until(2033-11-06T02:00:00) type=8 -09 AKST
|
||||
0137: 2034-03-12T11:00:00Z unix=2025774000 wall=2034-03-12T02:00:00 gap-until(2034-03-12T03:00:00) type=7 -08 AKDT dst
|
||||
0138: 2034-11-05T10:00:00Z unix=2046333600 wall=2034-11-05T01:00:00 fold-until(2034-11-05T02:00:00) type=8 -09 AKST
|
||||
0139: 2035-03-11T11:00:00Z unix=2057223600 wall=2035-03-11T02:00:00 gap-until(2035-03-11T03:00:00) type=7 -08 AKDT dst
|
||||
0140: 2035-11-04T10:00:00Z unix=2077783200 wall=2035-11-04T01:00:00 fold-until(2035-11-04T02:00:00) type=8 -09 AKST
|
||||
0141: 2036-03-09T11:00:00Z unix=2088673200 wall=2036-03-09T02:00:00 gap-until(2036-03-09T03:00:00) type=7 -08 AKDT dst
|
||||
0142: 2036-11-02T10:00:00Z unix=2109232800 wall=2036-11-02T01:00:00 fold-until(2036-11-02T02:00:00) type=8 -09 AKST
|
||||
0143: 2037-03-08T11:00:00Z unix=2120122800 wall=2037-03-08T02:00:00 gap-until(2037-03-08T03:00:00) type=7 -08 AKDT dst
|
||||
0144: 2037-11-01T10:00:00Z unix=2140682400 wall=2037-11-01T01:00:00 fold-until(2037-11-01T02:00:00) type=8 -09 AKST
|
||||
POSIX TIME ZONE STRING
|
||||
AKST9AKDT,M3.2.0,M11.1.0
|
||||
|
|
@ -0,0 +1,257 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse_v1())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
America/St_Johns
|
||||
LOCAL TIME TYPES
|
||||
000: offset=-03:30:52 designation=LMT indicator=local/wall
|
||||
001: offset=-02:30:52 designation=NDT dst indicator=local/wall
|
||||
002: offset=-03:30:52 designation=NST indicator=local/wall
|
||||
003: offset=-02:30 designation=NDT dst indicator=local/wall
|
||||
004: offset=-03:30 designation=NST indicator=local/wall
|
||||
005: offset=-02:30 designation=NPT dst indicator=ut/std
|
||||
006: offset=-02:30 designation=NWT dst indicator=local/wall
|
||||
007: offset=-01:30 designation=NDDT dst indicator=local/wall
|
||||
008: offset=-02:30 designation=NDT dst indicator=local/wall
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-01T22:29:07 unambiguous type=0 -03:30:52 LMT
|
||||
0001: 1901-12-13T20:45:52Z unix=-2147483648 wall=1901-12-13T17:15:00 unambiguous type=2 -03:30:52 NST
|
||||
0002: 1917-04-08T05:30:52Z unix=-1664130548 wall=1917-04-08T02:00:00 gap-until(1917-04-08T03:00:00) type=1 -02:30:52 NDT dst
|
||||
0003: 1917-09-17T04:30:52Z unix=-1650137348 wall=1917-09-17T01:00:00 fold-until(1917-09-17T02:00:00) type=2 -03:30:52 NST
|
||||
0004: 1918-04-14T05:30:52Z unix=-1632076148 wall=1918-04-14T02:00:00 gap-until(1918-04-14T03:00:00) type=1 -02:30:52 NDT dst
|
||||
0005: 1918-10-27T04:30:52Z unix=-1615145348 wall=1918-10-27T01:00:00 fold-until(1918-10-27T02:00:00) type=2 -03:30:52 NST
|
||||
0006: 1919-05-06T02:30:52Z unix=-1598650148 wall=1919-05-05T23:00:00 gap-until(1919-05-06T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0007: 1919-08-13T01:30:52Z unix=-1590100148 wall=1919-08-12T22:00:00 fold-until(1919-08-12T23:00:00) type=2 -03:30:52 NST
|
||||
0008: 1920-05-03T02:30:52Z unix=-1567286948 wall=1920-05-02T23:00:00 gap-until(1920-05-03T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0009: 1920-11-01T01:30:52Z unix=-1551565748 wall=1920-10-31T22:00:00 fold-until(1920-10-31T23:00:00) type=2 -03:30:52 NST
|
||||
0010: 1921-05-02T02:30:52Z unix=-1535837348 wall=1921-05-01T23:00:00 gap-until(1921-05-02T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0011: 1921-10-31T01:30:52Z unix=-1520116148 wall=1921-10-30T22:00:00 fold-until(1921-10-30T23:00:00) type=2 -03:30:52 NST
|
||||
0012: 1922-05-08T02:30:52Z unix=-1503782948 wall=1922-05-07T23:00:00 gap-until(1922-05-08T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0013: 1922-10-30T01:30:52Z unix=-1488666548 wall=1922-10-29T22:00:00 fold-until(1922-10-29T23:00:00) type=2 -03:30:52 NST
|
||||
0014: 1923-05-07T02:30:52Z unix=-1472333348 wall=1923-05-06T23:00:00 gap-until(1923-05-07T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0015: 1923-10-29T01:30:52Z unix=-1457216948 wall=1923-10-28T22:00:00 fold-until(1923-10-28T23:00:00) type=2 -03:30:52 NST
|
||||
0016: 1924-05-05T02:30:52Z unix=-1440883748 wall=1924-05-04T23:00:00 gap-until(1924-05-05T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0017: 1924-10-27T01:30:52Z unix=-1425767348 wall=1924-10-26T22:00:00 fold-until(1924-10-26T23:00:00) type=2 -03:30:52 NST
|
||||
0018: 1925-05-04T02:30:52Z unix=-1409434148 wall=1925-05-03T23:00:00 gap-until(1925-05-04T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0019: 1925-10-26T01:30:52Z unix=-1394317748 wall=1925-10-25T22:00:00 fold-until(1925-10-25T23:00:00) type=2 -03:30:52 NST
|
||||
0020: 1926-05-03T02:30:52Z unix=-1377984548 wall=1926-05-02T23:00:00 gap-until(1926-05-03T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0021: 1926-11-01T01:30:52Z unix=-1362263348 wall=1926-10-31T22:00:00 fold-until(1926-10-31T23:00:00) type=2 -03:30:52 NST
|
||||
0022: 1927-05-02T02:30:52Z unix=-1346534948 wall=1927-05-01T23:00:00 gap-until(1927-05-02T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0023: 1927-10-31T01:30:52Z unix=-1330813748 wall=1927-10-30T22:00:00 fold-until(1927-10-30T23:00:00) type=2 -03:30:52 NST
|
||||
0024: 1928-05-07T02:30:52Z unix=-1314480548 wall=1928-05-06T23:00:00 gap-until(1928-05-07T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0025: 1928-10-29T01:30:52Z unix=-1299364148 wall=1928-10-28T22:00:00 fold-until(1928-10-28T23:00:00) type=2 -03:30:52 NST
|
||||
0026: 1929-05-06T02:30:52Z unix=-1283030948 wall=1929-05-05T23:00:00 gap-until(1929-05-06T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0027: 1929-10-28T01:30:52Z unix=-1267914548 wall=1929-10-27T22:00:00 fold-until(1929-10-27T23:00:00) type=2 -03:30:52 NST
|
||||
0028: 1930-05-05T02:30:52Z unix=-1251581348 wall=1930-05-04T23:00:00 gap-until(1930-05-05T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0029: 1930-10-27T01:30:52Z unix=-1236464948 wall=1930-10-26T22:00:00 fold-until(1930-10-26T23:00:00) type=2 -03:30:52 NST
|
||||
0030: 1931-05-04T02:30:52Z unix=-1220131748 wall=1931-05-03T23:00:00 gap-until(1931-05-04T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0031: 1931-10-26T01:30:52Z unix=-1205015348 wall=1931-10-25T22:00:00 fold-until(1931-10-25T23:00:00) type=2 -03:30:52 NST
|
||||
0032: 1932-05-02T02:30:52Z unix=-1188682148 wall=1932-05-01T23:00:00 gap-until(1932-05-02T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0033: 1932-10-31T01:30:52Z unix=-1172960948 wall=1932-10-30T22:00:00 fold-until(1932-10-30T23:00:00) type=2 -03:30:52 NST
|
||||
0034: 1933-05-08T02:30:52Z unix=-1156627748 wall=1933-05-07T23:00:00 gap-until(1933-05-08T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0035: 1933-10-30T01:30:52Z unix=-1141511348 wall=1933-10-29T22:00:00 fold-until(1933-10-29T23:00:00) type=2 -03:30:52 NST
|
||||
0036: 1934-05-07T02:30:52Z unix=-1125178148 wall=1934-05-06T23:00:00 gap-until(1934-05-07T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0037: 1934-10-29T01:30:52Z unix=-1110061748 wall=1934-10-28T22:00:00 fold-until(1934-10-28T23:00:00) type=2 -03:30:52 NST
|
||||
0038: 1935-03-30T03:30:52Z unix=-1096921748 wall=1935-03-30T00:00:00 gap-until(1935-03-30T00:00:52) type=4 -03:30 NST
|
||||
0039: 1935-05-06T02:30:00Z unix=-1093728600 wall=1935-05-05T23:00:00 gap-until(1935-05-06T00:00:00) type=3 -02:30 NDT dst
|
||||
0040: 1935-10-28T01:30:00Z unix=-1078612200 wall=1935-10-27T22:00:00 fold-until(1935-10-27T23:00:00) type=4 -03:30 NST
|
||||
0041: 1936-05-11T03:30:00Z unix=-1061670600 wall=1936-05-11T00:00:00 gap-until(1936-05-11T01:00:00) type=3 -02:30 NDT dst
|
||||
0042: 1936-10-05T02:30:00Z unix=-1048973400 wall=1936-10-04T23:00:00 fold-until(1936-10-05T00:00:00) type=4 -03:30 NST
|
||||
0043: 1937-05-10T03:30:00Z unix=-1030221000 wall=1937-05-10T00:00:00 gap-until(1937-05-10T01:00:00) type=3 -02:30 NDT dst
|
||||
0044: 1937-10-04T02:30:00Z unix=-1017523800 wall=1937-10-03T23:00:00 fold-until(1937-10-04T00:00:00) type=4 -03:30 NST
|
||||
0045: 1938-05-09T03:30:00Z unix=-998771400 wall=1938-05-09T00:00:00 gap-until(1938-05-09T01:00:00) type=3 -02:30 NDT dst
|
||||
0046: 1938-10-03T02:30:00Z unix=-986074200 wall=1938-10-02T23:00:00 fold-until(1938-10-03T00:00:00) type=4 -03:30 NST
|
||||
0047: 1939-05-15T03:30:00Z unix=-966717000 wall=1939-05-15T00:00:00 gap-until(1939-05-15T01:00:00) type=3 -02:30 NDT dst
|
||||
0048: 1939-10-02T02:30:00Z unix=-954624600 wall=1939-10-01T23:00:00 fold-until(1939-10-02T00:00:00) type=4 -03:30 NST
|
||||
0049: 1940-05-13T03:30:00Z unix=-935267400 wall=1940-05-13T00:00:00 gap-until(1940-05-13T01:00:00) type=3 -02:30 NDT dst
|
||||
0050: 1940-10-07T02:30:00Z unix=-922570200 wall=1940-10-06T23:00:00 fold-until(1940-10-07T00:00:00) type=4 -03:30 NST
|
||||
0051: 1941-05-12T03:30:00Z unix=-903817800 wall=1941-05-12T00:00:00 gap-until(1941-05-12T01:00:00) type=3 -02:30 NDT dst
|
||||
0052: 1941-10-06T02:30:00Z unix=-891120600 wall=1941-10-05T23:00:00 fold-until(1941-10-06T00:00:00) type=4 -03:30 NST
|
||||
0053: 1942-05-11T03:30:00Z unix=-872368200 wall=1942-05-11T00:00:00 gap-until(1942-05-11T01:00:00) type=6 -02:30 NWT dst
|
||||
0054: 1945-08-14T23:00:00Z unix=-769395600 wall=1945-08-14T20:30:00 unambiguous type=5 -02:30 NPT dst
|
||||
0055: 1945-09-30T04:30:00Z unix=-765401400 wall=1945-09-30T01:00:00 fold-until(1945-09-30T02:00:00) type=4 -03:30 NST
|
||||
0056: 1946-05-12T05:30:00Z unix=-746044200 wall=1946-05-12T02:00:00 gap-until(1946-05-12T03:00:00) type=3 -02:30 NDT dst
|
||||
0057: 1946-10-06T04:30:00Z unix=-733347000 wall=1946-10-06T01:00:00 fold-until(1946-10-06T02:00:00) type=4 -03:30 NST
|
||||
0058: 1947-05-11T05:30:00Z unix=-714594600 wall=1947-05-11T02:00:00 gap-until(1947-05-11T03:00:00) type=3 -02:30 NDT dst
|
||||
0059: 1947-10-05T04:30:00Z unix=-701897400 wall=1947-10-05T01:00:00 fold-until(1947-10-05T02:00:00) type=4 -03:30 NST
|
||||
0060: 1948-05-09T05:30:00Z unix=-683145000 wall=1948-05-09T02:00:00 gap-until(1948-05-09T03:00:00) type=3 -02:30 NDT dst
|
||||
0061: 1948-10-03T04:30:00Z unix=-670447800 wall=1948-10-03T01:00:00 fold-until(1948-10-03T02:00:00) type=4 -03:30 NST
|
||||
0062: 1949-05-08T05:30:00Z unix=-651695400 wall=1949-05-08T02:00:00 gap-until(1949-05-08T03:00:00) type=3 -02:30 NDT dst
|
||||
0063: 1949-10-02T04:30:00Z unix=-638998200 wall=1949-10-02T01:00:00 fold-until(1949-10-02T02:00:00) type=4 -03:30 NST
|
||||
0064: 1950-05-14T05:30:00Z unix=-619641000 wall=1950-05-14T02:00:00 gap-until(1950-05-14T03:00:00) type=3 -02:30 NDT dst
|
||||
0065: 1950-10-08T04:30:00Z unix=-606943800 wall=1950-10-08T01:00:00 fold-until(1950-10-08T02:00:00) type=4 -03:30 NST
|
||||
0066: 1951-04-29T05:30:00Z unix=-589401000 wall=1951-04-29T02:00:00 gap-until(1951-04-29T03:00:00) type=3 -02:30 NDT dst
|
||||
0067: 1951-09-30T04:30:00Z unix=-576099000 wall=1951-09-30T01:00:00 fold-until(1951-09-30T02:00:00) type=4 -03:30 NST
|
||||
0068: 1952-04-27T05:30:00Z unix=-557951400 wall=1952-04-27T02:00:00 gap-until(1952-04-27T03:00:00) type=3 -02:30 NDT dst
|
||||
0069: 1952-09-28T04:30:00Z unix=-544649400 wall=1952-09-28T01:00:00 fold-until(1952-09-28T02:00:00) type=4 -03:30 NST
|
||||
0070: 1953-04-26T05:30:00Z unix=-526501800 wall=1953-04-26T02:00:00 gap-until(1953-04-26T03:00:00) type=3 -02:30 NDT dst
|
||||
0071: 1953-09-27T04:30:00Z unix=-513199800 wall=1953-09-27T01:00:00 fold-until(1953-09-27T02:00:00) type=4 -03:30 NST
|
||||
0072: 1954-04-25T05:30:00Z unix=-495052200 wall=1954-04-25T02:00:00 gap-until(1954-04-25T03:00:00) type=3 -02:30 NDT dst
|
||||
0073: 1954-09-26T04:30:00Z unix=-481750200 wall=1954-09-26T01:00:00 fold-until(1954-09-26T02:00:00) type=4 -03:30 NST
|
||||
0074: 1955-04-24T05:30:00Z unix=-463602600 wall=1955-04-24T02:00:00 gap-until(1955-04-24T03:00:00) type=3 -02:30 NDT dst
|
||||
0075: 1955-09-25T04:30:00Z unix=-450300600 wall=1955-09-25T01:00:00 fold-until(1955-09-25T02:00:00) type=4 -03:30 NST
|
||||
0076: 1956-04-29T05:30:00Z unix=-431548200 wall=1956-04-29T02:00:00 gap-until(1956-04-29T03:00:00) type=3 -02:30 NDT dst
|
||||
0077: 1956-09-30T04:30:00Z unix=-418246200 wall=1956-09-30T01:00:00 fold-until(1956-09-30T02:00:00) type=4 -03:30 NST
|
||||
0078: 1957-04-28T05:30:00Z unix=-400098600 wall=1957-04-28T02:00:00 gap-until(1957-04-28T03:00:00) type=3 -02:30 NDT dst
|
||||
0079: 1957-09-29T04:30:00Z unix=-386796600 wall=1957-09-29T01:00:00 fold-until(1957-09-29T02:00:00) type=4 -03:30 NST
|
||||
0080: 1958-04-27T05:30:00Z unix=-368649000 wall=1958-04-27T02:00:00 gap-until(1958-04-27T03:00:00) type=3 -02:30 NDT dst
|
||||
0081: 1958-09-28T04:30:00Z unix=-355347000 wall=1958-09-28T01:00:00 fold-until(1958-09-28T02:00:00) type=4 -03:30 NST
|
||||
0082: 1959-04-26T05:30:00Z unix=-337199400 wall=1959-04-26T02:00:00 gap-until(1959-04-26T03:00:00) type=3 -02:30 NDT dst
|
||||
0083: 1959-09-27T04:30:00Z unix=-323897400 wall=1959-09-27T01:00:00 fold-until(1959-09-27T02:00:00) type=4 -03:30 NST
|
||||
0084: 1960-04-24T05:30:00Z unix=-305749800 wall=1960-04-24T02:00:00 gap-until(1960-04-24T03:00:00) type=3 -02:30 NDT dst
|
||||
0085: 1960-10-30T04:30:00Z unix=-289423800 wall=1960-10-30T01:00:00 fold-until(1960-10-30T02:00:00) type=4 -03:30 NST
|
||||
0086: 1961-04-30T05:30:00Z unix=-273695400 wall=1961-04-30T02:00:00 gap-until(1961-04-30T03:00:00) type=3 -02:30 NDT dst
|
||||
0087: 1961-10-29T04:30:00Z unix=-257974200 wall=1961-10-29T01:00:00 fold-until(1961-10-29T02:00:00) type=4 -03:30 NST
|
||||
0088: 1962-04-29T05:30:00Z unix=-242245800 wall=1962-04-29T02:00:00 gap-until(1962-04-29T03:00:00) type=3 -02:30 NDT dst
|
||||
0089: 1962-10-28T04:30:00Z unix=-226524600 wall=1962-10-28T01:00:00 fold-until(1962-10-28T02:00:00) type=4 -03:30 NST
|
||||
0090: 1963-04-28T05:30:00Z unix=-210796200 wall=1963-04-28T02:00:00 gap-until(1963-04-28T03:00:00) type=3 -02:30 NDT dst
|
||||
0091: 1963-10-27T04:30:00Z unix=-195075000 wall=1963-10-27T01:00:00 fold-until(1963-10-27T02:00:00) type=4 -03:30 NST
|
||||
0092: 1964-04-26T05:30:00Z unix=-179346600 wall=1964-04-26T02:00:00 gap-until(1964-04-26T03:00:00) type=3 -02:30 NDT dst
|
||||
0093: 1964-10-25T04:30:00Z unix=-163625400 wall=1964-10-25T01:00:00 fold-until(1964-10-25T02:00:00) type=4 -03:30 NST
|
||||
0094: 1965-04-25T05:30:00Z unix=-147897000 wall=1965-04-25T02:00:00 gap-until(1965-04-25T03:00:00) type=3 -02:30 NDT dst
|
||||
0095: 1965-10-31T04:30:00Z unix=-131571000 wall=1965-10-31T01:00:00 fold-until(1965-10-31T02:00:00) type=4 -03:30 NST
|
||||
0096: 1966-04-24T05:30:00Z unix=-116447400 wall=1966-04-24T02:00:00 gap-until(1966-04-24T03:00:00) type=3 -02:30 NDT dst
|
||||
0097: 1966-10-30T04:30:00Z unix=-100121400 wall=1966-10-30T01:00:00 fold-until(1966-10-30T02:00:00) type=4 -03:30 NST
|
||||
0098: 1967-04-30T05:30:00Z unix=-84393000 wall=1967-04-30T02:00:00 gap-until(1967-04-30T03:00:00) type=3 -02:30 NDT dst
|
||||
0099: 1967-10-29T04:30:00Z unix=-68671800 wall=1967-10-29T01:00:00 fold-until(1967-10-29T02:00:00) type=4 -03:30 NST
|
||||
0100: 1968-04-28T05:30:00Z unix=-52943400 wall=1968-04-28T02:00:00 gap-until(1968-04-28T03:00:00) type=3 -02:30 NDT dst
|
||||
0101: 1968-10-27T04:30:00Z unix=-37222200 wall=1968-10-27T01:00:00 fold-until(1968-10-27T02:00:00) type=4 -03:30 NST
|
||||
0102: 1969-04-27T05:30:00Z unix=-21493800 wall=1969-04-27T02:00:00 gap-until(1969-04-27T03:00:00) type=3 -02:30 NDT dst
|
||||
0103: 1969-10-26T04:30:00Z unix=-5772600 wall=1969-10-26T01:00:00 fold-until(1969-10-26T02:00:00) type=4 -03:30 NST
|
||||
0104: 1970-04-26T05:30:00Z unix=9955800 wall=1970-04-26T02:00:00 gap-until(1970-04-26T03:00:00) type=3 -02:30 NDT dst
|
||||
0105: 1970-10-25T04:30:00Z unix=25677000 wall=1970-10-25T01:00:00 fold-until(1970-10-25T02:00:00) type=4 -03:30 NST
|
||||
0106: 1971-04-25T05:30:00Z unix=41405400 wall=1971-04-25T02:00:00 gap-until(1971-04-25T03:00:00) type=3 -02:30 NDT dst
|
||||
0107: 1971-10-31T04:30:00Z unix=57731400 wall=1971-10-31T01:00:00 fold-until(1971-10-31T02:00:00) type=4 -03:30 NST
|
||||
0108: 1972-04-30T05:30:00Z unix=73459800 wall=1972-04-30T02:00:00 gap-until(1972-04-30T03:00:00) type=3 -02:30 NDT dst
|
||||
0109: 1972-10-29T04:30:00Z unix=89181000 wall=1972-10-29T01:00:00 fold-until(1972-10-29T02:00:00) type=4 -03:30 NST
|
||||
0110: 1973-04-29T05:30:00Z unix=104909400 wall=1973-04-29T02:00:00 gap-until(1973-04-29T03:00:00) type=3 -02:30 NDT dst
|
||||
0111: 1973-10-28T04:30:00Z unix=120630600 wall=1973-10-28T01:00:00 fold-until(1973-10-28T02:00:00) type=4 -03:30 NST
|
||||
0112: 1974-04-28T05:30:00Z unix=136359000 wall=1974-04-28T02:00:00 gap-until(1974-04-28T03:00:00) type=3 -02:30 NDT dst
|
||||
0113: 1974-10-27T04:30:00Z unix=152080200 wall=1974-10-27T01:00:00 fold-until(1974-10-27T02:00:00) type=4 -03:30 NST
|
||||
0114: 1975-04-27T05:30:00Z unix=167808600 wall=1975-04-27T02:00:00 gap-until(1975-04-27T03:00:00) type=3 -02:30 NDT dst
|
||||
0115: 1975-10-26T04:30:00Z unix=183529800 wall=1975-10-26T01:00:00 fold-until(1975-10-26T02:00:00) type=4 -03:30 NST
|
||||
0116: 1976-04-25T05:30:00Z unix=199258200 wall=1976-04-25T02:00:00 gap-until(1976-04-25T03:00:00) type=3 -02:30 NDT dst
|
||||
0117: 1976-10-31T04:30:00Z unix=215584200 wall=1976-10-31T01:00:00 fold-until(1976-10-31T02:00:00) type=4 -03:30 NST
|
||||
0118: 1977-04-24T05:30:00Z unix=230707800 wall=1977-04-24T02:00:00 gap-until(1977-04-24T03:00:00) type=3 -02:30 NDT dst
|
||||
0119: 1977-10-30T04:30:00Z unix=247033800 wall=1977-10-30T01:00:00 fold-until(1977-10-30T02:00:00) type=4 -03:30 NST
|
||||
0120: 1978-04-30T05:30:00Z unix=262762200 wall=1978-04-30T02:00:00 gap-until(1978-04-30T03:00:00) type=3 -02:30 NDT dst
|
||||
0121: 1978-10-29T04:30:00Z unix=278483400 wall=1978-10-29T01:00:00 fold-until(1978-10-29T02:00:00) type=4 -03:30 NST
|
||||
0122: 1979-04-29T05:30:00Z unix=294211800 wall=1979-04-29T02:00:00 gap-until(1979-04-29T03:00:00) type=3 -02:30 NDT dst
|
||||
0123: 1979-10-28T04:30:00Z unix=309933000 wall=1979-10-28T01:00:00 fold-until(1979-10-28T02:00:00) type=4 -03:30 NST
|
||||
0124: 1980-04-27T05:30:00Z unix=325661400 wall=1980-04-27T02:00:00 gap-until(1980-04-27T03:00:00) type=3 -02:30 NDT dst
|
||||
0125: 1980-10-26T04:30:00Z unix=341382600 wall=1980-10-26T01:00:00 fold-until(1980-10-26T02:00:00) type=4 -03:30 NST
|
||||
0126: 1981-04-26T05:30:00Z unix=357111000 wall=1981-04-26T02:00:00 gap-until(1981-04-26T03:00:00) type=3 -02:30 NDT dst
|
||||
0127: 1981-10-25T04:30:00Z unix=372832200 wall=1981-10-25T01:00:00 fold-until(1981-10-25T02:00:00) type=4 -03:30 NST
|
||||
0128: 1982-04-25T05:30:00Z unix=388560600 wall=1982-04-25T02:00:00 gap-until(1982-04-25T03:00:00) type=3 -02:30 NDT dst
|
||||
0129: 1982-10-31T04:30:00Z unix=404886600 wall=1982-10-31T01:00:00 fold-until(1982-10-31T02:00:00) type=4 -03:30 NST
|
||||
0130: 1983-04-24T05:30:00Z unix=420010200 wall=1983-04-24T02:00:00 gap-until(1983-04-24T03:00:00) type=3 -02:30 NDT dst
|
||||
0131: 1983-10-30T04:30:00Z unix=436336200 wall=1983-10-30T01:00:00 fold-until(1983-10-30T02:00:00) type=4 -03:30 NST
|
||||
0132: 1984-04-29T05:30:00Z unix=452064600 wall=1984-04-29T02:00:00 gap-until(1984-04-29T03:00:00) type=3 -02:30 NDT dst
|
||||
0133: 1984-10-28T04:30:00Z unix=467785800 wall=1984-10-28T01:00:00 fold-until(1984-10-28T02:00:00) type=4 -03:30 NST
|
||||
0134: 1985-04-28T05:30:00Z unix=483514200 wall=1985-04-28T02:00:00 gap-until(1985-04-28T03:00:00) type=3 -02:30 NDT dst
|
||||
0135: 1985-10-27T04:30:00Z unix=499235400 wall=1985-10-27T01:00:00 fold-until(1985-10-27T02:00:00) type=4 -03:30 NST
|
||||
0136: 1986-04-27T05:30:00Z unix=514963800 wall=1986-04-27T02:00:00 gap-until(1986-04-27T03:00:00) type=3 -02:30 NDT dst
|
||||
0137: 1986-10-26T04:30:00Z unix=530685000 wall=1986-10-26T01:00:00 fold-until(1986-10-26T02:00:00) type=4 -03:30 NST
|
||||
0138: 1987-04-05T03:31:00Z unix=544591860 wall=1987-04-05T00:01:00 gap-until(1987-04-05T01:01:00) type=3 -02:30 NDT dst
|
||||
0139: 1987-10-25T02:31:00Z unix=562127460 wall=1987-10-24T23:01:00 fold-until(1987-10-25T00:01:00) type=4 -03:30 NST
|
||||
0140: 1988-04-03T03:31:00Z unix=576041460 wall=1988-04-03T00:01:00 gap-until(1988-04-03T02:01:00) type=7 -01:30 NDDT dst
|
||||
0141: 1988-10-30T01:31:00Z unix=594178260 wall=1988-10-29T22:01:00 fold-until(1988-10-30T00:01:00) type=4 -03:30 NST
|
||||
0142: 1989-04-02T03:31:00Z unix=607491060 wall=1989-04-02T00:01:00 gap-until(1989-04-02T01:01:00) type=3 -02:30 NDT dst
|
||||
0143: 1989-10-29T02:31:00Z unix=625631460 wall=1989-10-28T23:01:00 fold-until(1989-10-29T00:01:00) type=4 -03:30 NST
|
||||
0144: 1990-04-01T03:31:00Z unix=638940660 wall=1990-04-01T00:01:00 gap-until(1990-04-01T01:01:00) type=3 -02:30 NDT dst
|
||||
0145: 1990-10-28T02:31:00Z unix=657081060 wall=1990-10-27T23:01:00 fold-until(1990-10-28T00:01:00) type=4 -03:30 NST
|
||||
0146: 1991-04-07T03:31:00Z unix=670995060 wall=1991-04-07T00:01:00 gap-until(1991-04-07T01:01:00) type=3 -02:30 NDT dst
|
||||
0147: 1991-10-27T02:31:00Z unix=688530660 wall=1991-10-26T23:01:00 fold-until(1991-10-27T00:01:00) type=4 -03:30 NST
|
||||
0148: 1992-04-05T03:31:00Z unix=702444660 wall=1992-04-05T00:01:00 gap-until(1992-04-05T01:01:00) type=3 -02:30 NDT dst
|
||||
0149: 1992-10-25T02:31:00Z unix=719980260 wall=1992-10-24T23:01:00 fold-until(1992-10-25T00:01:00) type=4 -03:30 NST
|
||||
0150: 1993-04-04T03:31:00Z unix=733894260 wall=1993-04-04T00:01:00 gap-until(1993-04-04T01:01:00) type=3 -02:30 NDT dst
|
||||
0151: 1993-10-31T02:31:00Z unix=752034660 wall=1993-10-30T23:01:00 fold-until(1993-10-31T00:01:00) type=4 -03:30 NST
|
||||
0152: 1994-04-03T03:31:00Z unix=765343860 wall=1994-04-03T00:01:00 gap-until(1994-04-03T01:01:00) type=3 -02:30 NDT dst
|
||||
0153: 1994-10-30T02:31:00Z unix=783484260 wall=1994-10-29T23:01:00 fold-until(1994-10-30T00:01:00) type=4 -03:30 NST
|
||||
0154: 1995-04-02T03:31:00Z unix=796793460 wall=1995-04-02T00:01:00 gap-until(1995-04-02T01:01:00) type=3 -02:30 NDT dst
|
||||
0155: 1995-10-29T02:31:00Z unix=814933860 wall=1995-10-28T23:01:00 fold-until(1995-10-29T00:01:00) type=4 -03:30 NST
|
||||
0156: 1996-04-07T03:31:00Z unix=828847860 wall=1996-04-07T00:01:00 gap-until(1996-04-07T01:01:00) type=3 -02:30 NDT dst
|
||||
0157: 1996-10-27T02:31:00Z unix=846383460 wall=1996-10-26T23:01:00 fold-until(1996-10-27T00:01:00) type=4 -03:30 NST
|
||||
0158: 1997-04-06T03:31:00Z unix=860297460 wall=1997-04-06T00:01:00 gap-until(1997-04-06T01:01:00) type=3 -02:30 NDT dst
|
||||
0159: 1997-10-26T02:31:00Z unix=877833060 wall=1997-10-25T23:01:00 fold-until(1997-10-26T00:01:00) type=4 -03:30 NST
|
||||
0160: 1998-04-05T03:31:00Z unix=891747060 wall=1998-04-05T00:01:00 gap-until(1998-04-05T01:01:00) type=3 -02:30 NDT dst
|
||||
0161: 1998-10-25T02:31:00Z unix=909282660 wall=1998-10-24T23:01:00 fold-until(1998-10-25T00:01:00) type=4 -03:30 NST
|
||||
0162: 1999-04-04T03:31:00Z unix=923196660 wall=1999-04-04T00:01:00 gap-until(1999-04-04T01:01:00) type=3 -02:30 NDT dst
|
||||
0163: 1999-10-31T02:31:00Z unix=941337060 wall=1999-10-30T23:01:00 fold-until(1999-10-31T00:01:00) type=4 -03:30 NST
|
||||
0164: 2000-04-02T03:31:00Z unix=954646260 wall=2000-04-02T00:01:00 gap-until(2000-04-02T01:01:00) type=3 -02:30 NDT dst
|
||||
0165: 2000-10-29T02:31:00Z unix=972786660 wall=2000-10-28T23:01:00 fold-until(2000-10-29T00:01:00) type=4 -03:30 NST
|
||||
0166: 2001-04-01T03:31:00Z unix=986095860 wall=2001-04-01T00:01:00 gap-until(2001-04-01T01:01:00) type=3 -02:30 NDT dst
|
||||
0167: 2001-10-28T02:31:00Z unix=1004236260 wall=2001-10-27T23:01:00 fold-until(2001-10-28T00:01:00) type=4 -03:30 NST
|
||||
0168: 2002-04-07T03:31:00Z unix=1018150260 wall=2002-04-07T00:01:00 gap-until(2002-04-07T01:01:00) type=3 -02:30 NDT dst
|
||||
0169: 2002-10-27T02:31:00Z unix=1035685860 wall=2002-10-26T23:01:00 fold-until(2002-10-27T00:01:00) type=4 -03:30 NST
|
||||
0170: 2003-04-06T03:31:00Z unix=1049599860 wall=2003-04-06T00:01:00 gap-until(2003-04-06T01:01:00) type=3 -02:30 NDT dst
|
||||
0171: 2003-10-26T02:31:00Z unix=1067135460 wall=2003-10-25T23:01:00 fold-until(2003-10-26T00:01:00) type=4 -03:30 NST
|
||||
0172: 2004-04-04T03:31:00Z unix=1081049460 wall=2004-04-04T00:01:00 gap-until(2004-04-04T01:01:00) type=3 -02:30 NDT dst
|
||||
0173: 2004-10-31T02:31:00Z unix=1099189860 wall=2004-10-30T23:01:00 fold-until(2004-10-31T00:01:00) type=4 -03:30 NST
|
||||
0174: 2005-04-03T03:31:00Z unix=1112499060 wall=2005-04-03T00:01:00 gap-until(2005-04-03T01:01:00) type=3 -02:30 NDT dst
|
||||
0175: 2005-10-30T02:31:00Z unix=1130639460 wall=2005-10-29T23:01:00 fold-until(2005-10-30T00:01:00) type=4 -03:30 NST
|
||||
0176: 2006-04-02T03:31:00Z unix=1143948660 wall=2006-04-02T00:01:00 gap-until(2006-04-02T01:01:00) type=3 -02:30 NDT dst
|
||||
0177: 2006-10-29T02:31:00Z unix=1162089060 wall=2006-10-28T23:01:00 fold-until(2006-10-29T00:01:00) type=4 -03:30 NST
|
||||
0178: 2007-03-11T03:31:00Z unix=1173583860 wall=2007-03-11T00:01:00 gap-until(2007-03-11T01:01:00) type=3 -02:30 NDT dst
|
||||
0179: 2007-11-04T02:31:00Z unix=1194143460 wall=2007-11-03T23:01:00 fold-until(2007-11-04T00:01:00) type=4 -03:30 NST
|
||||
0180: 2008-03-09T03:31:00Z unix=1205033460 wall=2008-03-09T00:01:00 gap-until(2008-03-09T01:01:00) type=3 -02:30 NDT dst
|
||||
0181: 2008-11-02T02:31:00Z unix=1225593060 wall=2008-11-01T23:01:00 fold-until(2008-11-02T00:01:00) type=4 -03:30 NST
|
||||
0182: 2009-03-08T03:31:00Z unix=1236483060 wall=2009-03-08T00:01:00 gap-until(2009-03-08T01:01:00) type=3 -02:30 NDT dst
|
||||
0183: 2009-11-01T02:31:00Z unix=1257042660 wall=2009-10-31T23:01:00 fold-until(2009-11-01T00:01:00) type=4 -03:30 NST
|
||||
0184: 2010-03-14T03:31:00Z unix=1268537460 wall=2010-03-14T00:01:00 gap-until(2010-03-14T01:01:00) type=3 -02:30 NDT dst
|
||||
0185: 2010-11-07T02:31:00Z unix=1289097060 wall=2010-11-06T23:01:00 fold-until(2010-11-07T00:01:00) type=4 -03:30 NST
|
||||
0186: 2011-03-13T03:31:00Z unix=1299987060 wall=2011-03-13T00:01:00 gap-until(2011-03-13T01:01:00) type=3 -02:30 NDT dst
|
||||
0187: 2011-11-06T04:30:00Z unix=1320553800 wall=2011-11-06T01:00:00 fold-until(2011-11-06T02:00:00) type=4 -03:30 NST
|
||||
0188: 2012-03-11T05:30:00Z unix=1331443800 wall=2012-03-11T02:00:00 gap-until(2012-03-11T03:00:00) type=3 -02:30 NDT dst
|
||||
0189: 2012-11-04T04:30:00Z unix=1352003400 wall=2012-11-04T01:00:00 fold-until(2012-11-04T02:00:00) type=4 -03:30 NST
|
||||
0190: 2013-03-10T05:30:00Z unix=1362893400 wall=2013-03-10T02:00:00 gap-until(2013-03-10T03:00:00) type=3 -02:30 NDT dst
|
||||
0191: 2013-11-03T04:30:00Z unix=1383453000 wall=2013-11-03T01:00:00 fold-until(2013-11-03T02:00:00) type=4 -03:30 NST
|
||||
0192: 2014-03-09T05:30:00Z unix=1394343000 wall=2014-03-09T02:00:00 gap-until(2014-03-09T03:00:00) type=3 -02:30 NDT dst
|
||||
0193: 2014-11-02T04:30:00Z unix=1414902600 wall=2014-11-02T01:00:00 fold-until(2014-11-02T02:00:00) type=4 -03:30 NST
|
||||
0194: 2015-03-08T05:30:00Z unix=1425792600 wall=2015-03-08T02:00:00 gap-until(2015-03-08T03:00:00) type=3 -02:30 NDT dst
|
||||
0195: 2015-11-01T04:30:00Z unix=1446352200 wall=2015-11-01T01:00:00 fold-until(2015-11-01T02:00:00) type=4 -03:30 NST
|
||||
0196: 2016-03-13T05:30:00Z unix=1457847000 wall=2016-03-13T02:00:00 gap-until(2016-03-13T03:00:00) type=3 -02:30 NDT dst
|
||||
0197: 2016-11-06T04:30:00Z unix=1478406600 wall=2016-11-06T01:00:00 fold-until(2016-11-06T02:00:00) type=4 -03:30 NST
|
||||
0198: 2017-03-12T05:30:00Z unix=1489296600 wall=2017-03-12T02:00:00 gap-until(2017-03-12T03:00:00) type=3 -02:30 NDT dst
|
||||
0199: 2017-11-05T04:30:00Z unix=1509856200 wall=2017-11-05T01:00:00 fold-until(2017-11-05T02:00:00) type=4 -03:30 NST
|
||||
0200: 2018-03-11T05:30:00Z unix=1520746200 wall=2018-03-11T02:00:00 gap-until(2018-03-11T03:00:00) type=3 -02:30 NDT dst
|
||||
0201: 2018-11-04T04:30:00Z unix=1541305800 wall=2018-11-04T01:00:00 fold-until(2018-11-04T02:00:00) type=4 -03:30 NST
|
||||
0202: 2019-03-10T05:30:00Z unix=1552195800 wall=2019-03-10T02:00:00 gap-until(2019-03-10T03:00:00) type=3 -02:30 NDT dst
|
||||
0203: 2019-11-03T04:30:00Z unix=1572755400 wall=2019-11-03T01:00:00 fold-until(2019-11-03T02:00:00) type=4 -03:30 NST
|
||||
0204: 2020-03-08T05:30:00Z unix=1583645400 wall=2020-03-08T02:00:00 gap-until(2020-03-08T03:00:00) type=3 -02:30 NDT dst
|
||||
0205: 2020-11-01T04:30:00Z unix=1604205000 wall=2020-11-01T01:00:00 fold-until(2020-11-01T02:00:00) type=4 -03:30 NST
|
||||
0206: 2021-03-14T05:30:00Z unix=1615699800 wall=2021-03-14T02:00:00 gap-until(2021-03-14T03:00:00) type=3 -02:30 NDT dst
|
||||
0207: 2021-11-07T04:30:00Z unix=1636259400 wall=2021-11-07T01:00:00 fold-until(2021-11-07T02:00:00) type=4 -03:30 NST
|
||||
0208: 2022-03-13T05:30:00Z unix=1647149400 wall=2022-03-13T02:00:00 gap-until(2022-03-13T03:00:00) type=3 -02:30 NDT dst
|
||||
0209: 2022-11-06T04:30:00Z unix=1667709000 wall=2022-11-06T01:00:00 fold-until(2022-11-06T02:00:00) type=4 -03:30 NST
|
||||
0210: 2023-03-12T05:30:00Z unix=1678599000 wall=2023-03-12T02:00:00 gap-until(2023-03-12T03:00:00) type=3 -02:30 NDT dst
|
||||
0211: 2023-11-05T04:30:00Z unix=1699158600 wall=2023-11-05T01:00:00 fold-until(2023-11-05T02:00:00) type=4 -03:30 NST
|
||||
0212: 2024-03-10T05:30:00Z unix=1710048600 wall=2024-03-10T02:00:00 gap-until(2024-03-10T03:00:00) type=3 -02:30 NDT dst
|
||||
0213: 2024-11-03T04:30:00Z unix=1730608200 wall=2024-11-03T01:00:00 fold-until(2024-11-03T02:00:00) type=4 -03:30 NST
|
||||
0214: 2025-03-09T05:30:00Z unix=1741498200 wall=2025-03-09T02:00:00 gap-until(2025-03-09T03:00:00) type=3 -02:30 NDT dst
|
||||
0215: 2025-11-02T04:30:00Z unix=1762057800 wall=2025-11-02T01:00:00 fold-until(2025-11-02T02:00:00) type=4 -03:30 NST
|
||||
0216: 2026-03-08T05:30:00Z unix=1772947800 wall=2026-03-08T02:00:00 gap-until(2026-03-08T03:00:00) type=3 -02:30 NDT dst
|
||||
0217: 2026-11-01T04:30:00Z unix=1793507400 wall=2026-11-01T01:00:00 fold-until(2026-11-01T02:00:00) type=4 -03:30 NST
|
||||
0218: 2027-03-14T05:30:00Z unix=1805002200 wall=2027-03-14T02:00:00 gap-until(2027-03-14T03:00:00) type=3 -02:30 NDT dst
|
||||
0219: 2027-11-07T04:30:00Z unix=1825561800 wall=2027-11-07T01:00:00 fold-until(2027-11-07T02:00:00) type=4 -03:30 NST
|
||||
0220: 2028-03-12T05:30:00Z unix=1836451800 wall=2028-03-12T02:00:00 gap-until(2028-03-12T03:00:00) type=3 -02:30 NDT dst
|
||||
0221: 2028-11-05T04:30:00Z unix=1857011400 wall=2028-11-05T01:00:00 fold-until(2028-11-05T02:00:00) type=4 -03:30 NST
|
||||
0222: 2029-03-11T05:30:00Z unix=1867901400 wall=2029-03-11T02:00:00 gap-until(2029-03-11T03:00:00) type=3 -02:30 NDT dst
|
||||
0223: 2029-11-04T04:30:00Z unix=1888461000 wall=2029-11-04T01:00:00 fold-until(2029-11-04T02:00:00) type=4 -03:30 NST
|
||||
0224: 2030-03-10T05:30:00Z unix=1899351000 wall=2030-03-10T02:00:00 gap-until(2030-03-10T03:00:00) type=3 -02:30 NDT dst
|
||||
0225: 2030-11-03T04:30:00Z unix=1919910600 wall=2030-11-03T01:00:00 fold-until(2030-11-03T02:00:00) type=4 -03:30 NST
|
||||
0226: 2031-03-09T05:30:00Z unix=1930800600 wall=2031-03-09T02:00:00 gap-until(2031-03-09T03:00:00) type=3 -02:30 NDT dst
|
||||
0227: 2031-11-02T04:30:00Z unix=1951360200 wall=2031-11-02T01:00:00 fold-until(2031-11-02T02:00:00) type=4 -03:30 NST
|
||||
0228: 2032-03-14T05:30:00Z unix=1962855000 wall=2032-03-14T02:00:00 gap-until(2032-03-14T03:00:00) type=3 -02:30 NDT dst
|
||||
0229: 2032-11-07T04:30:00Z unix=1983414600 wall=2032-11-07T01:00:00 fold-until(2032-11-07T02:00:00) type=4 -03:30 NST
|
||||
0230: 2033-03-13T05:30:00Z unix=1994304600 wall=2033-03-13T02:00:00 gap-until(2033-03-13T03:00:00) type=3 -02:30 NDT dst
|
||||
0231: 2033-11-06T04:30:00Z unix=2014864200 wall=2033-11-06T01:00:00 fold-until(2033-11-06T02:00:00) type=4 -03:30 NST
|
||||
0232: 2034-03-12T05:30:00Z unix=2025754200 wall=2034-03-12T02:00:00 gap-until(2034-03-12T03:00:00) type=3 -02:30 NDT dst
|
||||
0233: 2034-11-05T04:30:00Z unix=2046313800 wall=2034-11-05T01:00:00 fold-until(2034-11-05T02:00:00) type=4 -03:30 NST
|
||||
0234: 2035-03-11T05:30:00Z unix=2057203800 wall=2035-03-11T02:00:00 gap-until(2035-03-11T03:00:00) type=3 -02:30 NDT dst
|
||||
0235: 2035-11-04T04:30:00Z unix=2077763400 wall=2035-11-04T01:00:00 fold-until(2035-11-04T02:00:00) type=4 -03:30 NST
|
||||
0236: 2036-03-09T05:30:00Z unix=2088653400 wall=2036-03-09T02:00:00 gap-until(2036-03-09T03:00:00) type=3 -02:30 NDT dst
|
||||
0237: 2036-11-02T04:30:00Z unix=2109213000 wall=2036-11-02T01:00:00 fold-until(2036-11-02T02:00:00) type=4 -03:30 NST
|
||||
0238: 2037-03-08T05:30:00Z unix=2120103000 wall=2037-03-08T02:00:00 gap-until(2037-03-08T03:00:00) type=3 -02:30 NDT dst
|
||||
0239: 2037-11-01T04:30:00Z unix=2140662600 wall=2037-11-01T01:00:00 fold-until(2037-11-01T02:00:00) type=4 -03:30 NST
|
||||
|
|
@ -0,0 +1,259 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
America/St_Johns
|
||||
LOCAL TIME TYPES
|
||||
000: offset=-03:30:52 designation=LMT indicator=local/wall
|
||||
001: offset=-02:30:52 designation=NDT dst indicator=local/wall
|
||||
002: offset=-03:30:52 designation=NST indicator=local/wall
|
||||
003: offset=-02:30 designation=NDT dst indicator=local/wall
|
||||
004: offset=-03:30 designation=NST indicator=local/wall
|
||||
005: offset=-02:30 designation=NPT dst indicator=ut/std
|
||||
006: offset=-02:30 designation=NWT dst indicator=local/wall
|
||||
007: offset=-01:30 designation=NDDT dst indicator=local/wall
|
||||
008: offset=-02:30 designation=NDT dst indicator=local/wall
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-01T22:29:07 unambiguous type=0 -03:30:52 LMT
|
||||
0001: 1884-01-01T03:30:52Z unix=-2713897748 wall=1884-01-01T00:00:00 unambiguous type=2 -03:30:52 NST
|
||||
0002: 1917-04-08T05:30:52Z unix=-1664130548 wall=1917-04-08T02:00:00 gap-until(1917-04-08T03:00:00) type=1 -02:30:52 NDT dst
|
||||
0003: 1917-09-17T04:30:52Z unix=-1650137348 wall=1917-09-17T01:00:00 fold-until(1917-09-17T02:00:00) type=2 -03:30:52 NST
|
||||
0004: 1918-04-14T05:30:52Z unix=-1632076148 wall=1918-04-14T02:00:00 gap-until(1918-04-14T03:00:00) type=1 -02:30:52 NDT dst
|
||||
0005: 1918-10-27T04:30:52Z unix=-1615145348 wall=1918-10-27T01:00:00 fold-until(1918-10-27T02:00:00) type=2 -03:30:52 NST
|
||||
0006: 1919-05-06T02:30:52Z unix=-1598650148 wall=1919-05-05T23:00:00 gap-until(1919-05-06T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0007: 1919-08-13T01:30:52Z unix=-1590100148 wall=1919-08-12T22:00:00 fold-until(1919-08-12T23:00:00) type=2 -03:30:52 NST
|
||||
0008: 1920-05-03T02:30:52Z unix=-1567286948 wall=1920-05-02T23:00:00 gap-until(1920-05-03T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0009: 1920-11-01T01:30:52Z unix=-1551565748 wall=1920-10-31T22:00:00 fold-until(1920-10-31T23:00:00) type=2 -03:30:52 NST
|
||||
0010: 1921-05-02T02:30:52Z unix=-1535837348 wall=1921-05-01T23:00:00 gap-until(1921-05-02T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0011: 1921-10-31T01:30:52Z unix=-1520116148 wall=1921-10-30T22:00:00 fold-until(1921-10-30T23:00:00) type=2 -03:30:52 NST
|
||||
0012: 1922-05-08T02:30:52Z unix=-1503782948 wall=1922-05-07T23:00:00 gap-until(1922-05-08T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0013: 1922-10-30T01:30:52Z unix=-1488666548 wall=1922-10-29T22:00:00 fold-until(1922-10-29T23:00:00) type=2 -03:30:52 NST
|
||||
0014: 1923-05-07T02:30:52Z unix=-1472333348 wall=1923-05-06T23:00:00 gap-until(1923-05-07T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0015: 1923-10-29T01:30:52Z unix=-1457216948 wall=1923-10-28T22:00:00 fold-until(1923-10-28T23:00:00) type=2 -03:30:52 NST
|
||||
0016: 1924-05-05T02:30:52Z unix=-1440883748 wall=1924-05-04T23:00:00 gap-until(1924-05-05T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0017: 1924-10-27T01:30:52Z unix=-1425767348 wall=1924-10-26T22:00:00 fold-until(1924-10-26T23:00:00) type=2 -03:30:52 NST
|
||||
0018: 1925-05-04T02:30:52Z unix=-1409434148 wall=1925-05-03T23:00:00 gap-until(1925-05-04T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0019: 1925-10-26T01:30:52Z unix=-1394317748 wall=1925-10-25T22:00:00 fold-until(1925-10-25T23:00:00) type=2 -03:30:52 NST
|
||||
0020: 1926-05-03T02:30:52Z unix=-1377984548 wall=1926-05-02T23:00:00 gap-until(1926-05-03T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0021: 1926-11-01T01:30:52Z unix=-1362263348 wall=1926-10-31T22:00:00 fold-until(1926-10-31T23:00:00) type=2 -03:30:52 NST
|
||||
0022: 1927-05-02T02:30:52Z unix=-1346534948 wall=1927-05-01T23:00:00 gap-until(1927-05-02T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0023: 1927-10-31T01:30:52Z unix=-1330813748 wall=1927-10-30T22:00:00 fold-until(1927-10-30T23:00:00) type=2 -03:30:52 NST
|
||||
0024: 1928-05-07T02:30:52Z unix=-1314480548 wall=1928-05-06T23:00:00 gap-until(1928-05-07T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0025: 1928-10-29T01:30:52Z unix=-1299364148 wall=1928-10-28T22:00:00 fold-until(1928-10-28T23:00:00) type=2 -03:30:52 NST
|
||||
0026: 1929-05-06T02:30:52Z unix=-1283030948 wall=1929-05-05T23:00:00 gap-until(1929-05-06T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0027: 1929-10-28T01:30:52Z unix=-1267914548 wall=1929-10-27T22:00:00 fold-until(1929-10-27T23:00:00) type=2 -03:30:52 NST
|
||||
0028: 1930-05-05T02:30:52Z unix=-1251581348 wall=1930-05-04T23:00:00 gap-until(1930-05-05T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0029: 1930-10-27T01:30:52Z unix=-1236464948 wall=1930-10-26T22:00:00 fold-until(1930-10-26T23:00:00) type=2 -03:30:52 NST
|
||||
0030: 1931-05-04T02:30:52Z unix=-1220131748 wall=1931-05-03T23:00:00 gap-until(1931-05-04T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0031: 1931-10-26T01:30:52Z unix=-1205015348 wall=1931-10-25T22:00:00 fold-until(1931-10-25T23:00:00) type=2 -03:30:52 NST
|
||||
0032: 1932-05-02T02:30:52Z unix=-1188682148 wall=1932-05-01T23:00:00 gap-until(1932-05-02T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0033: 1932-10-31T01:30:52Z unix=-1172960948 wall=1932-10-30T22:00:00 fold-until(1932-10-30T23:00:00) type=2 -03:30:52 NST
|
||||
0034: 1933-05-08T02:30:52Z unix=-1156627748 wall=1933-05-07T23:00:00 gap-until(1933-05-08T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0035: 1933-10-30T01:30:52Z unix=-1141511348 wall=1933-10-29T22:00:00 fold-until(1933-10-29T23:00:00) type=2 -03:30:52 NST
|
||||
0036: 1934-05-07T02:30:52Z unix=-1125178148 wall=1934-05-06T23:00:00 gap-until(1934-05-07T00:00:00) type=1 -02:30:52 NDT dst
|
||||
0037: 1934-10-29T01:30:52Z unix=-1110061748 wall=1934-10-28T22:00:00 fold-until(1934-10-28T23:00:00) type=2 -03:30:52 NST
|
||||
0038: 1935-03-30T03:30:52Z unix=-1096921748 wall=1935-03-30T00:00:00 gap-until(1935-03-30T00:00:52) type=4 -03:30 NST
|
||||
0039: 1935-05-06T02:30:00Z unix=-1093728600 wall=1935-05-05T23:00:00 gap-until(1935-05-06T00:00:00) type=3 -02:30 NDT dst
|
||||
0040: 1935-10-28T01:30:00Z unix=-1078612200 wall=1935-10-27T22:00:00 fold-until(1935-10-27T23:00:00) type=4 -03:30 NST
|
||||
0041: 1936-05-11T03:30:00Z unix=-1061670600 wall=1936-05-11T00:00:00 gap-until(1936-05-11T01:00:00) type=3 -02:30 NDT dst
|
||||
0042: 1936-10-05T02:30:00Z unix=-1048973400 wall=1936-10-04T23:00:00 fold-until(1936-10-05T00:00:00) type=4 -03:30 NST
|
||||
0043: 1937-05-10T03:30:00Z unix=-1030221000 wall=1937-05-10T00:00:00 gap-until(1937-05-10T01:00:00) type=3 -02:30 NDT dst
|
||||
0044: 1937-10-04T02:30:00Z unix=-1017523800 wall=1937-10-03T23:00:00 fold-until(1937-10-04T00:00:00) type=4 -03:30 NST
|
||||
0045: 1938-05-09T03:30:00Z unix=-998771400 wall=1938-05-09T00:00:00 gap-until(1938-05-09T01:00:00) type=3 -02:30 NDT dst
|
||||
0046: 1938-10-03T02:30:00Z unix=-986074200 wall=1938-10-02T23:00:00 fold-until(1938-10-03T00:00:00) type=4 -03:30 NST
|
||||
0047: 1939-05-15T03:30:00Z unix=-966717000 wall=1939-05-15T00:00:00 gap-until(1939-05-15T01:00:00) type=3 -02:30 NDT dst
|
||||
0048: 1939-10-02T02:30:00Z unix=-954624600 wall=1939-10-01T23:00:00 fold-until(1939-10-02T00:00:00) type=4 -03:30 NST
|
||||
0049: 1940-05-13T03:30:00Z unix=-935267400 wall=1940-05-13T00:00:00 gap-until(1940-05-13T01:00:00) type=3 -02:30 NDT dst
|
||||
0050: 1940-10-07T02:30:00Z unix=-922570200 wall=1940-10-06T23:00:00 fold-until(1940-10-07T00:00:00) type=4 -03:30 NST
|
||||
0051: 1941-05-12T03:30:00Z unix=-903817800 wall=1941-05-12T00:00:00 gap-until(1941-05-12T01:00:00) type=3 -02:30 NDT dst
|
||||
0052: 1941-10-06T02:30:00Z unix=-891120600 wall=1941-10-05T23:00:00 fold-until(1941-10-06T00:00:00) type=4 -03:30 NST
|
||||
0053: 1942-05-11T03:30:00Z unix=-872368200 wall=1942-05-11T00:00:00 gap-until(1942-05-11T01:00:00) type=6 -02:30 NWT dst
|
||||
0054: 1945-08-14T23:00:00Z unix=-769395600 wall=1945-08-14T20:30:00 unambiguous type=5 -02:30 NPT dst
|
||||
0055: 1945-09-30T04:30:00Z unix=-765401400 wall=1945-09-30T01:00:00 fold-until(1945-09-30T02:00:00) type=4 -03:30 NST
|
||||
0056: 1946-05-12T05:30:00Z unix=-746044200 wall=1946-05-12T02:00:00 gap-until(1946-05-12T03:00:00) type=3 -02:30 NDT dst
|
||||
0057: 1946-10-06T04:30:00Z unix=-733347000 wall=1946-10-06T01:00:00 fold-until(1946-10-06T02:00:00) type=4 -03:30 NST
|
||||
0058: 1947-05-11T05:30:00Z unix=-714594600 wall=1947-05-11T02:00:00 gap-until(1947-05-11T03:00:00) type=3 -02:30 NDT dst
|
||||
0059: 1947-10-05T04:30:00Z unix=-701897400 wall=1947-10-05T01:00:00 fold-until(1947-10-05T02:00:00) type=4 -03:30 NST
|
||||
0060: 1948-05-09T05:30:00Z unix=-683145000 wall=1948-05-09T02:00:00 gap-until(1948-05-09T03:00:00) type=3 -02:30 NDT dst
|
||||
0061: 1948-10-03T04:30:00Z unix=-670447800 wall=1948-10-03T01:00:00 fold-until(1948-10-03T02:00:00) type=4 -03:30 NST
|
||||
0062: 1949-05-08T05:30:00Z unix=-651695400 wall=1949-05-08T02:00:00 gap-until(1949-05-08T03:00:00) type=3 -02:30 NDT dst
|
||||
0063: 1949-10-02T04:30:00Z unix=-638998200 wall=1949-10-02T01:00:00 fold-until(1949-10-02T02:00:00) type=4 -03:30 NST
|
||||
0064: 1950-05-14T05:30:00Z unix=-619641000 wall=1950-05-14T02:00:00 gap-until(1950-05-14T03:00:00) type=3 -02:30 NDT dst
|
||||
0065: 1950-10-08T04:30:00Z unix=-606943800 wall=1950-10-08T01:00:00 fold-until(1950-10-08T02:00:00) type=4 -03:30 NST
|
||||
0066: 1951-04-29T05:30:00Z unix=-589401000 wall=1951-04-29T02:00:00 gap-until(1951-04-29T03:00:00) type=3 -02:30 NDT dst
|
||||
0067: 1951-09-30T04:30:00Z unix=-576099000 wall=1951-09-30T01:00:00 fold-until(1951-09-30T02:00:00) type=4 -03:30 NST
|
||||
0068: 1952-04-27T05:30:00Z unix=-557951400 wall=1952-04-27T02:00:00 gap-until(1952-04-27T03:00:00) type=3 -02:30 NDT dst
|
||||
0069: 1952-09-28T04:30:00Z unix=-544649400 wall=1952-09-28T01:00:00 fold-until(1952-09-28T02:00:00) type=4 -03:30 NST
|
||||
0070: 1953-04-26T05:30:00Z unix=-526501800 wall=1953-04-26T02:00:00 gap-until(1953-04-26T03:00:00) type=3 -02:30 NDT dst
|
||||
0071: 1953-09-27T04:30:00Z unix=-513199800 wall=1953-09-27T01:00:00 fold-until(1953-09-27T02:00:00) type=4 -03:30 NST
|
||||
0072: 1954-04-25T05:30:00Z unix=-495052200 wall=1954-04-25T02:00:00 gap-until(1954-04-25T03:00:00) type=3 -02:30 NDT dst
|
||||
0073: 1954-09-26T04:30:00Z unix=-481750200 wall=1954-09-26T01:00:00 fold-until(1954-09-26T02:00:00) type=4 -03:30 NST
|
||||
0074: 1955-04-24T05:30:00Z unix=-463602600 wall=1955-04-24T02:00:00 gap-until(1955-04-24T03:00:00) type=3 -02:30 NDT dst
|
||||
0075: 1955-09-25T04:30:00Z unix=-450300600 wall=1955-09-25T01:00:00 fold-until(1955-09-25T02:00:00) type=4 -03:30 NST
|
||||
0076: 1956-04-29T05:30:00Z unix=-431548200 wall=1956-04-29T02:00:00 gap-until(1956-04-29T03:00:00) type=3 -02:30 NDT dst
|
||||
0077: 1956-09-30T04:30:00Z unix=-418246200 wall=1956-09-30T01:00:00 fold-until(1956-09-30T02:00:00) type=4 -03:30 NST
|
||||
0078: 1957-04-28T05:30:00Z unix=-400098600 wall=1957-04-28T02:00:00 gap-until(1957-04-28T03:00:00) type=3 -02:30 NDT dst
|
||||
0079: 1957-09-29T04:30:00Z unix=-386796600 wall=1957-09-29T01:00:00 fold-until(1957-09-29T02:00:00) type=4 -03:30 NST
|
||||
0080: 1958-04-27T05:30:00Z unix=-368649000 wall=1958-04-27T02:00:00 gap-until(1958-04-27T03:00:00) type=3 -02:30 NDT dst
|
||||
0081: 1958-09-28T04:30:00Z unix=-355347000 wall=1958-09-28T01:00:00 fold-until(1958-09-28T02:00:00) type=4 -03:30 NST
|
||||
0082: 1959-04-26T05:30:00Z unix=-337199400 wall=1959-04-26T02:00:00 gap-until(1959-04-26T03:00:00) type=3 -02:30 NDT dst
|
||||
0083: 1959-09-27T04:30:00Z unix=-323897400 wall=1959-09-27T01:00:00 fold-until(1959-09-27T02:00:00) type=4 -03:30 NST
|
||||
0084: 1960-04-24T05:30:00Z unix=-305749800 wall=1960-04-24T02:00:00 gap-until(1960-04-24T03:00:00) type=3 -02:30 NDT dst
|
||||
0085: 1960-10-30T04:30:00Z unix=-289423800 wall=1960-10-30T01:00:00 fold-until(1960-10-30T02:00:00) type=4 -03:30 NST
|
||||
0086: 1961-04-30T05:30:00Z unix=-273695400 wall=1961-04-30T02:00:00 gap-until(1961-04-30T03:00:00) type=3 -02:30 NDT dst
|
||||
0087: 1961-10-29T04:30:00Z unix=-257974200 wall=1961-10-29T01:00:00 fold-until(1961-10-29T02:00:00) type=4 -03:30 NST
|
||||
0088: 1962-04-29T05:30:00Z unix=-242245800 wall=1962-04-29T02:00:00 gap-until(1962-04-29T03:00:00) type=3 -02:30 NDT dst
|
||||
0089: 1962-10-28T04:30:00Z unix=-226524600 wall=1962-10-28T01:00:00 fold-until(1962-10-28T02:00:00) type=4 -03:30 NST
|
||||
0090: 1963-04-28T05:30:00Z unix=-210796200 wall=1963-04-28T02:00:00 gap-until(1963-04-28T03:00:00) type=3 -02:30 NDT dst
|
||||
0091: 1963-10-27T04:30:00Z unix=-195075000 wall=1963-10-27T01:00:00 fold-until(1963-10-27T02:00:00) type=4 -03:30 NST
|
||||
0092: 1964-04-26T05:30:00Z unix=-179346600 wall=1964-04-26T02:00:00 gap-until(1964-04-26T03:00:00) type=3 -02:30 NDT dst
|
||||
0093: 1964-10-25T04:30:00Z unix=-163625400 wall=1964-10-25T01:00:00 fold-until(1964-10-25T02:00:00) type=4 -03:30 NST
|
||||
0094: 1965-04-25T05:30:00Z unix=-147897000 wall=1965-04-25T02:00:00 gap-until(1965-04-25T03:00:00) type=3 -02:30 NDT dst
|
||||
0095: 1965-10-31T04:30:00Z unix=-131571000 wall=1965-10-31T01:00:00 fold-until(1965-10-31T02:00:00) type=4 -03:30 NST
|
||||
0096: 1966-04-24T05:30:00Z unix=-116447400 wall=1966-04-24T02:00:00 gap-until(1966-04-24T03:00:00) type=3 -02:30 NDT dst
|
||||
0097: 1966-10-30T04:30:00Z unix=-100121400 wall=1966-10-30T01:00:00 fold-until(1966-10-30T02:00:00) type=4 -03:30 NST
|
||||
0098: 1967-04-30T05:30:00Z unix=-84393000 wall=1967-04-30T02:00:00 gap-until(1967-04-30T03:00:00) type=3 -02:30 NDT dst
|
||||
0099: 1967-10-29T04:30:00Z unix=-68671800 wall=1967-10-29T01:00:00 fold-until(1967-10-29T02:00:00) type=4 -03:30 NST
|
||||
0100: 1968-04-28T05:30:00Z unix=-52943400 wall=1968-04-28T02:00:00 gap-until(1968-04-28T03:00:00) type=3 -02:30 NDT dst
|
||||
0101: 1968-10-27T04:30:00Z unix=-37222200 wall=1968-10-27T01:00:00 fold-until(1968-10-27T02:00:00) type=4 -03:30 NST
|
||||
0102: 1969-04-27T05:30:00Z unix=-21493800 wall=1969-04-27T02:00:00 gap-until(1969-04-27T03:00:00) type=3 -02:30 NDT dst
|
||||
0103: 1969-10-26T04:30:00Z unix=-5772600 wall=1969-10-26T01:00:00 fold-until(1969-10-26T02:00:00) type=4 -03:30 NST
|
||||
0104: 1970-04-26T05:30:00Z unix=9955800 wall=1970-04-26T02:00:00 gap-until(1970-04-26T03:00:00) type=3 -02:30 NDT dst
|
||||
0105: 1970-10-25T04:30:00Z unix=25677000 wall=1970-10-25T01:00:00 fold-until(1970-10-25T02:00:00) type=4 -03:30 NST
|
||||
0106: 1971-04-25T05:30:00Z unix=41405400 wall=1971-04-25T02:00:00 gap-until(1971-04-25T03:00:00) type=3 -02:30 NDT dst
|
||||
0107: 1971-10-31T04:30:00Z unix=57731400 wall=1971-10-31T01:00:00 fold-until(1971-10-31T02:00:00) type=4 -03:30 NST
|
||||
0108: 1972-04-30T05:30:00Z unix=73459800 wall=1972-04-30T02:00:00 gap-until(1972-04-30T03:00:00) type=3 -02:30 NDT dst
|
||||
0109: 1972-10-29T04:30:00Z unix=89181000 wall=1972-10-29T01:00:00 fold-until(1972-10-29T02:00:00) type=4 -03:30 NST
|
||||
0110: 1973-04-29T05:30:00Z unix=104909400 wall=1973-04-29T02:00:00 gap-until(1973-04-29T03:00:00) type=3 -02:30 NDT dst
|
||||
0111: 1973-10-28T04:30:00Z unix=120630600 wall=1973-10-28T01:00:00 fold-until(1973-10-28T02:00:00) type=4 -03:30 NST
|
||||
0112: 1974-04-28T05:30:00Z unix=136359000 wall=1974-04-28T02:00:00 gap-until(1974-04-28T03:00:00) type=3 -02:30 NDT dst
|
||||
0113: 1974-10-27T04:30:00Z unix=152080200 wall=1974-10-27T01:00:00 fold-until(1974-10-27T02:00:00) type=4 -03:30 NST
|
||||
0114: 1975-04-27T05:30:00Z unix=167808600 wall=1975-04-27T02:00:00 gap-until(1975-04-27T03:00:00) type=3 -02:30 NDT dst
|
||||
0115: 1975-10-26T04:30:00Z unix=183529800 wall=1975-10-26T01:00:00 fold-until(1975-10-26T02:00:00) type=4 -03:30 NST
|
||||
0116: 1976-04-25T05:30:00Z unix=199258200 wall=1976-04-25T02:00:00 gap-until(1976-04-25T03:00:00) type=3 -02:30 NDT dst
|
||||
0117: 1976-10-31T04:30:00Z unix=215584200 wall=1976-10-31T01:00:00 fold-until(1976-10-31T02:00:00) type=4 -03:30 NST
|
||||
0118: 1977-04-24T05:30:00Z unix=230707800 wall=1977-04-24T02:00:00 gap-until(1977-04-24T03:00:00) type=3 -02:30 NDT dst
|
||||
0119: 1977-10-30T04:30:00Z unix=247033800 wall=1977-10-30T01:00:00 fold-until(1977-10-30T02:00:00) type=4 -03:30 NST
|
||||
0120: 1978-04-30T05:30:00Z unix=262762200 wall=1978-04-30T02:00:00 gap-until(1978-04-30T03:00:00) type=3 -02:30 NDT dst
|
||||
0121: 1978-10-29T04:30:00Z unix=278483400 wall=1978-10-29T01:00:00 fold-until(1978-10-29T02:00:00) type=4 -03:30 NST
|
||||
0122: 1979-04-29T05:30:00Z unix=294211800 wall=1979-04-29T02:00:00 gap-until(1979-04-29T03:00:00) type=3 -02:30 NDT dst
|
||||
0123: 1979-10-28T04:30:00Z unix=309933000 wall=1979-10-28T01:00:00 fold-until(1979-10-28T02:00:00) type=4 -03:30 NST
|
||||
0124: 1980-04-27T05:30:00Z unix=325661400 wall=1980-04-27T02:00:00 gap-until(1980-04-27T03:00:00) type=3 -02:30 NDT dst
|
||||
0125: 1980-10-26T04:30:00Z unix=341382600 wall=1980-10-26T01:00:00 fold-until(1980-10-26T02:00:00) type=4 -03:30 NST
|
||||
0126: 1981-04-26T05:30:00Z unix=357111000 wall=1981-04-26T02:00:00 gap-until(1981-04-26T03:00:00) type=3 -02:30 NDT dst
|
||||
0127: 1981-10-25T04:30:00Z unix=372832200 wall=1981-10-25T01:00:00 fold-until(1981-10-25T02:00:00) type=4 -03:30 NST
|
||||
0128: 1982-04-25T05:30:00Z unix=388560600 wall=1982-04-25T02:00:00 gap-until(1982-04-25T03:00:00) type=3 -02:30 NDT dst
|
||||
0129: 1982-10-31T04:30:00Z unix=404886600 wall=1982-10-31T01:00:00 fold-until(1982-10-31T02:00:00) type=4 -03:30 NST
|
||||
0130: 1983-04-24T05:30:00Z unix=420010200 wall=1983-04-24T02:00:00 gap-until(1983-04-24T03:00:00) type=3 -02:30 NDT dst
|
||||
0131: 1983-10-30T04:30:00Z unix=436336200 wall=1983-10-30T01:00:00 fold-until(1983-10-30T02:00:00) type=4 -03:30 NST
|
||||
0132: 1984-04-29T05:30:00Z unix=452064600 wall=1984-04-29T02:00:00 gap-until(1984-04-29T03:00:00) type=3 -02:30 NDT dst
|
||||
0133: 1984-10-28T04:30:00Z unix=467785800 wall=1984-10-28T01:00:00 fold-until(1984-10-28T02:00:00) type=4 -03:30 NST
|
||||
0134: 1985-04-28T05:30:00Z unix=483514200 wall=1985-04-28T02:00:00 gap-until(1985-04-28T03:00:00) type=3 -02:30 NDT dst
|
||||
0135: 1985-10-27T04:30:00Z unix=499235400 wall=1985-10-27T01:00:00 fold-until(1985-10-27T02:00:00) type=4 -03:30 NST
|
||||
0136: 1986-04-27T05:30:00Z unix=514963800 wall=1986-04-27T02:00:00 gap-until(1986-04-27T03:00:00) type=3 -02:30 NDT dst
|
||||
0137: 1986-10-26T04:30:00Z unix=530685000 wall=1986-10-26T01:00:00 fold-until(1986-10-26T02:00:00) type=4 -03:30 NST
|
||||
0138: 1987-04-05T03:31:00Z unix=544591860 wall=1987-04-05T00:01:00 gap-until(1987-04-05T01:01:00) type=3 -02:30 NDT dst
|
||||
0139: 1987-10-25T02:31:00Z unix=562127460 wall=1987-10-24T23:01:00 fold-until(1987-10-25T00:01:00) type=4 -03:30 NST
|
||||
0140: 1988-04-03T03:31:00Z unix=576041460 wall=1988-04-03T00:01:00 gap-until(1988-04-03T02:01:00) type=7 -01:30 NDDT dst
|
||||
0141: 1988-10-30T01:31:00Z unix=594178260 wall=1988-10-29T22:01:00 fold-until(1988-10-30T00:01:00) type=4 -03:30 NST
|
||||
0142: 1989-04-02T03:31:00Z unix=607491060 wall=1989-04-02T00:01:00 gap-until(1989-04-02T01:01:00) type=3 -02:30 NDT dst
|
||||
0143: 1989-10-29T02:31:00Z unix=625631460 wall=1989-10-28T23:01:00 fold-until(1989-10-29T00:01:00) type=4 -03:30 NST
|
||||
0144: 1990-04-01T03:31:00Z unix=638940660 wall=1990-04-01T00:01:00 gap-until(1990-04-01T01:01:00) type=3 -02:30 NDT dst
|
||||
0145: 1990-10-28T02:31:00Z unix=657081060 wall=1990-10-27T23:01:00 fold-until(1990-10-28T00:01:00) type=4 -03:30 NST
|
||||
0146: 1991-04-07T03:31:00Z unix=670995060 wall=1991-04-07T00:01:00 gap-until(1991-04-07T01:01:00) type=3 -02:30 NDT dst
|
||||
0147: 1991-10-27T02:31:00Z unix=688530660 wall=1991-10-26T23:01:00 fold-until(1991-10-27T00:01:00) type=4 -03:30 NST
|
||||
0148: 1992-04-05T03:31:00Z unix=702444660 wall=1992-04-05T00:01:00 gap-until(1992-04-05T01:01:00) type=3 -02:30 NDT dst
|
||||
0149: 1992-10-25T02:31:00Z unix=719980260 wall=1992-10-24T23:01:00 fold-until(1992-10-25T00:01:00) type=4 -03:30 NST
|
||||
0150: 1993-04-04T03:31:00Z unix=733894260 wall=1993-04-04T00:01:00 gap-until(1993-04-04T01:01:00) type=3 -02:30 NDT dst
|
||||
0151: 1993-10-31T02:31:00Z unix=752034660 wall=1993-10-30T23:01:00 fold-until(1993-10-31T00:01:00) type=4 -03:30 NST
|
||||
0152: 1994-04-03T03:31:00Z unix=765343860 wall=1994-04-03T00:01:00 gap-until(1994-04-03T01:01:00) type=3 -02:30 NDT dst
|
||||
0153: 1994-10-30T02:31:00Z unix=783484260 wall=1994-10-29T23:01:00 fold-until(1994-10-30T00:01:00) type=4 -03:30 NST
|
||||
0154: 1995-04-02T03:31:00Z unix=796793460 wall=1995-04-02T00:01:00 gap-until(1995-04-02T01:01:00) type=3 -02:30 NDT dst
|
||||
0155: 1995-10-29T02:31:00Z unix=814933860 wall=1995-10-28T23:01:00 fold-until(1995-10-29T00:01:00) type=4 -03:30 NST
|
||||
0156: 1996-04-07T03:31:00Z unix=828847860 wall=1996-04-07T00:01:00 gap-until(1996-04-07T01:01:00) type=3 -02:30 NDT dst
|
||||
0157: 1996-10-27T02:31:00Z unix=846383460 wall=1996-10-26T23:01:00 fold-until(1996-10-27T00:01:00) type=4 -03:30 NST
|
||||
0158: 1997-04-06T03:31:00Z unix=860297460 wall=1997-04-06T00:01:00 gap-until(1997-04-06T01:01:00) type=3 -02:30 NDT dst
|
||||
0159: 1997-10-26T02:31:00Z unix=877833060 wall=1997-10-25T23:01:00 fold-until(1997-10-26T00:01:00) type=4 -03:30 NST
|
||||
0160: 1998-04-05T03:31:00Z unix=891747060 wall=1998-04-05T00:01:00 gap-until(1998-04-05T01:01:00) type=3 -02:30 NDT dst
|
||||
0161: 1998-10-25T02:31:00Z unix=909282660 wall=1998-10-24T23:01:00 fold-until(1998-10-25T00:01:00) type=4 -03:30 NST
|
||||
0162: 1999-04-04T03:31:00Z unix=923196660 wall=1999-04-04T00:01:00 gap-until(1999-04-04T01:01:00) type=3 -02:30 NDT dst
|
||||
0163: 1999-10-31T02:31:00Z unix=941337060 wall=1999-10-30T23:01:00 fold-until(1999-10-31T00:01:00) type=4 -03:30 NST
|
||||
0164: 2000-04-02T03:31:00Z unix=954646260 wall=2000-04-02T00:01:00 gap-until(2000-04-02T01:01:00) type=3 -02:30 NDT dst
|
||||
0165: 2000-10-29T02:31:00Z unix=972786660 wall=2000-10-28T23:01:00 fold-until(2000-10-29T00:01:00) type=4 -03:30 NST
|
||||
0166: 2001-04-01T03:31:00Z unix=986095860 wall=2001-04-01T00:01:00 gap-until(2001-04-01T01:01:00) type=3 -02:30 NDT dst
|
||||
0167: 2001-10-28T02:31:00Z unix=1004236260 wall=2001-10-27T23:01:00 fold-until(2001-10-28T00:01:00) type=4 -03:30 NST
|
||||
0168: 2002-04-07T03:31:00Z unix=1018150260 wall=2002-04-07T00:01:00 gap-until(2002-04-07T01:01:00) type=3 -02:30 NDT dst
|
||||
0169: 2002-10-27T02:31:00Z unix=1035685860 wall=2002-10-26T23:01:00 fold-until(2002-10-27T00:01:00) type=4 -03:30 NST
|
||||
0170: 2003-04-06T03:31:00Z unix=1049599860 wall=2003-04-06T00:01:00 gap-until(2003-04-06T01:01:00) type=3 -02:30 NDT dst
|
||||
0171: 2003-10-26T02:31:00Z unix=1067135460 wall=2003-10-25T23:01:00 fold-until(2003-10-26T00:01:00) type=4 -03:30 NST
|
||||
0172: 2004-04-04T03:31:00Z unix=1081049460 wall=2004-04-04T00:01:00 gap-until(2004-04-04T01:01:00) type=3 -02:30 NDT dst
|
||||
0173: 2004-10-31T02:31:00Z unix=1099189860 wall=2004-10-30T23:01:00 fold-until(2004-10-31T00:01:00) type=4 -03:30 NST
|
||||
0174: 2005-04-03T03:31:00Z unix=1112499060 wall=2005-04-03T00:01:00 gap-until(2005-04-03T01:01:00) type=3 -02:30 NDT dst
|
||||
0175: 2005-10-30T02:31:00Z unix=1130639460 wall=2005-10-29T23:01:00 fold-until(2005-10-30T00:01:00) type=4 -03:30 NST
|
||||
0176: 2006-04-02T03:31:00Z unix=1143948660 wall=2006-04-02T00:01:00 gap-until(2006-04-02T01:01:00) type=3 -02:30 NDT dst
|
||||
0177: 2006-10-29T02:31:00Z unix=1162089060 wall=2006-10-28T23:01:00 fold-until(2006-10-29T00:01:00) type=4 -03:30 NST
|
||||
0178: 2007-03-11T03:31:00Z unix=1173583860 wall=2007-03-11T00:01:00 gap-until(2007-03-11T01:01:00) type=3 -02:30 NDT dst
|
||||
0179: 2007-11-04T02:31:00Z unix=1194143460 wall=2007-11-03T23:01:00 fold-until(2007-11-04T00:01:00) type=4 -03:30 NST
|
||||
0180: 2008-03-09T03:31:00Z unix=1205033460 wall=2008-03-09T00:01:00 gap-until(2008-03-09T01:01:00) type=3 -02:30 NDT dst
|
||||
0181: 2008-11-02T02:31:00Z unix=1225593060 wall=2008-11-01T23:01:00 fold-until(2008-11-02T00:01:00) type=4 -03:30 NST
|
||||
0182: 2009-03-08T03:31:00Z unix=1236483060 wall=2009-03-08T00:01:00 gap-until(2009-03-08T01:01:00) type=3 -02:30 NDT dst
|
||||
0183: 2009-11-01T02:31:00Z unix=1257042660 wall=2009-10-31T23:01:00 fold-until(2009-11-01T00:01:00) type=4 -03:30 NST
|
||||
0184: 2010-03-14T03:31:00Z unix=1268537460 wall=2010-03-14T00:01:00 gap-until(2010-03-14T01:01:00) type=3 -02:30 NDT dst
|
||||
0185: 2010-11-07T02:31:00Z unix=1289097060 wall=2010-11-06T23:01:00 fold-until(2010-11-07T00:01:00) type=4 -03:30 NST
|
||||
0186: 2011-03-13T03:31:00Z unix=1299987060 wall=2011-03-13T00:01:00 gap-until(2011-03-13T01:01:00) type=3 -02:30 NDT dst
|
||||
0187: 2011-11-06T04:30:00Z unix=1320553800 wall=2011-11-06T01:00:00 fold-until(2011-11-06T02:00:00) type=4 -03:30 NST
|
||||
0188: 2012-03-11T05:30:00Z unix=1331443800 wall=2012-03-11T02:00:00 gap-until(2012-03-11T03:00:00) type=3 -02:30 NDT dst
|
||||
0189: 2012-11-04T04:30:00Z unix=1352003400 wall=2012-11-04T01:00:00 fold-until(2012-11-04T02:00:00) type=4 -03:30 NST
|
||||
0190: 2013-03-10T05:30:00Z unix=1362893400 wall=2013-03-10T02:00:00 gap-until(2013-03-10T03:00:00) type=3 -02:30 NDT dst
|
||||
0191: 2013-11-03T04:30:00Z unix=1383453000 wall=2013-11-03T01:00:00 fold-until(2013-11-03T02:00:00) type=4 -03:30 NST
|
||||
0192: 2014-03-09T05:30:00Z unix=1394343000 wall=2014-03-09T02:00:00 gap-until(2014-03-09T03:00:00) type=3 -02:30 NDT dst
|
||||
0193: 2014-11-02T04:30:00Z unix=1414902600 wall=2014-11-02T01:00:00 fold-until(2014-11-02T02:00:00) type=4 -03:30 NST
|
||||
0194: 2015-03-08T05:30:00Z unix=1425792600 wall=2015-03-08T02:00:00 gap-until(2015-03-08T03:00:00) type=3 -02:30 NDT dst
|
||||
0195: 2015-11-01T04:30:00Z unix=1446352200 wall=2015-11-01T01:00:00 fold-until(2015-11-01T02:00:00) type=4 -03:30 NST
|
||||
0196: 2016-03-13T05:30:00Z unix=1457847000 wall=2016-03-13T02:00:00 gap-until(2016-03-13T03:00:00) type=3 -02:30 NDT dst
|
||||
0197: 2016-11-06T04:30:00Z unix=1478406600 wall=2016-11-06T01:00:00 fold-until(2016-11-06T02:00:00) type=4 -03:30 NST
|
||||
0198: 2017-03-12T05:30:00Z unix=1489296600 wall=2017-03-12T02:00:00 gap-until(2017-03-12T03:00:00) type=3 -02:30 NDT dst
|
||||
0199: 2017-11-05T04:30:00Z unix=1509856200 wall=2017-11-05T01:00:00 fold-until(2017-11-05T02:00:00) type=4 -03:30 NST
|
||||
0200: 2018-03-11T05:30:00Z unix=1520746200 wall=2018-03-11T02:00:00 gap-until(2018-03-11T03:00:00) type=3 -02:30 NDT dst
|
||||
0201: 2018-11-04T04:30:00Z unix=1541305800 wall=2018-11-04T01:00:00 fold-until(2018-11-04T02:00:00) type=4 -03:30 NST
|
||||
0202: 2019-03-10T05:30:00Z unix=1552195800 wall=2019-03-10T02:00:00 gap-until(2019-03-10T03:00:00) type=3 -02:30 NDT dst
|
||||
0203: 2019-11-03T04:30:00Z unix=1572755400 wall=2019-11-03T01:00:00 fold-until(2019-11-03T02:00:00) type=4 -03:30 NST
|
||||
0204: 2020-03-08T05:30:00Z unix=1583645400 wall=2020-03-08T02:00:00 gap-until(2020-03-08T03:00:00) type=3 -02:30 NDT dst
|
||||
0205: 2020-11-01T04:30:00Z unix=1604205000 wall=2020-11-01T01:00:00 fold-until(2020-11-01T02:00:00) type=4 -03:30 NST
|
||||
0206: 2021-03-14T05:30:00Z unix=1615699800 wall=2021-03-14T02:00:00 gap-until(2021-03-14T03:00:00) type=3 -02:30 NDT dst
|
||||
0207: 2021-11-07T04:30:00Z unix=1636259400 wall=2021-11-07T01:00:00 fold-until(2021-11-07T02:00:00) type=4 -03:30 NST
|
||||
0208: 2022-03-13T05:30:00Z unix=1647149400 wall=2022-03-13T02:00:00 gap-until(2022-03-13T03:00:00) type=3 -02:30 NDT dst
|
||||
0209: 2022-11-06T04:30:00Z unix=1667709000 wall=2022-11-06T01:00:00 fold-until(2022-11-06T02:00:00) type=4 -03:30 NST
|
||||
0210: 2023-03-12T05:30:00Z unix=1678599000 wall=2023-03-12T02:00:00 gap-until(2023-03-12T03:00:00) type=3 -02:30 NDT dst
|
||||
0211: 2023-11-05T04:30:00Z unix=1699158600 wall=2023-11-05T01:00:00 fold-until(2023-11-05T02:00:00) type=4 -03:30 NST
|
||||
0212: 2024-03-10T05:30:00Z unix=1710048600 wall=2024-03-10T02:00:00 gap-until(2024-03-10T03:00:00) type=3 -02:30 NDT dst
|
||||
0213: 2024-11-03T04:30:00Z unix=1730608200 wall=2024-11-03T01:00:00 fold-until(2024-11-03T02:00:00) type=4 -03:30 NST
|
||||
0214: 2025-03-09T05:30:00Z unix=1741498200 wall=2025-03-09T02:00:00 gap-until(2025-03-09T03:00:00) type=3 -02:30 NDT dst
|
||||
0215: 2025-11-02T04:30:00Z unix=1762057800 wall=2025-11-02T01:00:00 fold-until(2025-11-02T02:00:00) type=4 -03:30 NST
|
||||
0216: 2026-03-08T05:30:00Z unix=1772947800 wall=2026-03-08T02:00:00 gap-until(2026-03-08T03:00:00) type=3 -02:30 NDT dst
|
||||
0217: 2026-11-01T04:30:00Z unix=1793507400 wall=2026-11-01T01:00:00 fold-until(2026-11-01T02:00:00) type=4 -03:30 NST
|
||||
0218: 2027-03-14T05:30:00Z unix=1805002200 wall=2027-03-14T02:00:00 gap-until(2027-03-14T03:00:00) type=3 -02:30 NDT dst
|
||||
0219: 2027-11-07T04:30:00Z unix=1825561800 wall=2027-11-07T01:00:00 fold-until(2027-11-07T02:00:00) type=4 -03:30 NST
|
||||
0220: 2028-03-12T05:30:00Z unix=1836451800 wall=2028-03-12T02:00:00 gap-until(2028-03-12T03:00:00) type=3 -02:30 NDT dst
|
||||
0221: 2028-11-05T04:30:00Z unix=1857011400 wall=2028-11-05T01:00:00 fold-until(2028-11-05T02:00:00) type=4 -03:30 NST
|
||||
0222: 2029-03-11T05:30:00Z unix=1867901400 wall=2029-03-11T02:00:00 gap-until(2029-03-11T03:00:00) type=3 -02:30 NDT dst
|
||||
0223: 2029-11-04T04:30:00Z unix=1888461000 wall=2029-11-04T01:00:00 fold-until(2029-11-04T02:00:00) type=4 -03:30 NST
|
||||
0224: 2030-03-10T05:30:00Z unix=1899351000 wall=2030-03-10T02:00:00 gap-until(2030-03-10T03:00:00) type=3 -02:30 NDT dst
|
||||
0225: 2030-11-03T04:30:00Z unix=1919910600 wall=2030-11-03T01:00:00 fold-until(2030-11-03T02:00:00) type=4 -03:30 NST
|
||||
0226: 2031-03-09T05:30:00Z unix=1930800600 wall=2031-03-09T02:00:00 gap-until(2031-03-09T03:00:00) type=3 -02:30 NDT dst
|
||||
0227: 2031-11-02T04:30:00Z unix=1951360200 wall=2031-11-02T01:00:00 fold-until(2031-11-02T02:00:00) type=4 -03:30 NST
|
||||
0228: 2032-03-14T05:30:00Z unix=1962855000 wall=2032-03-14T02:00:00 gap-until(2032-03-14T03:00:00) type=3 -02:30 NDT dst
|
||||
0229: 2032-11-07T04:30:00Z unix=1983414600 wall=2032-11-07T01:00:00 fold-until(2032-11-07T02:00:00) type=4 -03:30 NST
|
||||
0230: 2033-03-13T05:30:00Z unix=1994304600 wall=2033-03-13T02:00:00 gap-until(2033-03-13T03:00:00) type=3 -02:30 NDT dst
|
||||
0231: 2033-11-06T04:30:00Z unix=2014864200 wall=2033-11-06T01:00:00 fold-until(2033-11-06T02:00:00) type=4 -03:30 NST
|
||||
0232: 2034-03-12T05:30:00Z unix=2025754200 wall=2034-03-12T02:00:00 gap-until(2034-03-12T03:00:00) type=3 -02:30 NDT dst
|
||||
0233: 2034-11-05T04:30:00Z unix=2046313800 wall=2034-11-05T01:00:00 fold-until(2034-11-05T02:00:00) type=4 -03:30 NST
|
||||
0234: 2035-03-11T05:30:00Z unix=2057203800 wall=2035-03-11T02:00:00 gap-until(2035-03-11T03:00:00) type=3 -02:30 NDT dst
|
||||
0235: 2035-11-04T04:30:00Z unix=2077763400 wall=2035-11-04T01:00:00 fold-until(2035-11-04T02:00:00) type=4 -03:30 NST
|
||||
0236: 2036-03-09T05:30:00Z unix=2088653400 wall=2036-03-09T02:00:00 gap-until(2036-03-09T03:00:00) type=3 -02:30 NDT dst
|
||||
0237: 2036-11-02T04:30:00Z unix=2109213000 wall=2036-11-02T01:00:00 fold-until(2036-11-02T02:00:00) type=4 -03:30 NST
|
||||
0238: 2037-03-08T05:30:00Z unix=2120103000 wall=2037-03-08T02:00:00 gap-until(2037-03-08T03:00:00) type=3 -02:30 NDT dst
|
||||
0239: 2037-11-01T04:30:00Z unix=2140662600 wall=2037-11-01T01:00:00 fold-until(2037-11-01T02:00:00) type=4 -03:30 NST
|
||||
POSIX TIME ZONE STRING
|
||||
NST3:30NDT,M3.2.0,M11.1.0
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse_v1())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
Antarctica/Troll
|
||||
LOCAL TIME TYPES
|
||||
000: offset=+00 designation=-00 indicator=local/wall
|
||||
001: offset=+02 designation=+02 dst indicator=ut/std
|
||||
002: offset=+00 designation=+00 indicator=ut/std
|
||||
003: offset=+00 designation=+00 indicator=local/wall
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-02T01:59:59 unambiguous type=0 +00 -00
|
||||
0001: 2005-02-12T00:00:00Z unix=1108166400 wall=2005-02-12T00:00:00 unambiguous type=3 +00 +00
|
||||
0002: 2005-03-27T01:00:00Z unix=1111885200 wall=2005-03-27T01:00:00 gap-until(2005-03-27T03:00:00) type=1 +02 +02 dst
|
||||
0003: 2005-10-30T01:00:00Z unix=1130634000 wall=2005-10-30T01:00:00 fold-until(2005-10-30T03:00:00) type=2 +00 +00
|
||||
0004: 2006-03-26T01:00:00Z unix=1143334800 wall=2006-03-26T01:00:00 gap-until(2006-03-26T03:00:00) type=1 +02 +02 dst
|
||||
0005: 2006-10-29T01:00:00Z unix=1162083600 wall=2006-10-29T01:00:00 fold-until(2006-10-29T03:00:00) type=2 +00 +00
|
||||
0006: 2007-03-25T01:00:00Z unix=1174784400 wall=2007-03-25T01:00:00 gap-until(2007-03-25T03:00:00) type=1 +02 +02 dst
|
||||
0007: 2007-10-28T01:00:00Z unix=1193533200 wall=2007-10-28T01:00:00 fold-until(2007-10-28T03:00:00) type=2 +00 +00
|
||||
0008: 2008-03-30T01:00:00Z unix=1206838800 wall=2008-03-30T01:00:00 gap-until(2008-03-30T03:00:00) type=1 +02 +02 dst
|
||||
0009: 2008-10-26T01:00:00Z unix=1224982800 wall=2008-10-26T01:00:00 fold-until(2008-10-26T03:00:00) type=2 +00 +00
|
||||
0010: 2009-03-29T01:00:00Z unix=1238288400 wall=2009-03-29T01:00:00 gap-until(2009-03-29T03:00:00) type=1 +02 +02 dst
|
||||
0011: 2009-10-25T01:00:00Z unix=1256432400 wall=2009-10-25T01:00:00 fold-until(2009-10-25T03:00:00) type=2 +00 +00
|
||||
0012: 2010-03-28T01:00:00Z unix=1269738000 wall=2010-03-28T01:00:00 gap-until(2010-03-28T03:00:00) type=1 +02 +02 dst
|
||||
0013: 2010-10-31T01:00:00Z unix=1288486800 wall=2010-10-31T01:00:00 fold-until(2010-10-31T03:00:00) type=2 +00 +00
|
||||
0014: 2011-03-27T01:00:00Z unix=1301187600 wall=2011-03-27T01:00:00 gap-until(2011-03-27T03:00:00) type=1 +02 +02 dst
|
||||
0015: 2011-10-30T01:00:00Z unix=1319936400 wall=2011-10-30T01:00:00 fold-until(2011-10-30T03:00:00) type=2 +00 +00
|
||||
0016: 2012-03-25T01:00:00Z unix=1332637200 wall=2012-03-25T01:00:00 gap-until(2012-03-25T03:00:00) type=1 +02 +02 dst
|
||||
0017: 2012-10-28T01:00:00Z unix=1351386000 wall=2012-10-28T01:00:00 fold-until(2012-10-28T03:00:00) type=2 +00 +00
|
||||
0018: 2013-03-31T01:00:00Z unix=1364691600 wall=2013-03-31T01:00:00 gap-until(2013-03-31T03:00:00) type=1 +02 +02 dst
|
||||
0019: 2013-10-27T01:00:00Z unix=1382835600 wall=2013-10-27T01:00:00 fold-until(2013-10-27T03:00:00) type=2 +00 +00
|
||||
0020: 2014-03-30T01:00:00Z unix=1396141200 wall=2014-03-30T01:00:00 gap-until(2014-03-30T03:00:00) type=1 +02 +02 dst
|
||||
0021: 2014-10-26T01:00:00Z unix=1414285200 wall=2014-10-26T01:00:00 fold-until(2014-10-26T03:00:00) type=2 +00 +00
|
||||
0022: 2015-03-29T01:00:00Z unix=1427590800 wall=2015-03-29T01:00:00 gap-until(2015-03-29T03:00:00) type=1 +02 +02 dst
|
||||
0023: 2015-10-25T01:00:00Z unix=1445734800 wall=2015-10-25T01:00:00 fold-until(2015-10-25T03:00:00) type=2 +00 +00
|
||||
0024: 2016-03-27T01:00:00Z unix=1459040400 wall=2016-03-27T01:00:00 gap-until(2016-03-27T03:00:00) type=1 +02 +02 dst
|
||||
0025: 2016-10-30T01:00:00Z unix=1477789200 wall=2016-10-30T01:00:00 fold-until(2016-10-30T03:00:00) type=2 +00 +00
|
||||
0026: 2017-03-26T01:00:00Z unix=1490490000 wall=2017-03-26T01:00:00 gap-until(2017-03-26T03:00:00) type=1 +02 +02 dst
|
||||
0027: 2017-10-29T01:00:00Z unix=1509238800 wall=2017-10-29T01:00:00 fold-until(2017-10-29T03:00:00) type=2 +00 +00
|
||||
0028: 2018-03-25T01:00:00Z unix=1521939600 wall=2018-03-25T01:00:00 gap-until(2018-03-25T03:00:00) type=1 +02 +02 dst
|
||||
0029: 2018-10-28T01:00:00Z unix=1540688400 wall=2018-10-28T01:00:00 fold-until(2018-10-28T03:00:00) type=2 +00 +00
|
||||
0030: 2019-03-31T01:00:00Z unix=1553994000 wall=2019-03-31T01:00:00 gap-until(2019-03-31T03:00:00) type=1 +02 +02 dst
|
||||
0031: 2019-10-27T01:00:00Z unix=1572138000 wall=2019-10-27T01:00:00 fold-until(2019-10-27T03:00:00) type=2 +00 +00
|
||||
0032: 2020-03-29T01:00:00Z unix=1585443600 wall=2020-03-29T01:00:00 gap-until(2020-03-29T03:00:00) type=1 +02 +02 dst
|
||||
0033: 2020-10-25T01:00:00Z unix=1603587600 wall=2020-10-25T01:00:00 fold-until(2020-10-25T03:00:00) type=2 +00 +00
|
||||
0034: 2021-03-28T01:00:00Z unix=1616893200 wall=2021-03-28T01:00:00 gap-until(2021-03-28T03:00:00) type=1 +02 +02 dst
|
||||
0035: 2021-10-31T01:00:00Z unix=1635642000 wall=2021-10-31T01:00:00 fold-until(2021-10-31T03:00:00) type=2 +00 +00
|
||||
0036: 2022-03-27T01:00:00Z unix=1648342800 wall=2022-03-27T01:00:00 gap-until(2022-03-27T03:00:00) type=1 +02 +02 dst
|
||||
0037: 2022-10-30T01:00:00Z unix=1667091600 wall=2022-10-30T01:00:00 fold-until(2022-10-30T03:00:00) type=2 +00 +00
|
||||
0038: 2023-03-26T01:00:00Z unix=1679792400 wall=2023-03-26T01:00:00 gap-until(2023-03-26T03:00:00) type=1 +02 +02 dst
|
||||
0039: 2023-10-29T01:00:00Z unix=1698541200 wall=2023-10-29T01:00:00 fold-until(2023-10-29T03:00:00) type=2 +00 +00
|
||||
0040: 2024-03-31T01:00:00Z unix=1711846800 wall=2024-03-31T01:00:00 gap-until(2024-03-31T03:00:00) type=1 +02 +02 dst
|
||||
0041: 2024-10-27T01:00:00Z unix=1729990800 wall=2024-10-27T01:00:00 fold-until(2024-10-27T03:00:00) type=2 +00 +00
|
||||
0042: 2025-03-30T01:00:00Z unix=1743296400 wall=2025-03-30T01:00:00 gap-until(2025-03-30T03:00:00) type=1 +02 +02 dst
|
||||
0043: 2025-10-26T01:00:00Z unix=1761440400 wall=2025-10-26T01:00:00 fold-until(2025-10-26T03:00:00) type=2 +00 +00
|
||||
0044: 2026-03-29T01:00:00Z unix=1774746000 wall=2026-03-29T01:00:00 gap-until(2026-03-29T03:00:00) type=1 +02 +02 dst
|
||||
0045: 2026-10-25T01:00:00Z unix=1792890000 wall=2026-10-25T01:00:00 fold-until(2026-10-25T03:00:00) type=2 +00 +00
|
||||
0046: 2027-03-28T01:00:00Z unix=1806195600 wall=2027-03-28T01:00:00 gap-until(2027-03-28T03:00:00) type=1 +02 +02 dst
|
||||
0047: 2027-10-31T01:00:00Z unix=1824944400 wall=2027-10-31T01:00:00 fold-until(2027-10-31T03:00:00) type=2 +00 +00
|
||||
0048: 2028-03-26T01:00:00Z unix=1837645200 wall=2028-03-26T01:00:00 gap-until(2028-03-26T03:00:00) type=1 +02 +02 dst
|
||||
0049: 2028-10-29T01:00:00Z unix=1856394000 wall=2028-10-29T01:00:00 fold-until(2028-10-29T03:00:00) type=2 +00 +00
|
||||
0050: 2029-03-25T01:00:00Z unix=1869094800 wall=2029-03-25T01:00:00 gap-until(2029-03-25T03:00:00) type=1 +02 +02 dst
|
||||
0051: 2029-10-28T01:00:00Z unix=1887843600 wall=2029-10-28T01:00:00 fold-until(2029-10-28T03:00:00) type=2 +00 +00
|
||||
0052: 2030-03-31T01:00:00Z unix=1901149200 wall=2030-03-31T01:00:00 gap-until(2030-03-31T03:00:00) type=1 +02 +02 dst
|
||||
0053: 2030-10-27T01:00:00Z unix=1919293200 wall=2030-10-27T01:00:00 fold-until(2030-10-27T03:00:00) type=2 +00 +00
|
||||
0054: 2031-03-30T01:00:00Z unix=1932598800 wall=2031-03-30T01:00:00 gap-until(2031-03-30T03:00:00) type=1 +02 +02 dst
|
||||
0055: 2031-10-26T01:00:00Z unix=1950742800 wall=2031-10-26T01:00:00 fold-until(2031-10-26T03:00:00) type=2 +00 +00
|
||||
0056: 2032-03-28T01:00:00Z unix=1964048400 wall=2032-03-28T01:00:00 gap-until(2032-03-28T03:00:00) type=1 +02 +02 dst
|
||||
0057: 2032-10-31T01:00:00Z unix=1982797200 wall=2032-10-31T01:00:00 fold-until(2032-10-31T03:00:00) type=2 +00 +00
|
||||
0058: 2033-03-27T01:00:00Z unix=1995498000 wall=2033-03-27T01:00:00 gap-until(2033-03-27T03:00:00) type=1 +02 +02 dst
|
||||
0059: 2033-10-30T01:00:00Z unix=2014246800 wall=2033-10-30T01:00:00 fold-until(2033-10-30T03:00:00) type=2 +00 +00
|
||||
0060: 2034-03-26T01:00:00Z unix=2026947600 wall=2034-03-26T01:00:00 gap-until(2034-03-26T03:00:00) type=1 +02 +02 dst
|
||||
0061: 2034-10-29T01:00:00Z unix=2045696400 wall=2034-10-29T01:00:00 fold-until(2034-10-29T03:00:00) type=2 +00 +00
|
||||
0062: 2035-03-25T01:00:00Z unix=2058397200 wall=2035-03-25T01:00:00 gap-until(2035-03-25T03:00:00) type=1 +02 +02 dst
|
||||
0063: 2035-10-28T01:00:00Z unix=2077146000 wall=2035-10-28T01:00:00 fold-until(2035-10-28T03:00:00) type=2 +00 +00
|
||||
0064: 2036-03-30T01:00:00Z unix=2090451600 wall=2036-03-30T01:00:00 gap-until(2036-03-30T03:00:00) type=1 +02 +02 dst
|
||||
0065: 2036-10-26T01:00:00Z unix=2108595600 wall=2036-10-26T01:00:00 fold-until(2036-10-26T03:00:00) type=2 +00 +00
|
||||
0066: 2037-03-29T01:00:00Z unix=2121901200 wall=2037-03-29T01:00:00 gap-until(2037-03-29T03:00:00) type=1 +02 +02 dst
|
||||
0067: 2037-10-25T01:00:00Z unix=2140045200 wall=2037-10-25T01:00:00 fold-until(2037-10-25T03:00:00) type=2 +00 +00
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
Antarctica/Troll
|
||||
LOCAL TIME TYPES
|
||||
000: offset=+00 designation=-00 indicator=local/wall
|
||||
001: offset=+02 designation=+02 dst indicator=ut/std
|
||||
002: offset=+00 designation=+00 indicator=ut/std
|
||||
003: offset=+00 designation=+00 indicator=local/wall
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-02T01:59:59 unambiguous type=0 +00 -00
|
||||
0001: 2005-02-12T00:00:00Z unix=1108166400 wall=2005-02-12T00:00:00 unambiguous type=3 +00 +00
|
||||
0002: 2005-03-27T01:00:00Z unix=1111885200 wall=2005-03-27T01:00:00 gap-until(2005-03-27T03:00:00) type=1 +02 +02 dst
|
||||
0003: 2005-10-30T01:00:00Z unix=1130634000 wall=2005-10-30T01:00:00 fold-until(2005-10-30T03:00:00) type=2 +00 +00
|
||||
0004: 2006-03-26T01:00:00Z unix=1143334800 wall=2006-03-26T01:00:00 gap-until(2006-03-26T03:00:00) type=1 +02 +02 dst
|
||||
0005: 2006-10-29T01:00:00Z unix=1162083600 wall=2006-10-29T01:00:00 fold-until(2006-10-29T03:00:00) type=2 +00 +00
|
||||
0006: 2007-03-25T01:00:00Z unix=1174784400 wall=2007-03-25T01:00:00 gap-until(2007-03-25T03:00:00) type=1 +02 +02 dst
|
||||
0007: 2007-10-28T01:00:00Z unix=1193533200 wall=2007-10-28T01:00:00 fold-until(2007-10-28T03:00:00) type=2 +00 +00
|
||||
0008: 2008-03-30T01:00:00Z unix=1206838800 wall=2008-03-30T01:00:00 gap-until(2008-03-30T03:00:00) type=1 +02 +02 dst
|
||||
0009: 2008-10-26T01:00:00Z unix=1224982800 wall=2008-10-26T01:00:00 fold-until(2008-10-26T03:00:00) type=2 +00 +00
|
||||
0010: 2009-03-29T01:00:00Z unix=1238288400 wall=2009-03-29T01:00:00 gap-until(2009-03-29T03:00:00) type=1 +02 +02 dst
|
||||
0011: 2009-10-25T01:00:00Z unix=1256432400 wall=2009-10-25T01:00:00 fold-until(2009-10-25T03:00:00) type=2 +00 +00
|
||||
0012: 2010-03-28T01:00:00Z unix=1269738000 wall=2010-03-28T01:00:00 gap-until(2010-03-28T03:00:00) type=1 +02 +02 dst
|
||||
0013: 2010-10-31T01:00:00Z unix=1288486800 wall=2010-10-31T01:00:00 fold-until(2010-10-31T03:00:00) type=2 +00 +00
|
||||
0014: 2011-03-27T01:00:00Z unix=1301187600 wall=2011-03-27T01:00:00 gap-until(2011-03-27T03:00:00) type=1 +02 +02 dst
|
||||
0015: 2011-10-30T01:00:00Z unix=1319936400 wall=2011-10-30T01:00:00 fold-until(2011-10-30T03:00:00) type=2 +00 +00
|
||||
0016: 2012-03-25T01:00:00Z unix=1332637200 wall=2012-03-25T01:00:00 gap-until(2012-03-25T03:00:00) type=1 +02 +02 dst
|
||||
0017: 2012-10-28T01:00:00Z unix=1351386000 wall=2012-10-28T01:00:00 fold-until(2012-10-28T03:00:00) type=2 +00 +00
|
||||
0018: 2013-03-31T01:00:00Z unix=1364691600 wall=2013-03-31T01:00:00 gap-until(2013-03-31T03:00:00) type=1 +02 +02 dst
|
||||
0019: 2013-10-27T01:00:00Z unix=1382835600 wall=2013-10-27T01:00:00 fold-until(2013-10-27T03:00:00) type=2 +00 +00
|
||||
0020: 2014-03-30T01:00:00Z unix=1396141200 wall=2014-03-30T01:00:00 gap-until(2014-03-30T03:00:00) type=1 +02 +02 dst
|
||||
0021: 2014-10-26T01:00:00Z unix=1414285200 wall=2014-10-26T01:00:00 fold-until(2014-10-26T03:00:00) type=2 +00 +00
|
||||
0022: 2015-03-29T01:00:00Z unix=1427590800 wall=2015-03-29T01:00:00 gap-until(2015-03-29T03:00:00) type=1 +02 +02 dst
|
||||
0023: 2015-10-25T01:00:00Z unix=1445734800 wall=2015-10-25T01:00:00 fold-until(2015-10-25T03:00:00) type=2 +00 +00
|
||||
0024: 2016-03-27T01:00:00Z unix=1459040400 wall=2016-03-27T01:00:00 gap-until(2016-03-27T03:00:00) type=1 +02 +02 dst
|
||||
0025: 2016-10-30T01:00:00Z unix=1477789200 wall=2016-10-30T01:00:00 fold-until(2016-10-30T03:00:00) type=2 +00 +00
|
||||
0026: 2017-03-26T01:00:00Z unix=1490490000 wall=2017-03-26T01:00:00 gap-until(2017-03-26T03:00:00) type=1 +02 +02 dst
|
||||
0027: 2017-10-29T01:00:00Z unix=1509238800 wall=2017-10-29T01:00:00 fold-until(2017-10-29T03:00:00) type=2 +00 +00
|
||||
0028: 2018-03-25T01:00:00Z unix=1521939600 wall=2018-03-25T01:00:00 gap-until(2018-03-25T03:00:00) type=1 +02 +02 dst
|
||||
0029: 2018-10-28T01:00:00Z unix=1540688400 wall=2018-10-28T01:00:00 fold-until(2018-10-28T03:00:00) type=2 +00 +00
|
||||
0030: 2019-03-31T01:00:00Z unix=1553994000 wall=2019-03-31T01:00:00 gap-until(2019-03-31T03:00:00) type=1 +02 +02 dst
|
||||
0031: 2019-10-27T01:00:00Z unix=1572138000 wall=2019-10-27T01:00:00 fold-until(2019-10-27T03:00:00) type=2 +00 +00
|
||||
0032: 2020-03-29T01:00:00Z unix=1585443600 wall=2020-03-29T01:00:00 gap-until(2020-03-29T03:00:00) type=1 +02 +02 dst
|
||||
0033: 2020-10-25T01:00:00Z unix=1603587600 wall=2020-10-25T01:00:00 fold-until(2020-10-25T03:00:00) type=2 +00 +00
|
||||
0034: 2021-03-28T01:00:00Z unix=1616893200 wall=2021-03-28T01:00:00 gap-until(2021-03-28T03:00:00) type=1 +02 +02 dst
|
||||
0035: 2021-10-31T01:00:00Z unix=1635642000 wall=2021-10-31T01:00:00 fold-until(2021-10-31T03:00:00) type=2 +00 +00
|
||||
0036: 2022-03-27T01:00:00Z unix=1648342800 wall=2022-03-27T01:00:00 gap-until(2022-03-27T03:00:00) type=1 +02 +02 dst
|
||||
0037: 2022-10-30T01:00:00Z unix=1667091600 wall=2022-10-30T01:00:00 fold-until(2022-10-30T03:00:00) type=2 +00 +00
|
||||
0038: 2023-03-26T01:00:00Z unix=1679792400 wall=2023-03-26T01:00:00 gap-until(2023-03-26T03:00:00) type=1 +02 +02 dst
|
||||
0039: 2023-10-29T01:00:00Z unix=1698541200 wall=2023-10-29T01:00:00 fold-until(2023-10-29T03:00:00) type=2 +00 +00
|
||||
0040: 2024-03-31T01:00:00Z unix=1711846800 wall=2024-03-31T01:00:00 gap-until(2024-03-31T03:00:00) type=1 +02 +02 dst
|
||||
0041: 2024-10-27T01:00:00Z unix=1729990800 wall=2024-10-27T01:00:00 fold-until(2024-10-27T03:00:00) type=2 +00 +00
|
||||
0042: 2025-03-30T01:00:00Z unix=1743296400 wall=2025-03-30T01:00:00 gap-until(2025-03-30T03:00:00) type=1 +02 +02 dst
|
||||
0043: 2025-10-26T01:00:00Z unix=1761440400 wall=2025-10-26T01:00:00 fold-until(2025-10-26T03:00:00) type=2 +00 +00
|
||||
0044: 2026-03-29T01:00:00Z unix=1774746000 wall=2026-03-29T01:00:00 gap-until(2026-03-29T03:00:00) type=1 +02 +02 dst
|
||||
0045: 2026-10-25T01:00:00Z unix=1792890000 wall=2026-10-25T01:00:00 fold-until(2026-10-25T03:00:00) type=2 +00 +00
|
||||
0046: 2027-03-28T01:00:00Z unix=1806195600 wall=2027-03-28T01:00:00 gap-until(2027-03-28T03:00:00) type=1 +02 +02 dst
|
||||
0047: 2027-10-31T01:00:00Z unix=1824944400 wall=2027-10-31T01:00:00 fold-until(2027-10-31T03:00:00) type=2 +00 +00
|
||||
0048: 2028-03-26T01:00:00Z unix=1837645200 wall=2028-03-26T01:00:00 gap-until(2028-03-26T03:00:00) type=1 +02 +02 dst
|
||||
0049: 2028-10-29T01:00:00Z unix=1856394000 wall=2028-10-29T01:00:00 fold-until(2028-10-29T03:00:00) type=2 +00 +00
|
||||
0050: 2029-03-25T01:00:00Z unix=1869094800 wall=2029-03-25T01:00:00 gap-until(2029-03-25T03:00:00) type=1 +02 +02 dst
|
||||
0051: 2029-10-28T01:00:00Z unix=1887843600 wall=2029-10-28T01:00:00 fold-until(2029-10-28T03:00:00) type=2 +00 +00
|
||||
0052: 2030-03-31T01:00:00Z unix=1901149200 wall=2030-03-31T01:00:00 gap-until(2030-03-31T03:00:00) type=1 +02 +02 dst
|
||||
0053: 2030-10-27T01:00:00Z unix=1919293200 wall=2030-10-27T01:00:00 fold-until(2030-10-27T03:00:00) type=2 +00 +00
|
||||
0054: 2031-03-30T01:00:00Z unix=1932598800 wall=2031-03-30T01:00:00 gap-until(2031-03-30T03:00:00) type=1 +02 +02 dst
|
||||
0055: 2031-10-26T01:00:00Z unix=1950742800 wall=2031-10-26T01:00:00 fold-until(2031-10-26T03:00:00) type=2 +00 +00
|
||||
0056: 2032-03-28T01:00:00Z unix=1964048400 wall=2032-03-28T01:00:00 gap-until(2032-03-28T03:00:00) type=1 +02 +02 dst
|
||||
0057: 2032-10-31T01:00:00Z unix=1982797200 wall=2032-10-31T01:00:00 fold-until(2032-10-31T03:00:00) type=2 +00 +00
|
||||
0058: 2033-03-27T01:00:00Z unix=1995498000 wall=2033-03-27T01:00:00 gap-until(2033-03-27T03:00:00) type=1 +02 +02 dst
|
||||
0059: 2033-10-30T01:00:00Z unix=2014246800 wall=2033-10-30T01:00:00 fold-until(2033-10-30T03:00:00) type=2 +00 +00
|
||||
0060: 2034-03-26T01:00:00Z unix=2026947600 wall=2034-03-26T01:00:00 gap-until(2034-03-26T03:00:00) type=1 +02 +02 dst
|
||||
0061: 2034-10-29T01:00:00Z unix=2045696400 wall=2034-10-29T01:00:00 fold-until(2034-10-29T03:00:00) type=2 +00 +00
|
||||
0062: 2035-03-25T01:00:00Z unix=2058397200 wall=2035-03-25T01:00:00 gap-until(2035-03-25T03:00:00) type=1 +02 +02 dst
|
||||
0063: 2035-10-28T01:00:00Z unix=2077146000 wall=2035-10-28T01:00:00 fold-until(2035-10-28T03:00:00) type=2 +00 +00
|
||||
0064: 2036-03-30T01:00:00Z unix=2090451600 wall=2036-03-30T01:00:00 gap-until(2036-03-30T03:00:00) type=1 +02 +02 dst
|
||||
0065: 2036-10-26T01:00:00Z unix=2108595600 wall=2036-10-26T01:00:00 fold-until(2036-10-26T03:00:00) type=2 +00 +00
|
||||
0066: 2037-03-29T01:00:00Z unix=2121901200 wall=2037-03-29T01:00:00 gap-until(2037-03-29T03:00:00) type=1 +02 +02 dst
|
||||
0067: 2037-10-25T01:00:00Z unix=2140045200 wall=2037-10-25T01:00:00 fold-until(2037-10-25T03:00:00) type=2 +00 +00
|
||||
POSIX TIME ZONE STRING
|
||||
<+00>0<+02>-2,M3.5.0/1,M10.5.0/3
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse_v1())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
Australia/Tasmania
|
||||
LOCAL TIME TYPES
|
||||
000: offset=+09:49:16 designation=LMT indicator=local/wall
|
||||
001: offset=+11 designation=AEDT dst indicator=local/std
|
||||
002: offset=+10 designation=AEST indicator=local/std
|
||||
003: offset=+10 designation=AEST indicator=local/wall
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-02T11:49:15 unambiguous type=0 +09:49:16 LMT
|
||||
0001: 1901-12-13T20:45:52Z unix=-2147483648 wall=1901-12-14T06:35:08 gap-until(1901-12-14T06:45:52) type=3 +10 AEST
|
||||
0002: 1916-09-30T16:00:00Z unix=-1680508800 wall=1916-10-01T02:00:00 gap-until(1916-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0003: 1917-03-24T16:00:00Z unix=-1665388800 wall=1917-03-25T02:00:00 fold-until(1917-03-25T03:00:00) type=2 +10 AEST
|
||||
0004: 1917-10-27T16:00:00Z unix=-1646640000 wall=1917-10-28T02:00:00 gap-until(1917-10-28T03:00:00) type=1 +11 AEDT dst
|
||||
0005: 1918-03-02T16:00:00Z unix=-1635753600 wall=1918-03-03T02:00:00 fold-until(1918-03-03T03:00:00) type=2 +10 AEST
|
||||
0006: 1918-10-26T16:00:00Z unix=-1615190400 wall=1918-10-27T02:00:00 gap-until(1918-10-27T03:00:00) type=1 +11 AEDT dst
|
||||
0007: 1919-03-01T16:00:00Z unix=-1604304000 wall=1919-03-02T02:00:00 fold-until(1919-03-02T03:00:00) type=2 +10 AEST
|
||||
0008: 1941-12-31T16:00:00Z unix=-883641600 wall=1942-01-01T02:00:00 gap-until(1942-01-01T03:00:00) type=1 +11 AEDT dst
|
||||
0009: 1942-03-28T16:00:00Z unix=-876124800 wall=1942-03-29T02:00:00 fold-until(1942-03-29T03:00:00) type=2 +10 AEST
|
||||
0010: 1942-09-26T16:00:00Z unix=-860400000 wall=1942-09-27T02:00:00 gap-until(1942-09-27T03:00:00) type=1 +11 AEDT dst
|
||||
0011: 1943-03-27T16:00:00Z unix=-844675200 wall=1943-03-28T02:00:00 fold-until(1943-03-28T03:00:00) type=2 +10 AEST
|
||||
0012: 1943-10-02T16:00:00Z unix=-828345600 wall=1943-10-03T02:00:00 gap-until(1943-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0013: 1944-03-25T16:00:00Z unix=-813225600 wall=1944-03-26T02:00:00 fold-until(1944-03-26T03:00:00) type=2 +10 AEST
|
||||
0014: 1967-09-30T16:00:00Z unix=-71136000 wall=1967-10-01T02:00:00 gap-until(1967-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0015: 1968-03-30T16:00:00Z unix=-55411200 wall=1968-03-31T02:00:00 fold-until(1968-03-31T03:00:00) type=2 +10 AEST
|
||||
0016: 1968-10-26T16:00:00Z unix=-37267200 wall=1968-10-27T02:00:00 gap-until(1968-10-27T03:00:00) type=1 +11 AEDT dst
|
||||
0017: 1969-03-08T16:00:00Z unix=-25776000 wall=1969-03-09T02:00:00 fold-until(1969-03-09T03:00:00) type=2 +10 AEST
|
||||
0018: 1969-10-25T16:00:00Z unix=-5817600 wall=1969-10-26T02:00:00 gap-until(1969-10-26T03:00:00) type=1 +11 AEDT dst
|
||||
0019: 1970-03-07T16:00:00Z unix=5673600 wall=1970-03-08T02:00:00 fold-until(1970-03-08T03:00:00) type=2 +10 AEST
|
||||
0020: 1970-10-24T16:00:00Z unix=25632000 wall=1970-10-25T02:00:00 gap-until(1970-10-25T03:00:00) type=1 +11 AEDT dst
|
||||
0021: 1971-03-13T16:00:00Z unix=37728000 wall=1971-03-14T02:00:00 fold-until(1971-03-14T03:00:00) type=2 +10 AEST
|
||||
0022: 1971-10-30T16:00:00Z unix=57686400 wall=1971-10-31T02:00:00 gap-until(1971-10-31T03:00:00) type=1 +11 AEDT dst
|
||||
0023: 1972-02-26T16:00:00Z unix=67968000 wall=1972-02-27T02:00:00 fold-until(1972-02-27T03:00:00) type=2 +10 AEST
|
||||
0024: 1972-10-28T16:00:00Z unix=89136000 wall=1972-10-29T02:00:00 gap-until(1972-10-29T03:00:00) type=1 +11 AEDT dst
|
||||
0025: 1973-03-03T16:00:00Z unix=100022400 wall=1973-03-04T02:00:00 fold-until(1973-03-04T03:00:00) type=2 +10 AEST
|
||||
0026: 1973-10-27T16:00:00Z unix=120585600 wall=1973-10-28T02:00:00 gap-until(1973-10-28T03:00:00) type=1 +11 AEDT dst
|
||||
0027: 1974-03-02T16:00:00Z unix=131472000 wall=1974-03-03T02:00:00 fold-until(1974-03-03T03:00:00) type=2 +10 AEST
|
||||
0028: 1974-10-26T16:00:00Z unix=152035200 wall=1974-10-27T02:00:00 gap-until(1974-10-27T03:00:00) type=1 +11 AEDT dst
|
||||
0029: 1975-03-01T16:00:00Z unix=162921600 wall=1975-03-02T02:00:00 fold-until(1975-03-02T03:00:00) type=2 +10 AEST
|
||||
0030: 1975-10-25T16:00:00Z unix=183484800 wall=1975-10-26T02:00:00 gap-until(1975-10-26T03:00:00) type=1 +11 AEDT dst
|
||||
0031: 1976-03-06T16:00:00Z unix=194976000 wall=1976-03-07T02:00:00 fold-until(1976-03-07T03:00:00) type=2 +10 AEST
|
||||
0032: 1976-10-30T16:00:00Z unix=215539200 wall=1976-10-31T02:00:00 gap-until(1976-10-31T03:00:00) type=1 +11 AEDT dst
|
||||
0033: 1977-03-05T16:00:00Z unix=226425600 wall=1977-03-06T02:00:00 fold-until(1977-03-06T03:00:00) type=2 +10 AEST
|
||||
0034: 1977-10-29T16:00:00Z unix=246988800 wall=1977-10-30T02:00:00 gap-until(1977-10-30T03:00:00) type=1 +11 AEDT dst
|
||||
0035: 1978-03-04T16:00:00Z unix=257875200 wall=1978-03-05T02:00:00 fold-until(1978-03-05T03:00:00) type=2 +10 AEST
|
||||
0036: 1978-10-28T16:00:00Z unix=278438400 wall=1978-10-29T02:00:00 gap-until(1978-10-29T03:00:00) type=1 +11 AEDT dst
|
||||
0037: 1979-03-03T16:00:00Z unix=289324800 wall=1979-03-04T02:00:00 fold-until(1979-03-04T03:00:00) type=2 +10 AEST
|
||||
0038: 1979-10-27T16:00:00Z unix=309888000 wall=1979-10-28T02:00:00 gap-until(1979-10-28T03:00:00) type=1 +11 AEDT dst
|
||||
0039: 1980-03-01T16:00:00Z unix=320774400 wall=1980-03-02T02:00:00 fold-until(1980-03-02T03:00:00) type=2 +10 AEST
|
||||
0040: 1980-10-25T16:00:00Z unix=341337600 wall=1980-10-26T02:00:00 gap-until(1980-10-26T03:00:00) type=1 +11 AEDT dst
|
||||
0041: 1981-02-28T16:00:00Z unix=352224000 wall=1981-03-01T02:00:00 fold-until(1981-03-01T03:00:00) type=2 +10 AEST
|
||||
0042: 1981-10-24T16:00:00Z unix=372787200 wall=1981-10-25T02:00:00 gap-until(1981-10-25T03:00:00) type=1 +11 AEDT dst
|
||||
0043: 1982-03-27T16:00:00Z unix=386092800 wall=1982-03-28T02:00:00 fold-until(1982-03-28T03:00:00) type=2 +10 AEST
|
||||
0044: 1982-10-30T16:00:00Z unix=404841600 wall=1982-10-31T02:00:00 gap-until(1982-10-31T03:00:00) type=1 +11 AEDT dst
|
||||
0045: 1983-03-26T16:00:00Z unix=417542400 wall=1983-03-27T02:00:00 fold-until(1983-03-27T03:00:00) type=2 +10 AEST
|
||||
0046: 1983-10-29T16:00:00Z unix=436291200 wall=1983-10-30T02:00:00 gap-until(1983-10-30T03:00:00) type=1 +11 AEDT dst
|
||||
0047: 1984-03-03T16:00:00Z unix=447177600 wall=1984-03-04T02:00:00 fold-until(1984-03-04T03:00:00) type=2 +10 AEST
|
||||
0048: 1984-10-27T16:00:00Z unix=467740800 wall=1984-10-28T02:00:00 gap-until(1984-10-28T03:00:00) type=1 +11 AEDT dst
|
||||
0049: 1985-03-02T16:00:00Z unix=478627200 wall=1985-03-03T02:00:00 fold-until(1985-03-03T03:00:00) type=2 +10 AEST
|
||||
0050: 1985-10-26T16:00:00Z unix=499190400 wall=1985-10-27T02:00:00 gap-until(1985-10-27T03:00:00) type=1 +11 AEDT dst
|
||||
0051: 1986-03-01T16:00:00Z unix=510076800 wall=1986-03-02T02:00:00 fold-until(1986-03-02T03:00:00) type=2 +10 AEST
|
||||
0052: 1986-10-18T16:00:00Z unix=530035200 wall=1986-10-19T02:00:00 gap-until(1986-10-19T03:00:00) type=1 +11 AEDT dst
|
||||
0053: 1987-03-14T16:00:00Z unix=542736000 wall=1987-03-15T02:00:00 fold-until(1987-03-15T03:00:00) type=2 +10 AEST
|
||||
0054: 1987-10-24T16:00:00Z unix=562089600 wall=1987-10-25T02:00:00 gap-until(1987-10-25T03:00:00) type=1 +11 AEDT dst
|
||||
0055: 1988-03-19T16:00:00Z unix=574790400 wall=1988-03-20T02:00:00 fold-until(1988-03-20T03:00:00) type=2 +10 AEST
|
||||
0056: 1988-10-29T16:00:00Z unix=594144000 wall=1988-10-30T02:00:00 gap-until(1988-10-30T03:00:00) type=1 +11 AEDT dst
|
||||
0057: 1989-03-18T16:00:00Z unix=606240000 wall=1989-03-19T02:00:00 fold-until(1989-03-19T03:00:00) type=2 +10 AEST
|
||||
0058: 1989-10-28T16:00:00Z unix=625593600 wall=1989-10-29T02:00:00 gap-until(1989-10-29T03:00:00) type=1 +11 AEDT dst
|
||||
0059: 1990-03-17T16:00:00Z unix=637689600 wall=1990-03-18T02:00:00 fold-until(1990-03-18T03:00:00) type=2 +10 AEST
|
||||
0060: 1990-10-27T16:00:00Z unix=657043200 wall=1990-10-28T02:00:00 gap-until(1990-10-28T03:00:00) type=1 +11 AEDT dst
|
||||
0061: 1991-03-30T16:00:00Z unix=670348800 wall=1991-03-31T02:00:00 fold-until(1991-03-31T03:00:00) type=2 +10 AEST
|
||||
0062: 1991-10-05T16:00:00Z unix=686678400 wall=1991-10-06T02:00:00 gap-until(1991-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0063: 1992-03-28T16:00:00Z unix=701798400 wall=1992-03-29T02:00:00 fold-until(1992-03-29T03:00:00) type=2 +10 AEST
|
||||
0064: 1992-10-03T16:00:00Z unix=718128000 wall=1992-10-04T02:00:00 gap-until(1992-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
0065: 1993-03-27T16:00:00Z unix=733248000 wall=1993-03-28T02:00:00 fold-until(1993-03-28T03:00:00) type=2 +10 AEST
|
||||
0066: 1993-10-02T16:00:00Z unix=749577600 wall=1993-10-03T02:00:00 gap-until(1993-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0067: 1994-03-26T16:00:00Z unix=764697600 wall=1994-03-27T02:00:00 fold-until(1994-03-27T03:00:00) type=2 +10 AEST
|
||||
0068: 1994-10-01T16:00:00Z unix=781027200 wall=1994-10-02T02:00:00 gap-until(1994-10-02T03:00:00) type=1 +11 AEDT dst
|
||||
0069: 1995-03-25T16:00:00Z unix=796147200 wall=1995-03-26T02:00:00 fold-until(1995-03-26T03:00:00) type=2 +10 AEST
|
||||
0070: 1995-09-30T16:00:00Z unix=812476800 wall=1995-10-01T02:00:00 gap-until(1995-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0071: 1996-03-30T16:00:00Z unix=828201600 wall=1996-03-31T02:00:00 fold-until(1996-03-31T03:00:00) type=2 +10 AEST
|
||||
0072: 1996-10-05T16:00:00Z unix=844531200 wall=1996-10-06T02:00:00 gap-until(1996-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0073: 1997-03-29T16:00:00Z unix=859651200 wall=1997-03-30T02:00:00 fold-until(1997-03-30T03:00:00) type=2 +10 AEST
|
||||
0074: 1997-10-04T16:00:00Z unix=875980800 wall=1997-10-05T02:00:00 gap-until(1997-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0075: 1998-03-28T16:00:00Z unix=891100800 wall=1998-03-29T02:00:00 fold-until(1998-03-29T03:00:00) type=2 +10 AEST
|
||||
0076: 1998-10-03T16:00:00Z unix=907430400 wall=1998-10-04T02:00:00 gap-until(1998-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
0077: 1999-03-27T16:00:00Z unix=922550400 wall=1999-03-28T02:00:00 fold-until(1999-03-28T03:00:00) type=2 +10 AEST
|
||||
0078: 1999-10-02T16:00:00Z unix=938880000 wall=1999-10-03T02:00:00 gap-until(1999-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0079: 2000-03-25T16:00:00Z unix=954000000 wall=2000-03-26T02:00:00 fold-until(2000-03-26T03:00:00) type=2 +10 AEST
|
||||
0080: 2000-08-26T16:00:00Z unix=967305600 wall=2000-08-27T02:00:00 gap-until(2000-08-27T03:00:00) type=1 +11 AEDT dst
|
||||
0081: 2001-03-24T16:00:00Z unix=985449600 wall=2001-03-25T02:00:00 fold-until(2001-03-25T03:00:00) type=2 +10 AEST
|
||||
0082: 2001-10-06T16:00:00Z unix=1002384000 wall=2001-10-07T02:00:00 gap-until(2001-10-07T03:00:00) type=1 +11 AEDT dst
|
||||
0083: 2002-03-30T16:00:00Z unix=1017504000 wall=2002-03-31T02:00:00 fold-until(2002-03-31T03:00:00) type=2 +10 AEST
|
||||
0084: 2002-10-05T16:00:00Z unix=1033833600 wall=2002-10-06T02:00:00 gap-until(2002-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0085: 2003-03-29T16:00:00Z unix=1048953600 wall=2003-03-30T02:00:00 fold-until(2003-03-30T03:00:00) type=2 +10 AEST
|
||||
0086: 2003-10-04T16:00:00Z unix=1065283200 wall=2003-10-05T02:00:00 gap-until(2003-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0087: 2004-03-27T16:00:00Z unix=1080403200 wall=2004-03-28T02:00:00 fold-until(2004-03-28T03:00:00) type=2 +10 AEST
|
||||
0088: 2004-10-02T16:00:00Z unix=1096732800 wall=2004-10-03T02:00:00 gap-until(2004-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0089: 2005-03-26T16:00:00Z unix=1111852800 wall=2005-03-27T02:00:00 fold-until(2005-03-27T03:00:00) type=2 +10 AEST
|
||||
0090: 2005-10-01T16:00:00Z unix=1128182400 wall=2005-10-02T02:00:00 gap-until(2005-10-02T03:00:00) type=1 +11 AEDT dst
|
||||
0091: 2006-04-01T16:00:00Z unix=1143907200 wall=2006-04-02T02:00:00 fold-until(2006-04-02T03:00:00) type=2 +10 AEST
|
||||
0092: 2006-09-30T16:00:00Z unix=1159632000 wall=2006-10-01T02:00:00 gap-until(2006-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0093: 2007-03-24T16:00:00Z unix=1174752000 wall=2007-03-25T02:00:00 fold-until(2007-03-25T03:00:00) type=2 +10 AEST
|
||||
0094: 2007-10-06T16:00:00Z unix=1191686400 wall=2007-10-07T02:00:00 gap-until(2007-10-07T03:00:00) type=1 +11 AEDT dst
|
||||
0095: 2008-04-05T16:00:00Z unix=1207411200 wall=2008-04-06T02:00:00 fold-until(2008-04-06T03:00:00) type=2 +10 AEST
|
||||
0096: 2008-10-04T16:00:00Z unix=1223136000 wall=2008-10-05T02:00:00 gap-until(2008-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0097: 2009-04-04T16:00:00Z unix=1238860800 wall=2009-04-05T02:00:00 fold-until(2009-04-05T03:00:00) type=2 +10 AEST
|
||||
0098: 2009-10-03T16:00:00Z unix=1254585600 wall=2009-10-04T02:00:00 gap-until(2009-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
0099: 2010-04-03T16:00:00Z unix=1270310400 wall=2010-04-04T02:00:00 fold-until(2010-04-04T03:00:00) type=2 +10 AEST
|
||||
0100: 2010-10-02T16:00:00Z unix=1286035200 wall=2010-10-03T02:00:00 gap-until(2010-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0101: 2011-04-02T16:00:00Z unix=1301760000 wall=2011-04-03T02:00:00 fold-until(2011-04-03T03:00:00) type=2 +10 AEST
|
||||
0102: 2011-10-01T16:00:00Z unix=1317484800 wall=2011-10-02T02:00:00 gap-until(2011-10-02T03:00:00) type=1 +11 AEDT dst
|
||||
0103: 2012-03-31T16:00:00Z unix=1333209600 wall=2012-04-01T02:00:00 fold-until(2012-04-01T03:00:00) type=2 +10 AEST
|
||||
0104: 2012-10-06T16:00:00Z unix=1349539200 wall=2012-10-07T02:00:00 gap-until(2012-10-07T03:00:00) type=1 +11 AEDT dst
|
||||
0105: 2013-04-06T16:00:00Z unix=1365264000 wall=2013-04-07T02:00:00 fold-until(2013-04-07T03:00:00) type=2 +10 AEST
|
||||
0106: 2013-10-05T16:00:00Z unix=1380988800 wall=2013-10-06T02:00:00 gap-until(2013-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0107: 2014-04-05T16:00:00Z unix=1396713600 wall=2014-04-06T02:00:00 fold-until(2014-04-06T03:00:00) type=2 +10 AEST
|
||||
0108: 2014-10-04T16:00:00Z unix=1412438400 wall=2014-10-05T02:00:00 gap-until(2014-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0109: 2015-04-04T16:00:00Z unix=1428163200 wall=2015-04-05T02:00:00 fold-until(2015-04-05T03:00:00) type=2 +10 AEST
|
||||
0110: 2015-10-03T16:00:00Z unix=1443888000 wall=2015-10-04T02:00:00 gap-until(2015-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
0111: 2016-04-02T16:00:00Z unix=1459612800 wall=2016-04-03T02:00:00 fold-until(2016-04-03T03:00:00) type=2 +10 AEST
|
||||
0112: 2016-10-01T16:00:00Z unix=1475337600 wall=2016-10-02T02:00:00 gap-until(2016-10-02T03:00:00) type=1 +11 AEDT dst
|
||||
0113: 2017-04-01T16:00:00Z unix=1491062400 wall=2017-04-02T02:00:00 fold-until(2017-04-02T03:00:00) type=2 +10 AEST
|
||||
0114: 2017-09-30T16:00:00Z unix=1506787200 wall=2017-10-01T02:00:00 gap-until(2017-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0115: 2018-03-31T16:00:00Z unix=1522512000 wall=2018-04-01T02:00:00 fold-until(2018-04-01T03:00:00) type=2 +10 AEST
|
||||
0116: 2018-10-06T16:00:00Z unix=1538841600 wall=2018-10-07T02:00:00 gap-until(2018-10-07T03:00:00) type=1 +11 AEDT dst
|
||||
0117: 2019-04-06T16:00:00Z unix=1554566400 wall=2019-04-07T02:00:00 fold-until(2019-04-07T03:00:00) type=2 +10 AEST
|
||||
0118: 2019-10-05T16:00:00Z unix=1570291200 wall=2019-10-06T02:00:00 gap-until(2019-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0119: 2020-04-04T16:00:00Z unix=1586016000 wall=2020-04-05T02:00:00 fold-until(2020-04-05T03:00:00) type=2 +10 AEST
|
||||
0120: 2020-10-03T16:00:00Z unix=1601740800 wall=2020-10-04T02:00:00 gap-until(2020-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
0121: 2021-04-03T16:00:00Z unix=1617465600 wall=2021-04-04T02:00:00 fold-until(2021-04-04T03:00:00) type=2 +10 AEST
|
||||
0122: 2021-10-02T16:00:00Z unix=1633190400 wall=2021-10-03T02:00:00 gap-until(2021-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0123: 2022-04-02T16:00:00Z unix=1648915200 wall=2022-04-03T02:00:00 fold-until(2022-04-03T03:00:00) type=2 +10 AEST
|
||||
0124: 2022-10-01T16:00:00Z unix=1664640000 wall=2022-10-02T02:00:00 gap-until(2022-10-02T03:00:00) type=1 +11 AEDT dst
|
||||
0125: 2023-04-01T16:00:00Z unix=1680364800 wall=2023-04-02T02:00:00 fold-until(2023-04-02T03:00:00) type=2 +10 AEST
|
||||
0126: 2023-09-30T16:00:00Z unix=1696089600 wall=2023-10-01T02:00:00 gap-until(2023-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0127: 2024-04-06T16:00:00Z unix=1712419200 wall=2024-04-07T02:00:00 fold-until(2024-04-07T03:00:00) type=2 +10 AEST
|
||||
0128: 2024-10-05T16:00:00Z unix=1728144000 wall=2024-10-06T02:00:00 gap-until(2024-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0129: 2025-04-05T16:00:00Z unix=1743868800 wall=2025-04-06T02:00:00 fold-until(2025-04-06T03:00:00) type=2 +10 AEST
|
||||
0130: 2025-10-04T16:00:00Z unix=1759593600 wall=2025-10-05T02:00:00 gap-until(2025-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0131: 2026-04-04T16:00:00Z unix=1775318400 wall=2026-04-05T02:00:00 fold-until(2026-04-05T03:00:00) type=2 +10 AEST
|
||||
0132: 2026-10-03T16:00:00Z unix=1791043200 wall=2026-10-04T02:00:00 gap-until(2026-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
0133: 2027-04-03T16:00:00Z unix=1806768000 wall=2027-04-04T02:00:00 fold-until(2027-04-04T03:00:00) type=2 +10 AEST
|
||||
0134: 2027-10-02T16:00:00Z unix=1822492800 wall=2027-10-03T02:00:00 gap-until(2027-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0135: 2028-04-01T16:00:00Z unix=1838217600 wall=2028-04-02T02:00:00 fold-until(2028-04-02T03:00:00) type=2 +10 AEST
|
||||
0136: 2028-09-30T16:00:00Z unix=1853942400 wall=2028-10-01T02:00:00 gap-until(2028-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0137: 2029-03-31T16:00:00Z unix=1869667200 wall=2029-04-01T02:00:00 fold-until(2029-04-01T03:00:00) type=2 +10 AEST
|
||||
0138: 2029-10-06T16:00:00Z unix=1885996800 wall=2029-10-07T02:00:00 gap-until(2029-10-07T03:00:00) type=1 +11 AEDT dst
|
||||
0139: 2030-04-06T16:00:00Z unix=1901721600 wall=2030-04-07T02:00:00 fold-until(2030-04-07T03:00:00) type=2 +10 AEST
|
||||
0140: 2030-10-05T16:00:00Z unix=1917446400 wall=2030-10-06T02:00:00 gap-until(2030-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0141: 2031-04-05T16:00:00Z unix=1933171200 wall=2031-04-06T02:00:00 fold-until(2031-04-06T03:00:00) type=2 +10 AEST
|
||||
0142: 2031-10-04T16:00:00Z unix=1948896000 wall=2031-10-05T02:00:00 gap-until(2031-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0143: 2032-04-03T16:00:00Z unix=1964620800 wall=2032-04-04T02:00:00 fold-until(2032-04-04T03:00:00) type=2 +10 AEST
|
||||
0144: 2032-10-02T16:00:00Z unix=1980345600 wall=2032-10-03T02:00:00 gap-until(2032-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0145: 2033-04-02T16:00:00Z unix=1996070400 wall=2033-04-03T02:00:00 fold-until(2033-04-03T03:00:00) type=2 +10 AEST
|
||||
0146: 2033-10-01T16:00:00Z unix=2011795200 wall=2033-10-02T02:00:00 gap-until(2033-10-02T03:00:00) type=1 +11 AEDT dst
|
||||
0147: 2034-04-01T16:00:00Z unix=2027520000 wall=2034-04-02T02:00:00 fold-until(2034-04-02T03:00:00) type=2 +10 AEST
|
||||
0148: 2034-09-30T16:00:00Z unix=2043244800 wall=2034-10-01T02:00:00 gap-until(2034-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0149: 2035-03-31T16:00:00Z unix=2058969600 wall=2035-04-01T02:00:00 fold-until(2035-04-01T03:00:00) type=2 +10 AEST
|
||||
0150: 2035-10-06T16:00:00Z unix=2075299200 wall=2035-10-07T02:00:00 gap-until(2035-10-07T03:00:00) type=1 +11 AEDT dst
|
||||
0151: 2036-04-05T16:00:00Z unix=2091024000 wall=2036-04-06T02:00:00 fold-until(2036-04-06T03:00:00) type=2 +10 AEST
|
||||
0152: 2036-10-04T16:00:00Z unix=2106748800 wall=2036-10-05T02:00:00 gap-until(2036-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0153: 2037-04-04T16:00:00Z unix=2122473600 wall=2037-04-05T02:00:00 fold-until(2037-04-05T03:00:00) type=2 +10 AEST
|
||||
0154: 2037-10-03T16:00:00Z unix=2138198400 wall=2037-10-04T02:00:00 gap-until(2037-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
Australia/Tasmania
|
||||
LOCAL TIME TYPES
|
||||
000: offset=+09:49:16 designation=LMT indicator=local/wall
|
||||
001: offset=+11 designation=AEDT dst indicator=local/std
|
||||
002: offset=+10 designation=AEST indicator=local/std
|
||||
003: offset=+10 designation=AEST indicator=local/wall
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-02T11:49:15 unambiguous type=0 +09:49:16 LMT
|
||||
0001: 1895-08-31T14:10:44Z unix=-2345795356 wall=1895-09-01T00:00:00 gap-until(1895-09-01T00:10:44) type=3 +10 AEST
|
||||
0002: 1916-09-30T16:00:00Z unix=-1680508800 wall=1916-10-01T02:00:00 gap-until(1916-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0003: 1917-03-24T16:00:00Z unix=-1665388800 wall=1917-03-25T02:00:00 fold-until(1917-03-25T03:00:00) type=2 +10 AEST
|
||||
0004: 1917-10-27T16:00:00Z unix=-1646640000 wall=1917-10-28T02:00:00 gap-until(1917-10-28T03:00:00) type=1 +11 AEDT dst
|
||||
0005: 1918-03-02T16:00:00Z unix=-1635753600 wall=1918-03-03T02:00:00 fold-until(1918-03-03T03:00:00) type=2 +10 AEST
|
||||
0006: 1918-10-26T16:00:00Z unix=-1615190400 wall=1918-10-27T02:00:00 gap-until(1918-10-27T03:00:00) type=1 +11 AEDT dst
|
||||
0007: 1919-03-01T16:00:00Z unix=-1604304000 wall=1919-03-02T02:00:00 fold-until(1919-03-02T03:00:00) type=2 +10 AEST
|
||||
0008: 1941-12-31T16:00:00Z unix=-883641600 wall=1942-01-01T02:00:00 gap-until(1942-01-01T03:00:00) type=1 +11 AEDT dst
|
||||
0009: 1942-03-28T16:00:00Z unix=-876124800 wall=1942-03-29T02:00:00 fold-until(1942-03-29T03:00:00) type=2 +10 AEST
|
||||
0010: 1942-09-26T16:00:00Z unix=-860400000 wall=1942-09-27T02:00:00 gap-until(1942-09-27T03:00:00) type=1 +11 AEDT dst
|
||||
0011: 1943-03-27T16:00:00Z unix=-844675200 wall=1943-03-28T02:00:00 fold-until(1943-03-28T03:00:00) type=2 +10 AEST
|
||||
0012: 1943-10-02T16:00:00Z unix=-828345600 wall=1943-10-03T02:00:00 gap-until(1943-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0013: 1944-03-25T16:00:00Z unix=-813225600 wall=1944-03-26T02:00:00 fold-until(1944-03-26T03:00:00) type=2 +10 AEST
|
||||
0014: 1967-09-30T16:00:00Z unix=-71136000 wall=1967-10-01T02:00:00 gap-until(1967-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0015: 1968-03-30T16:00:00Z unix=-55411200 wall=1968-03-31T02:00:00 fold-until(1968-03-31T03:00:00) type=2 +10 AEST
|
||||
0016: 1968-10-26T16:00:00Z unix=-37267200 wall=1968-10-27T02:00:00 gap-until(1968-10-27T03:00:00) type=1 +11 AEDT dst
|
||||
0017: 1969-03-08T16:00:00Z unix=-25776000 wall=1969-03-09T02:00:00 fold-until(1969-03-09T03:00:00) type=2 +10 AEST
|
||||
0018: 1969-10-25T16:00:00Z unix=-5817600 wall=1969-10-26T02:00:00 gap-until(1969-10-26T03:00:00) type=1 +11 AEDT dst
|
||||
0019: 1970-03-07T16:00:00Z unix=5673600 wall=1970-03-08T02:00:00 fold-until(1970-03-08T03:00:00) type=2 +10 AEST
|
||||
0020: 1970-10-24T16:00:00Z unix=25632000 wall=1970-10-25T02:00:00 gap-until(1970-10-25T03:00:00) type=1 +11 AEDT dst
|
||||
0021: 1971-03-13T16:00:00Z unix=37728000 wall=1971-03-14T02:00:00 fold-until(1971-03-14T03:00:00) type=2 +10 AEST
|
||||
0022: 1971-10-30T16:00:00Z unix=57686400 wall=1971-10-31T02:00:00 gap-until(1971-10-31T03:00:00) type=1 +11 AEDT dst
|
||||
0023: 1972-02-26T16:00:00Z unix=67968000 wall=1972-02-27T02:00:00 fold-until(1972-02-27T03:00:00) type=2 +10 AEST
|
||||
0024: 1972-10-28T16:00:00Z unix=89136000 wall=1972-10-29T02:00:00 gap-until(1972-10-29T03:00:00) type=1 +11 AEDT dst
|
||||
0025: 1973-03-03T16:00:00Z unix=100022400 wall=1973-03-04T02:00:00 fold-until(1973-03-04T03:00:00) type=2 +10 AEST
|
||||
0026: 1973-10-27T16:00:00Z unix=120585600 wall=1973-10-28T02:00:00 gap-until(1973-10-28T03:00:00) type=1 +11 AEDT dst
|
||||
0027: 1974-03-02T16:00:00Z unix=131472000 wall=1974-03-03T02:00:00 fold-until(1974-03-03T03:00:00) type=2 +10 AEST
|
||||
0028: 1974-10-26T16:00:00Z unix=152035200 wall=1974-10-27T02:00:00 gap-until(1974-10-27T03:00:00) type=1 +11 AEDT dst
|
||||
0029: 1975-03-01T16:00:00Z unix=162921600 wall=1975-03-02T02:00:00 fold-until(1975-03-02T03:00:00) type=2 +10 AEST
|
||||
0030: 1975-10-25T16:00:00Z unix=183484800 wall=1975-10-26T02:00:00 gap-until(1975-10-26T03:00:00) type=1 +11 AEDT dst
|
||||
0031: 1976-03-06T16:00:00Z unix=194976000 wall=1976-03-07T02:00:00 fold-until(1976-03-07T03:00:00) type=2 +10 AEST
|
||||
0032: 1976-10-30T16:00:00Z unix=215539200 wall=1976-10-31T02:00:00 gap-until(1976-10-31T03:00:00) type=1 +11 AEDT dst
|
||||
0033: 1977-03-05T16:00:00Z unix=226425600 wall=1977-03-06T02:00:00 fold-until(1977-03-06T03:00:00) type=2 +10 AEST
|
||||
0034: 1977-10-29T16:00:00Z unix=246988800 wall=1977-10-30T02:00:00 gap-until(1977-10-30T03:00:00) type=1 +11 AEDT dst
|
||||
0035: 1978-03-04T16:00:00Z unix=257875200 wall=1978-03-05T02:00:00 fold-until(1978-03-05T03:00:00) type=2 +10 AEST
|
||||
0036: 1978-10-28T16:00:00Z unix=278438400 wall=1978-10-29T02:00:00 gap-until(1978-10-29T03:00:00) type=1 +11 AEDT dst
|
||||
0037: 1979-03-03T16:00:00Z unix=289324800 wall=1979-03-04T02:00:00 fold-until(1979-03-04T03:00:00) type=2 +10 AEST
|
||||
0038: 1979-10-27T16:00:00Z unix=309888000 wall=1979-10-28T02:00:00 gap-until(1979-10-28T03:00:00) type=1 +11 AEDT dst
|
||||
0039: 1980-03-01T16:00:00Z unix=320774400 wall=1980-03-02T02:00:00 fold-until(1980-03-02T03:00:00) type=2 +10 AEST
|
||||
0040: 1980-10-25T16:00:00Z unix=341337600 wall=1980-10-26T02:00:00 gap-until(1980-10-26T03:00:00) type=1 +11 AEDT dst
|
||||
0041: 1981-02-28T16:00:00Z unix=352224000 wall=1981-03-01T02:00:00 fold-until(1981-03-01T03:00:00) type=2 +10 AEST
|
||||
0042: 1981-10-24T16:00:00Z unix=372787200 wall=1981-10-25T02:00:00 gap-until(1981-10-25T03:00:00) type=1 +11 AEDT dst
|
||||
0043: 1982-03-27T16:00:00Z unix=386092800 wall=1982-03-28T02:00:00 fold-until(1982-03-28T03:00:00) type=2 +10 AEST
|
||||
0044: 1982-10-30T16:00:00Z unix=404841600 wall=1982-10-31T02:00:00 gap-until(1982-10-31T03:00:00) type=1 +11 AEDT dst
|
||||
0045: 1983-03-26T16:00:00Z unix=417542400 wall=1983-03-27T02:00:00 fold-until(1983-03-27T03:00:00) type=2 +10 AEST
|
||||
0046: 1983-10-29T16:00:00Z unix=436291200 wall=1983-10-30T02:00:00 gap-until(1983-10-30T03:00:00) type=1 +11 AEDT dst
|
||||
0047: 1984-03-03T16:00:00Z unix=447177600 wall=1984-03-04T02:00:00 fold-until(1984-03-04T03:00:00) type=2 +10 AEST
|
||||
0048: 1984-10-27T16:00:00Z unix=467740800 wall=1984-10-28T02:00:00 gap-until(1984-10-28T03:00:00) type=1 +11 AEDT dst
|
||||
0049: 1985-03-02T16:00:00Z unix=478627200 wall=1985-03-03T02:00:00 fold-until(1985-03-03T03:00:00) type=2 +10 AEST
|
||||
0050: 1985-10-26T16:00:00Z unix=499190400 wall=1985-10-27T02:00:00 gap-until(1985-10-27T03:00:00) type=1 +11 AEDT dst
|
||||
0051: 1986-03-01T16:00:00Z unix=510076800 wall=1986-03-02T02:00:00 fold-until(1986-03-02T03:00:00) type=2 +10 AEST
|
||||
0052: 1986-10-18T16:00:00Z unix=530035200 wall=1986-10-19T02:00:00 gap-until(1986-10-19T03:00:00) type=1 +11 AEDT dst
|
||||
0053: 1987-03-14T16:00:00Z unix=542736000 wall=1987-03-15T02:00:00 fold-until(1987-03-15T03:00:00) type=2 +10 AEST
|
||||
0054: 1987-10-24T16:00:00Z unix=562089600 wall=1987-10-25T02:00:00 gap-until(1987-10-25T03:00:00) type=1 +11 AEDT dst
|
||||
0055: 1988-03-19T16:00:00Z unix=574790400 wall=1988-03-20T02:00:00 fold-until(1988-03-20T03:00:00) type=2 +10 AEST
|
||||
0056: 1988-10-29T16:00:00Z unix=594144000 wall=1988-10-30T02:00:00 gap-until(1988-10-30T03:00:00) type=1 +11 AEDT dst
|
||||
0057: 1989-03-18T16:00:00Z unix=606240000 wall=1989-03-19T02:00:00 fold-until(1989-03-19T03:00:00) type=2 +10 AEST
|
||||
0058: 1989-10-28T16:00:00Z unix=625593600 wall=1989-10-29T02:00:00 gap-until(1989-10-29T03:00:00) type=1 +11 AEDT dst
|
||||
0059: 1990-03-17T16:00:00Z unix=637689600 wall=1990-03-18T02:00:00 fold-until(1990-03-18T03:00:00) type=2 +10 AEST
|
||||
0060: 1990-10-27T16:00:00Z unix=657043200 wall=1990-10-28T02:00:00 gap-until(1990-10-28T03:00:00) type=1 +11 AEDT dst
|
||||
0061: 1991-03-30T16:00:00Z unix=670348800 wall=1991-03-31T02:00:00 fold-until(1991-03-31T03:00:00) type=2 +10 AEST
|
||||
0062: 1991-10-05T16:00:00Z unix=686678400 wall=1991-10-06T02:00:00 gap-until(1991-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0063: 1992-03-28T16:00:00Z unix=701798400 wall=1992-03-29T02:00:00 fold-until(1992-03-29T03:00:00) type=2 +10 AEST
|
||||
0064: 1992-10-03T16:00:00Z unix=718128000 wall=1992-10-04T02:00:00 gap-until(1992-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
0065: 1993-03-27T16:00:00Z unix=733248000 wall=1993-03-28T02:00:00 fold-until(1993-03-28T03:00:00) type=2 +10 AEST
|
||||
0066: 1993-10-02T16:00:00Z unix=749577600 wall=1993-10-03T02:00:00 gap-until(1993-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0067: 1994-03-26T16:00:00Z unix=764697600 wall=1994-03-27T02:00:00 fold-until(1994-03-27T03:00:00) type=2 +10 AEST
|
||||
0068: 1994-10-01T16:00:00Z unix=781027200 wall=1994-10-02T02:00:00 gap-until(1994-10-02T03:00:00) type=1 +11 AEDT dst
|
||||
0069: 1995-03-25T16:00:00Z unix=796147200 wall=1995-03-26T02:00:00 fold-until(1995-03-26T03:00:00) type=2 +10 AEST
|
||||
0070: 1995-09-30T16:00:00Z unix=812476800 wall=1995-10-01T02:00:00 gap-until(1995-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0071: 1996-03-30T16:00:00Z unix=828201600 wall=1996-03-31T02:00:00 fold-until(1996-03-31T03:00:00) type=2 +10 AEST
|
||||
0072: 1996-10-05T16:00:00Z unix=844531200 wall=1996-10-06T02:00:00 gap-until(1996-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0073: 1997-03-29T16:00:00Z unix=859651200 wall=1997-03-30T02:00:00 fold-until(1997-03-30T03:00:00) type=2 +10 AEST
|
||||
0074: 1997-10-04T16:00:00Z unix=875980800 wall=1997-10-05T02:00:00 gap-until(1997-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0075: 1998-03-28T16:00:00Z unix=891100800 wall=1998-03-29T02:00:00 fold-until(1998-03-29T03:00:00) type=2 +10 AEST
|
||||
0076: 1998-10-03T16:00:00Z unix=907430400 wall=1998-10-04T02:00:00 gap-until(1998-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
0077: 1999-03-27T16:00:00Z unix=922550400 wall=1999-03-28T02:00:00 fold-until(1999-03-28T03:00:00) type=2 +10 AEST
|
||||
0078: 1999-10-02T16:00:00Z unix=938880000 wall=1999-10-03T02:00:00 gap-until(1999-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0079: 2000-03-25T16:00:00Z unix=954000000 wall=2000-03-26T02:00:00 fold-until(2000-03-26T03:00:00) type=2 +10 AEST
|
||||
0080: 2000-08-26T16:00:00Z unix=967305600 wall=2000-08-27T02:00:00 gap-until(2000-08-27T03:00:00) type=1 +11 AEDT dst
|
||||
0081: 2001-03-24T16:00:00Z unix=985449600 wall=2001-03-25T02:00:00 fold-until(2001-03-25T03:00:00) type=2 +10 AEST
|
||||
0082: 2001-10-06T16:00:00Z unix=1002384000 wall=2001-10-07T02:00:00 gap-until(2001-10-07T03:00:00) type=1 +11 AEDT dst
|
||||
0083: 2002-03-30T16:00:00Z unix=1017504000 wall=2002-03-31T02:00:00 fold-until(2002-03-31T03:00:00) type=2 +10 AEST
|
||||
0084: 2002-10-05T16:00:00Z unix=1033833600 wall=2002-10-06T02:00:00 gap-until(2002-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0085: 2003-03-29T16:00:00Z unix=1048953600 wall=2003-03-30T02:00:00 fold-until(2003-03-30T03:00:00) type=2 +10 AEST
|
||||
0086: 2003-10-04T16:00:00Z unix=1065283200 wall=2003-10-05T02:00:00 gap-until(2003-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0087: 2004-03-27T16:00:00Z unix=1080403200 wall=2004-03-28T02:00:00 fold-until(2004-03-28T03:00:00) type=2 +10 AEST
|
||||
0088: 2004-10-02T16:00:00Z unix=1096732800 wall=2004-10-03T02:00:00 gap-until(2004-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0089: 2005-03-26T16:00:00Z unix=1111852800 wall=2005-03-27T02:00:00 fold-until(2005-03-27T03:00:00) type=2 +10 AEST
|
||||
0090: 2005-10-01T16:00:00Z unix=1128182400 wall=2005-10-02T02:00:00 gap-until(2005-10-02T03:00:00) type=1 +11 AEDT dst
|
||||
0091: 2006-04-01T16:00:00Z unix=1143907200 wall=2006-04-02T02:00:00 fold-until(2006-04-02T03:00:00) type=2 +10 AEST
|
||||
0092: 2006-09-30T16:00:00Z unix=1159632000 wall=2006-10-01T02:00:00 gap-until(2006-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0093: 2007-03-24T16:00:00Z unix=1174752000 wall=2007-03-25T02:00:00 fold-until(2007-03-25T03:00:00) type=2 +10 AEST
|
||||
0094: 2007-10-06T16:00:00Z unix=1191686400 wall=2007-10-07T02:00:00 gap-until(2007-10-07T03:00:00) type=1 +11 AEDT dst
|
||||
0095: 2008-04-05T16:00:00Z unix=1207411200 wall=2008-04-06T02:00:00 fold-until(2008-04-06T03:00:00) type=2 +10 AEST
|
||||
0096: 2008-10-04T16:00:00Z unix=1223136000 wall=2008-10-05T02:00:00 gap-until(2008-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0097: 2009-04-04T16:00:00Z unix=1238860800 wall=2009-04-05T02:00:00 fold-until(2009-04-05T03:00:00) type=2 +10 AEST
|
||||
0098: 2009-10-03T16:00:00Z unix=1254585600 wall=2009-10-04T02:00:00 gap-until(2009-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
0099: 2010-04-03T16:00:00Z unix=1270310400 wall=2010-04-04T02:00:00 fold-until(2010-04-04T03:00:00) type=2 +10 AEST
|
||||
0100: 2010-10-02T16:00:00Z unix=1286035200 wall=2010-10-03T02:00:00 gap-until(2010-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0101: 2011-04-02T16:00:00Z unix=1301760000 wall=2011-04-03T02:00:00 fold-until(2011-04-03T03:00:00) type=2 +10 AEST
|
||||
0102: 2011-10-01T16:00:00Z unix=1317484800 wall=2011-10-02T02:00:00 gap-until(2011-10-02T03:00:00) type=1 +11 AEDT dst
|
||||
0103: 2012-03-31T16:00:00Z unix=1333209600 wall=2012-04-01T02:00:00 fold-until(2012-04-01T03:00:00) type=2 +10 AEST
|
||||
0104: 2012-10-06T16:00:00Z unix=1349539200 wall=2012-10-07T02:00:00 gap-until(2012-10-07T03:00:00) type=1 +11 AEDT dst
|
||||
0105: 2013-04-06T16:00:00Z unix=1365264000 wall=2013-04-07T02:00:00 fold-until(2013-04-07T03:00:00) type=2 +10 AEST
|
||||
0106: 2013-10-05T16:00:00Z unix=1380988800 wall=2013-10-06T02:00:00 gap-until(2013-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0107: 2014-04-05T16:00:00Z unix=1396713600 wall=2014-04-06T02:00:00 fold-until(2014-04-06T03:00:00) type=2 +10 AEST
|
||||
0108: 2014-10-04T16:00:00Z unix=1412438400 wall=2014-10-05T02:00:00 gap-until(2014-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0109: 2015-04-04T16:00:00Z unix=1428163200 wall=2015-04-05T02:00:00 fold-until(2015-04-05T03:00:00) type=2 +10 AEST
|
||||
0110: 2015-10-03T16:00:00Z unix=1443888000 wall=2015-10-04T02:00:00 gap-until(2015-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
0111: 2016-04-02T16:00:00Z unix=1459612800 wall=2016-04-03T02:00:00 fold-until(2016-04-03T03:00:00) type=2 +10 AEST
|
||||
0112: 2016-10-01T16:00:00Z unix=1475337600 wall=2016-10-02T02:00:00 gap-until(2016-10-02T03:00:00) type=1 +11 AEDT dst
|
||||
0113: 2017-04-01T16:00:00Z unix=1491062400 wall=2017-04-02T02:00:00 fold-until(2017-04-02T03:00:00) type=2 +10 AEST
|
||||
0114: 2017-09-30T16:00:00Z unix=1506787200 wall=2017-10-01T02:00:00 gap-until(2017-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0115: 2018-03-31T16:00:00Z unix=1522512000 wall=2018-04-01T02:00:00 fold-until(2018-04-01T03:00:00) type=2 +10 AEST
|
||||
0116: 2018-10-06T16:00:00Z unix=1538841600 wall=2018-10-07T02:00:00 gap-until(2018-10-07T03:00:00) type=1 +11 AEDT dst
|
||||
0117: 2019-04-06T16:00:00Z unix=1554566400 wall=2019-04-07T02:00:00 fold-until(2019-04-07T03:00:00) type=2 +10 AEST
|
||||
0118: 2019-10-05T16:00:00Z unix=1570291200 wall=2019-10-06T02:00:00 gap-until(2019-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0119: 2020-04-04T16:00:00Z unix=1586016000 wall=2020-04-05T02:00:00 fold-until(2020-04-05T03:00:00) type=2 +10 AEST
|
||||
0120: 2020-10-03T16:00:00Z unix=1601740800 wall=2020-10-04T02:00:00 gap-until(2020-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
0121: 2021-04-03T16:00:00Z unix=1617465600 wall=2021-04-04T02:00:00 fold-until(2021-04-04T03:00:00) type=2 +10 AEST
|
||||
0122: 2021-10-02T16:00:00Z unix=1633190400 wall=2021-10-03T02:00:00 gap-until(2021-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0123: 2022-04-02T16:00:00Z unix=1648915200 wall=2022-04-03T02:00:00 fold-until(2022-04-03T03:00:00) type=2 +10 AEST
|
||||
0124: 2022-10-01T16:00:00Z unix=1664640000 wall=2022-10-02T02:00:00 gap-until(2022-10-02T03:00:00) type=1 +11 AEDT dst
|
||||
0125: 2023-04-01T16:00:00Z unix=1680364800 wall=2023-04-02T02:00:00 fold-until(2023-04-02T03:00:00) type=2 +10 AEST
|
||||
0126: 2023-09-30T16:00:00Z unix=1696089600 wall=2023-10-01T02:00:00 gap-until(2023-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0127: 2024-04-06T16:00:00Z unix=1712419200 wall=2024-04-07T02:00:00 fold-until(2024-04-07T03:00:00) type=2 +10 AEST
|
||||
0128: 2024-10-05T16:00:00Z unix=1728144000 wall=2024-10-06T02:00:00 gap-until(2024-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0129: 2025-04-05T16:00:00Z unix=1743868800 wall=2025-04-06T02:00:00 fold-until(2025-04-06T03:00:00) type=2 +10 AEST
|
||||
0130: 2025-10-04T16:00:00Z unix=1759593600 wall=2025-10-05T02:00:00 gap-until(2025-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0131: 2026-04-04T16:00:00Z unix=1775318400 wall=2026-04-05T02:00:00 fold-until(2026-04-05T03:00:00) type=2 +10 AEST
|
||||
0132: 2026-10-03T16:00:00Z unix=1791043200 wall=2026-10-04T02:00:00 gap-until(2026-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
0133: 2027-04-03T16:00:00Z unix=1806768000 wall=2027-04-04T02:00:00 fold-until(2027-04-04T03:00:00) type=2 +10 AEST
|
||||
0134: 2027-10-02T16:00:00Z unix=1822492800 wall=2027-10-03T02:00:00 gap-until(2027-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0135: 2028-04-01T16:00:00Z unix=1838217600 wall=2028-04-02T02:00:00 fold-until(2028-04-02T03:00:00) type=2 +10 AEST
|
||||
0136: 2028-09-30T16:00:00Z unix=1853942400 wall=2028-10-01T02:00:00 gap-until(2028-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0137: 2029-03-31T16:00:00Z unix=1869667200 wall=2029-04-01T02:00:00 fold-until(2029-04-01T03:00:00) type=2 +10 AEST
|
||||
0138: 2029-10-06T16:00:00Z unix=1885996800 wall=2029-10-07T02:00:00 gap-until(2029-10-07T03:00:00) type=1 +11 AEDT dst
|
||||
0139: 2030-04-06T16:00:00Z unix=1901721600 wall=2030-04-07T02:00:00 fold-until(2030-04-07T03:00:00) type=2 +10 AEST
|
||||
0140: 2030-10-05T16:00:00Z unix=1917446400 wall=2030-10-06T02:00:00 gap-until(2030-10-06T03:00:00) type=1 +11 AEDT dst
|
||||
0141: 2031-04-05T16:00:00Z unix=1933171200 wall=2031-04-06T02:00:00 fold-until(2031-04-06T03:00:00) type=2 +10 AEST
|
||||
0142: 2031-10-04T16:00:00Z unix=1948896000 wall=2031-10-05T02:00:00 gap-until(2031-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0143: 2032-04-03T16:00:00Z unix=1964620800 wall=2032-04-04T02:00:00 fold-until(2032-04-04T03:00:00) type=2 +10 AEST
|
||||
0144: 2032-10-02T16:00:00Z unix=1980345600 wall=2032-10-03T02:00:00 gap-until(2032-10-03T03:00:00) type=1 +11 AEDT dst
|
||||
0145: 2033-04-02T16:00:00Z unix=1996070400 wall=2033-04-03T02:00:00 fold-until(2033-04-03T03:00:00) type=2 +10 AEST
|
||||
0146: 2033-10-01T16:00:00Z unix=2011795200 wall=2033-10-02T02:00:00 gap-until(2033-10-02T03:00:00) type=1 +11 AEDT dst
|
||||
0147: 2034-04-01T16:00:00Z unix=2027520000 wall=2034-04-02T02:00:00 fold-until(2034-04-02T03:00:00) type=2 +10 AEST
|
||||
0148: 2034-09-30T16:00:00Z unix=2043244800 wall=2034-10-01T02:00:00 gap-until(2034-10-01T03:00:00) type=1 +11 AEDT dst
|
||||
0149: 2035-03-31T16:00:00Z unix=2058969600 wall=2035-04-01T02:00:00 fold-until(2035-04-01T03:00:00) type=2 +10 AEST
|
||||
0150: 2035-10-06T16:00:00Z unix=2075299200 wall=2035-10-07T02:00:00 gap-until(2035-10-07T03:00:00) type=1 +11 AEDT dst
|
||||
0151: 2036-04-05T16:00:00Z unix=2091024000 wall=2036-04-06T02:00:00 fold-until(2036-04-06T03:00:00) type=2 +10 AEST
|
||||
0152: 2036-10-04T16:00:00Z unix=2106748800 wall=2036-10-05T02:00:00 gap-until(2036-10-05T03:00:00) type=1 +11 AEDT dst
|
||||
0153: 2037-04-04T16:00:00Z unix=2122473600 wall=2037-04-05T02:00:00 fold-until(2037-04-05T03:00:00) type=2 +10 AEST
|
||||
0154: 2037-10-03T16:00:00Z unix=2138198400 wall=2037-10-04T02:00:00 gap-until(2037-10-04T03:00:00) type=1 +11 AEDT dst
|
||||
POSIX TIME ZONE STRING
|
||||
AEST-10AEDT,M10.1.0,M4.1.0/3
|
||||
246
src/tz/snapshots/jiff__tz__tzif__tests__Europe__Dublin_v1.snap
Normal file
246
src/tz/snapshots/jiff__tz__tzif__tests__Europe__Dublin_v1.snap
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse_v1())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
Europe/Dublin
|
||||
LOCAL TIME TYPES
|
||||
000: offset=-00:25:21 designation=LMT indicator=local/wall
|
||||
001: offset=-00:25:21 designation=DMT indicator=local/wall
|
||||
002: offset=+00:34:39 designation=IST dst indicator=local/std
|
||||
003: offset=+01 designation=BST dst indicator=local/std
|
||||
004: offset=+00 designation=GMT indicator=local/std
|
||||
005: offset=+01 designation=IST dst indicator=local/std
|
||||
006: offset=+00 designation=GMT dst indicator=ut/std
|
||||
007: offset=+01 designation=IST indicator=ut/std
|
||||
008: offset=+01 designation=IST indicator=local/wall
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-02T01:34:38 unambiguous type=0 -00:25:21 LMT
|
||||
0001: 1901-12-13T20:45:52Z unix=-2147483648 wall=1901-12-13T20:20:31 unambiguous type=1 -00:25:21 DMT
|
||||
0002: 1916-05-21T02:25:21Z unix=-1691962479 wall=1916-05-21T02:00:00 gap-until(1916-05-21T03:00:00) type=2 +00:34:39 IST dst
|
||||
0003: 1916-10-01T02:25:21Z unix=-1680471279 wall=1916-10-01T02:25:21 fold-until(1916-10-01T03:00:00) type=4 +00 GMT
|
||||
0004: 1917-04-08T02:00:00Z unix=-1664143200 wall=1917-04-08T02:00:00 gap-until(1917-04-08T03:00:00) type=3 +01 BST dst
|
||||
0005: 1917-09-17T02:00:00Z unix=-1650146400 wall=1917-09-17T02:00:00 fold-until(1917-09-17T03:00:00) type=4 +00 GMT
|
||||
0006: 1918-03-24T02:00:00Z unix=-1633903200 wall=1918-03-24T02:00:00 gap-until(1918-03-24T03:00:00) type=3 +01 BST dst
|
||||
0007: 1918-09-30T02:00:00Z unix=-1617487200 wall=1918-09-30T02:00:00 fold-until(1918-09-30T03:00:00) type=4 +00 GMT
|
||||
0008: 1919-03-30T02:00:00Z unix=-1601848800 wall=1919-03-30T02:00:00 gap-until(1919-03-30T03:00:00) type=3 +01 BST dst
|
||||
0009: 1919-09-29T02:00:00Z unix=-1586037600 wall=1919-09-29T02:00:00 fold-until(1919-09-29T03:00:00) type=4 +00 GMT
|
||||
0010: 1920-03-28T02:00:00Z unix=-1570399200 wall=1920-03-28T02:00:00 gap-until(1920-03-28T03:00:00) type=3 +01 BST dst
|
||||
0011: 1920-10-25T02:00:00Z unix=-1552168800 wall=1920-10-25T02:00:00 fold-until(1920-10-25T03:00:00) type=4 +00 GMT
|
||||
0012: 1921-04-03T02:00:00Z unix=-1538344800 wall=1921-04-03T02:00:00 gap-until(1921-04-03T03:00:00) type=3 +01 BST dst
|
||||
0013: 1921-10-03T02:00:00Z unix=-1522533600 wall=1921-10-03T02:00:00 fold-until(1921-10-03T03:00:00) type=4 +00 GMT
|
||||
0014: 1922-03-26T02:00:00Z unix=-1507500000 wall=1922-03-26T02:00:00 gap-until(1922-03-26T03:00:00) type=5 +01 IST dst
|
||||
0015: 1922-10-08T02:00:00Z unix=-1490565600 wall=1922-10-08T02:00:00 fold-until(1922-10-08T03:00:00) type=4 +00 GMT
|
||||
0016: 1923-04-22T02:00:00Z unix=-1473631200 wall=1923-04-22T02:00:00 gap-until(1923-04-22T03:00:00) type=5 +01 IST dst
|
||||
0017: 1923-09-16T02:00:00Z unix=-1460930400 wall=1923-09-16T02:00:00 fold-until(1923-09-16T03:00:00) type=4 +00 GMT
|
||||
0018: 1924-04-13T02:00:00Z unix=-1442786400 wall=1924-04-13T02:00:00 gap-until(1924-04-13T03:00:00) type=5 +01 IST dst
|
||||
0019: 1924-09-21T02:00:00Z unix=-1428876000 wall=1924-09-21T02:00:00 fold-until(1924-09-21T03:00:00) type=4 +00 GMT
|
||||
0020: 1925-04-19T02:00:00Z unix=-1410732000 wall=1925-04-19T02:00:00 gap-until(1925-04-19T03:00:00) type=5 +01 IST dst
|
||||
0021: 1925-10-04T02:00:00Z unix=-1396216800 wall=1925-10-04T02:00:00 fold-until(1925-10-04T03:00:00) type=4 +00 GMT
|
||||
0022: 1926-04-18T02:00:00Z unix=-1379282400 wall=1926-04-18T02:00:00 gap-until(1926-04-18T03:00:00) type=5 +01 IST dst
|
||||
0023: 1926-10-03T02:00:00Z unix=-1364767200 wall=1926-10-03T02:00:00 fold-until(1926-10-03T03:00:00) type=4 +00 GMT
|
||||
0024: 1927-04-10T02:00:00Z unix=-1348437600 wall=1927-04-10T02:00:00 gap-until(1927-04-10T03:00:00) type=5 +01 IST dst
|
||||
0025: 1927-10-02T02:00:00Z unix=-1333317600 wall=1927-10-02T02:00:00 fold-until(1927-10-02T03:00:00) type=4 +00 GMT
|
||||
0026: 1928-04-22T02:00:00Z unix=-1315778400 wall=1928-04-22T02:00:00 gap-until(1928-04-22T03:00:00) type=5 +01 IST dst
|
||||
0027: 1928-10-07T02:00:00Z unix=-1301263200 wall=1928-10-07T02:00:00 fold-until(1928-10-07T03:00:00) type=4 +00 GMT
|
||||
0028: 1929-04-21T02:00:00Z unix=-1284328800 wall=1929-04-21T02:00:00 gap-until(1929-04-21T03:00:00) type=5 +01 IST dst
|
||||
0029: 1929-10-06T02:00:00Z unix=-1269813600 wall=1929-10-06T02:00:00 fold-until(1929-10-06T03:00:00) type=4 +00 GMT
|
||||
0030: 1930-04-13T02:00:00Z unix=-1253484000 wall=1930-04-13T02:00:00 gap-until(1930-04-13T03:00:00) type=5 +01 IST dst
|
||||
0031: 1930-10-05T02:00:00Z unix=-1238364000 wall=1930-10-05T02:00:00 fold-until(1930-10-05T03:00:00) type=4 +00 GMT
|
||||
0032: 1931-04-19T02:00:00Z unix=-1221429600 wall=1931-04-19T02:00:00 gap-until(1931-04-19T03:00:00) type=5 +01 IST dst
|
||||
0033: 1931-10-04T02:00:00Z unix=-1206914400 wall=1931-10-04T02:00:00 fold-until(1931-10-04T03:00:00) type=4 +00 GMT
|
||||
0034: 1932-04-17T02:00:00Z unix=-1189980000 wall=1932-04-17T02:00:00 gap-until(1932-04-17T03:00:00) type=5 +01 IST dst
|
||||
0035: 1932-10-02T02:00:00Z unix=-1175464800 wall=1932-10-02T02:00:00 fold-until(1932-10-02T03:00:00) type=4 +00 GMT
|
||||
0036: 1933-04-09T02:00:00Z unix=-1159135200 wall=1933-04-09T02:00:00 gap-until(1933-04-09T03:00:00) type=5 +01 IST dst
|
||||
0037: 1933-10-08T02:00:00Z unix=-1143410400 wall=1933-10-08T02:00:00 fold-until(1933-10-08T03:00:00) type=4 +00 GMT
|
||||
0038: 1934-04-22T02:00:00Z unix=-1126476000 wall=1934-04-22T02:00:00 gap-until(1934-04-22T03:00:00) type=5 +01 IST dst
|
||||
0039: 1934-10-07T02:00:00Z unix=-1111960800 wall=1934-10-07T02:00:00 fold-until(1934-10-07T03:00:00) type=4 +00 GMT
|
||||
0040: 1935-04-14T02:00:00Z unix=-1095631200 wall=1935-04-14T02:00:00 gap-until(1935-04-14T03:00:00) type=5 +01 IST dst
|
||||
0041: 1935-10-06T02:00:00Z unix=-1080511200 wall=1935-10-06T02:00:00 fold-until(1935-10-06T03:00:00) type=4 +00 GMT
|
||||
0042: 1936-04-19T02:00:00Z unix=-1063576800 wall=1936-04-19T02:00:00 gap-until(1936-04-19T03:00:00) type=5 +01 IST dst
|
||||
0043: 1936-10-04T02:00:00Z unix=-1049061600 wall=1936-10-04T02:00:00 fold-until(1936-10-04T03:00:00) type=4 +00 GMT
|
||||
0044: 1937-04-18T02:00:00Z unix=-1032127200 wall=1937-04-18T02:00:00 gap-until(1937-04-18T03:00:00) type=5 +01 IST dst
|
||||
0045: 1937-10-03T02:00:00Z unix=-1017612000 wall=1937-10-03T02:00:00 fold-until(1937-10-03T03:00:00) type=4 +00 GMT
|
||||
0046: 1938-04-10T02:00:00Z unix=-1001282400 wall=1938-04-10T02:00:00 gap-until(1938-04-10T03:00:00) type=5 +01 IST dst
|
||||
0047: 1938-10-02T02:00:00Z unix=-986162400 wall=1938-10-02T02:00:00 fold-until(1938-10-02T03:00:00) type=4 +00 GMT
|
||||
0048: 1939-04-16T02:00:00Z unix=-969228000 wall=1939-04-16T02:00:00 gap-until(1939-04-16T03:00:00) type=5 +01 IST dst
|
||||
0049: 1939-11-19T02:00:00Z unix=-950479200 wall=1939-11-19T02:00:00 fold-until(1939-11-19T03:00:00) type=4 +00 GMT
|
||||
0050: 1940-02-25T02:00:00Z unix=-942012000 wall=1940-02-25T02:00:00 gap-until(1940-02-25T03:00:00) type=5 +01 IST dst
|
||||
0051: 1946-10-06T02:00:00Z unix=-733356000 wall=1946-10-06T02:00:00 fold-until(1946-10-06T03:00:00) type=4 +00 GMT
|
||||
0052: 1947-03-16T02:00:00Z unix=-719445600 wall=1947-03-16T02:00:00 gap-until(1947-03-16T03:00:00) type=5 +01 IST dst
|
||||
0053: 1947-11-02T02:00:00Z unix=-699487200 wall=1947-11-02T02:00:00 fold-until(1947-11-02T03:00:00) type=4 +00 GMT
|
||||
0054: 1948-04-18T02:00:00Z unix=-684972000 wall=1948-04-18T02:00:00 gap-until(1948-04-18T03:00:00) type=5 +01 IST dst
|
||||
0055: 1948-10-31T02:00:00Z unix=-668037600 wall=1948-10-31T02:00:00 fold-until(1948-10-31T03:00:00) type=4 +00 GMT
|
||||
0056: 1949-04-03T02:00:00Z unix=-654732000 wall=1949-04-03T02:00:00 gap-until(1949-04-03T03:00:00) type=5 +01 IST dst
|
||||
0057: 1949-10-30T02:00:00Z unix=-636588000 wall=1949-10-30T02:00:00 fold-until(1949-10-30T03:00:00) type=4 +00 GMT
|
||||
0058: 1950-04-16T02:00:00Z unix=-622072800 wall=1950-04-16T02:00:00 gap-until(1950-04-16T03:00:00) type=5 +01 IST dst
|
||||
0059: 1950-10-22T02:00:00Z unix=-605743200 wall=1950-10-22T02:00:00 fold-until(1950-10-22T03:00:00) type=4 +00 GMT
|
||||
0060: 1951-04-15T02:00:00Z unix=-590623200 wall=1951-04-15T02:00:00 gap-until(1951-04-15T03:00:00) type=5 +01 IST dst
|
||||
0061: 1951-10-21T02:00:00Z unix=-574293600 wall=1951-10-21T02:00:00 fold-until(1951-10-21T03:00:00) type=4 +00 GMT
|
||||
0062: 1952-04-20T02:00:00Z unix=-558568800 wall=1952-04-20T02:00:00 gap-until(1952-04-20T03:00:00) type=5 +01 IST dst
|
||||
0063: 1952-10-26T02:00:00Z unix=-542239200 wall=1952-10-26T02:00:00 fold-until(1952-10-26T03:00:00) type=4 +00 GMT
|
||||
0064: 1953-04-19T02:00:00Z unix=-527119200 wall=1953-04-19T02:00:00 gap-until(1953-04-19T03:00:00) type=5 +01 IST dst
|
||||
0065: 1953-10-04T02:00:00Z unix=-512604000 wall=1953-10-04T02:00:00 fold-until(1953-10-04T03:00:00) type=4 +00 GMT
|
||||
0066: 1954-04-11T02:00:00Z unix=-496274400 wall=1954-04-11T02:00:00 gap-until(1954-04-11T03:00:00) type=5 +01 IST dst
|
||||
0067: 1954-10-03T02:00:00Z unix=-481154400 wall=1954-10-03T02:00:00 fold-until(1954-10-03T03:00:00) type=4 +00 GMT
|
||||
0068: 1955-04-17T02:00:00Z unix=-464220000 wall=1955-04-17T02:00:00 gap-until(1955-04-17T03:00:00) type=5 +01 IST dst
|
||||
0069: 1955-10-02T02:00:00Z unix=-449704800 wall=1955-10-02T02:00:00 fold-until(1955-10-02T03:00:00) type=4 +00 GMT
|
||||
0070: 1956-04-22T02:00:00Z unix=-432165600 wall=1956-04-22T02:00:00 gap-until(1956-04-22T03:00:00) type=5 +01 IST dst
|
||||
0071: 1956-10-07T02:00:00Z unix=-417650400 wall=1956-10-07T02:00:00 fold-until(1956-10-07T03:00:00) type=4 +00 GMT
|
||||
0072: 1957-04-14T02:00:00Z unix=-401320800 wall=1957-04-14T02:00:00 gap-until(1957-04-14T03:00:00) type=5 +01 IST dst
|
||||
0073: 1957-10-06T02:00:00Z unix=-386200800 wall=1957-10-06T02:00:00 fold-until(1957-10-06T03:00:00) type=4 +00 GMT
|
||||
0074: 1958-04-20T02:00:00Z unix=-369266400 wall=1958-04-20T02:00:00 gap-until(1958-04-20T03:00:00) type=5 +01 IST dst
|
||||
0075: 1958-10-05T02:00:00Z unix=-354751200 wall=1958-10-05T02:00:00 fold-until(1958-10-05T03:00:00) type=4 +00 GMT
|
||||
0076: 1959-04-19T02:00:00Z unix=-337816800 wall=1959-04-19T02:00:00 gap-until(1959-04-19T03:00:00) type=5 +01 IST dst
|
||||
0077: 1959-10-04T02:00:00Z unix=-323301600 wall=1959-10-04T02:00:00 fold-until(1959-10-04T03:00:00) type=4 +00 GMT
|
||||
0078: 1960-04-10T02:00:00Z unix=-306972000 wall=1960-04-10T02:00:00 gap-until(1960-04-10T03:00:00) type=5 +01 IST dst
|
||||
0079: 1960-10-02T02:00:00Z unix=-291852000 wall=1960-10-02T02:00:00 fold-until(1960-10-02T03:00:00) type=4 +00 GMT
|
||||
0080: 1961-03-26T02:00:00Z unix=-276732000 wall=1961-03-26T02:00:00 gap-until(1961-03-26T03:00:00) type=5 +01 IST dst
|
||||
0081: 1961-10-29T02:00:00Z unix=-257983200 wall=1961-10-29T02:00:00 fold-until(1961-10-29T03:00:00) type=4 +00 GMT
|
||||
0082: 1962-03-25T02:00:00Z unix=-245282400 wall=1962-03-25T02:00:00 gap-until(1962-03-25T03:00:00) type=5 +01 IST dst
|
||||
0083: 1962-10-28T02:00:00Z unix=-226533600 wall=1962-10-28T02:00:00 fold-until(1962-10-28T03:00:00) type=4 +00 GMT
|
||||
0084: 1963-03-31T02:00:00Z unix=-213228000 wall=1963-03-31T02:00:00 gap-until(1963-03-31T03:00:00) type=5 +01 IST dst
|
||||
0085: 1963-10-27T02:00:00Z unix=-195084000 wall=1963-10-27T02:00:00 fold-until(1963-10-27T03:00:00) type=4 +00 GMT
|
||||
0086: 1964-03-22T02:00:00Z unix=-182383200 wall=1964-03-22T02:00:00 gap-until(1964-03-22T03:00:00) type=5 +01 IST dst
|
||||
0087: 1964-10-25T02:00:00Z unix=-163634400 wall=1964-10-25T02:00:00 fold-until(1964-10-25T03:00:00) type=4 +00 GMT
|
||||
0088: 1965-03-21T02:00:00Z unix=-150933600 wall=1965-03-21T02:00:00 gap-until(1965-03-21T03:00:00) type=5 +01 IST dst
|
||||
0089: 1965-10-24T02:00:00Z unix=-132184800 wall=1965-10-24T02:00:00 fold-until(1965-10-24T03:00:00) type=4 +00 GMT
|
||||
0090: 1966-03-20T02:00:00Z unix=-119484000 wall=1966-03-20T02:00:00 gap-until(1966-03-20T03:00:00) type=5 +01 IST dst
|
||||
0091: 1966-10-23T02:00:00Z unix=-100735200 wall=1966-10-23T02:00:00 fold-until(1966-10-23T03:00:00) type=4 +00 GMT
|
||||
0092: 1967-03-19T02:00:00Z unix=-88034400 wall=1967-03-19T02:00:00 gap-until(1967-03-19T03:00:00) type=5 +01 IST dst
|
||||
0093: 1967-10-29T02:00:00Z unix=-68680800 wall=1967-10-29T02:00:00 fold-until(1967-10-29T03:00:00) type=4 +00 GMT
|
||||
0094: 1968-02-18T02:00:00Z unix=-59004000 wall=1968-02-18T02:00:00 gap-until(1968-02-18T03:00:00) type=5 +01 IST dst
|
||||
0095: 1968-10-26T23:00:00Z unix=-37242000 wall=1968-10-27T00:00:00 unambiguous type=8 +01 IST
|
||||
0096: 1971-10-31T02:00:00Z unix=57722400 wall=1971-10-31T02:00:00 fold-until(1971-10-31T03:00:00) type=6 +00 GMT dst
|
||||
0097: 1972-03-19T02:00:00Z unix=69818400 wall=1972-03-19T02:00:00 gap-until(1972-03-19T03:00:00) type=7 +01 IST
|
||||
0098: 1972-10-29T02:00:00Z unix=89172000 wall=1972-10-29T02:00:00 fold-until(1972-10-29T03:00:00) type=6 +00 GMT dst
|
||||
0099: 1973-03-18T02:00:00Z unix=101268000 wall=1973-03-18T02:00:00 gap-until(1973-03-18T03:00:00) type=7 +01 IST
|
||||
0100: 1973-10-28T02:00:00Z unix=120621600 wall=1973-10-28T02:00:00 fold-until(1973-10-28T03:00:00) type=6 +00 GMT dst
|
||||
0101: 1974-03-17T02:00:00Z unix=132717600 wall=1974-03-17T02:00:00 gap-until(1974-03-17T03:00:00) type=7 +01 IST
|
||||
0102: 1974-10-27T02:00:00Z unix=152071200 wall=1974-10-27T02:00:00 fold-until(1974-10-27T03:00:00) type=6 +00 GMT dst
|
||||
0103: 1975-03-16T02:00:00Z unix=164167200 wall=1975-03-16T02:00:00 gap-until(1975-03-16T03:00:00) type=7 +01 IST
|
||||
0104: 1975-10-26T02:00:00Z unix=183520800 wall=1975-10-26T02:00:00 fold-until(1975-10-26T03:00:00) type=6 +00 GMT dst
|
||||
0105: 1976-03-21T02:00:00Z unix=196221600 wall=1976-03-21T02:00:00 gap-until(1976-03-21T03:00:00) type=7 +01 IST
|
||||
0106: 1976-10-24T02:00:00Z unix=214970400 wall=1976-10-24T02:00:00 fold-until(1976-10-24T03:00:00) type=6 +00 GMT dst
|
||||
0107: 1977-03-20T02:00:00Z unix=227671200 wall=1977-03-20T02:00:00 gap-until(1977-03-20T03:00:00) type=7 +01 IST
|
||||
0108: 1977-10-23T02:00:00Z unix=246420000 wall=1977-10-23T02:00:00 fold-until(1977-10-23T03:00:00) type=6 +00 GMT dst
|
||||
0109: 1978-03-19T02:00:00Z unix=259120800 wall=1978-03-19T02:00:00 gap-until(1978-03-19T03:00:00) type=7 +01 IST
|
||||
0110: 1978-10-29T02:00:00Z unix=278474400 wall=1978-10-29T02:00:00 fold-until(1978-10-29T03:00:00) type=6 +00 GMT dst
|
||||
0111: 1979-03-18T02:00:00Z unix=290570400 wall=1979-03-18T02:00:00 gap-until(1979-03-18T03:00:00) type=7 +01 IST
|
||||
0112: 1979-10-28T02:00:00Z unix=309924000 wall=1979-10-28T02:00:00 fold-until(1979-10-28T03:00:00) type=6 +00 GMT dst
|
||||
0113: 1980-03-16T02:00:00Z unix=322020000 wall=1980-03-16T02:00:00 gap-until(1980-03-16T03:00:00) type=7 +01 IST
|
||||
0114: 1980-10-26T02:00:00Z unix=341373600 wall=1980-10-26T02:00:00 fold-until(1980-10-26T03:00:00) type=6 +00 GMT dst
|
||||
0115: 1981-03-29T01:00:00Z unix=354675600 wall=1981-03-29T01:00:00 gap-until(1981-03-29T02:00:00) type=7 +01 IST
|
||||
0116: 1981-10-25T01:00:00Z unix=372819600 wall=1981-10-25T01:00:00 fold-until(1981-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0117: 1982-03-28T01:00:00Z unix=386125200 wall=1982-03-28T01:00:00 gap-until(1982-03-28T02:00:00) type=7 +01 IST
|
||||
0118: 1982-10-24T01:00:00Z unix=404269200 wall=1982-10-24T01:00:00 fold-until(1982-10-24T02:00:00) type=6 +00 GMT dst
|
||||
0119: 1983-03-27T01:00:00Z unix=417574800 wall=1983-03-27T01:00:00 gap-until(1983-03-27T02:00:00) type=7 +01 IST
|
||||
0120: 1983-10-23T01:00:00Z unix=435718800 wall=1983-10-23T01:00:00 fold-until(1983-10-23T02:00:00) type=6 +00 GMT dst
|
||||
0121: 1984-03-25T01:00:00Z unix=449024400 wall=1984-03-25T01:00:00 gap-until(1984-03-25T02:00:00) type=7 +01 IST
|
||||
0122: 1984-10-28T01:00:00Z unix=467773200 wall=1984-10-28T01:00:00 fold-until(1984-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0123: 1985-03-31T01:00:00Z unix=481078800 wall=1985-03-31T01:00:00 gap-until(1985-03-31T02:00:00) type=7 +01 IST
|
||||
0124: 1985-10-27T01:00:00Z unix=499222800 wall=1985-10-27T01:00:00 fold-until(1985-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0125: 1986-03-30T01:00:00Z unix=512528400 wall=1986-03-30T01:00:00 gap-until(1986-03-30T02:00:00) type=7 +01 IST
|
||||
0126: 1986-10-26T01:00:00Z unix=530672400 wall=1986-10-26T01:00:00 fold-until(1986-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0127: 1987-03-29T01:00:00Z unix=543978000 wall=1987-03-29T01:00:00 gap-until(1987-03-29T02:00:00) type=7 +01 IST
|
||||
0128: 1987-10-25T01:00:00Z unix=562122000 wall=1987-10-25T01:00:00 fold-until(1987-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0129: 1988-03-27T01:00:00Z unix=575427600 wall=1988-03-27T01:00:00 gap-until(1988-03-27T02:00:00) type=7 +01 IST
|
||||
0130: 1988-10-23T01:00:00Z unix=593571600 wall=1988-10-23T01:00:00 fold-until(1988-10-23T02:00:00) type=6 +00 GMT dst
|
||||
0131: 1989-03-26T01:00:00Z unix=606877200 wall=1989-03-26T01:00:00 gap-until(1989-03-26T02:00:00) type=7 +01 IST
|
||||
0132: 1989-10-29T01:00:00Z unix=625626000 wall=1989-10-29T01:00:00 fold-until(1989-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0133: 1990-03-25T01:00:00Z unix=638326800 wall=1990-03-25T01:00:00 gap-until(1990-03-25T02:00:00) type=7 +01 IST
|
||||
0134: 1990-10-28T01:00:00Z unix=657075600 wall=1990-10-28T01:00:00 fold-until(1990-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0135: 1991-03-31T01:00:00Z unix=670381200 wall=1991-03-31T01:00:00 gap-until(1991-03-31T02:00:00) type=7 +01 IST
|
||||
0136: 1991-10-27T01:00:00Z unix=688525200 wall=1991-10-27T01:00:00 fold-until(1991-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0137: 1992-03-29T01:00:00Z unix=701830800 wall=1992-03-29T01:00:00 gap-until(1992-03-29T02:00:00) type=7 +01 IST
|
||||
0138: 1992-10-25T01:00:00Z unix=719974800 wall=1992-10-25T01:00:00 fold-until(1992-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0139: 1993-03-28T01:00:00Z unix=733280400 wall=1993-03-28T01:00:00 gap-until(1993-03-28T02:00:00) type=7 +01 IST
|
||||
0140: 1993-10-24T01:00:00Z unix=751424400 wall=1993-10-24T01:00:00 fold-until(1993-10-24T02:00:00) type=6 +00 GMT dst
|
||||
0141: 1994-03-27T01:00:00Z unix=764730000 wall=1994-03-27T01:00:00 gap-until(1994-03-27T02:00:00) type=7 +01 IST
|
||||
0142: 1994-10-23T01:00:00Z unix=782874000 wall=1994-10-23T01:00:00 fold-until(1994-10-23T02:00:00) type=6 +00 GMT dst
|
||||
0143: 1995-03-26T01:00:00Z unix=796179600 wall=1995-03-26T01:00:00 gap-until(1995-03-26T02:00:00) type=7 +01 IST
|
||||
0144: 1995-10-22T01:00:00Z unix=814323600 wall=1995-10-22T01:00:00 fold-until(1995-10-22T02:00:00) type=6 +00 GMT dst
|
||||
0145: 1996-03-31T01:00:00Z unix=828234000 wall=1996-03-31T01:00:00 gap-until(1996-03-31T02:00:00) type=7 +01 IST
|
||||
0146: 1996-10-27T01:00:00Z unix=846378000 wall=1996-10-27T01:00:00 fold-until(1996-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0147: 1997-03-30T01:00:00Z unix=859683600 wall=1997-03-30T01:00:00 gap-until(1997-03-30T02:00:00) type=7 +01 IST
|
||||
0148: 1997-10-26T01:00:00Z unix=877827600 wall=1997-10-26T01:00:00 fold-until(1997-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0149: 1998-03-29T01:00:00Z unix=891133200 wall=1998-03-29T01:00:00 gap-until(1998-03-29T02:00:00) type=7 +01 IST
|
||||
0150: 1998-10-25T01:00:00Z unix=909277200 wall=1998-10-25T01:00:00 fold-until(1998-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0151: 1999-03-28T01:00:00Z unix=922582800 wall=1999-03-28T01:00:00 gap-until(1999-03-28T02:00:00) type=7 +01 IST
|
||||
0152: 1999-10-31T01:00:00Z unix=941331600 wall=1999-10-31T01:00:00 fold-until(1999-10-31T02:00:00) type=6 +00 GMT dst
|
||||
0153: 2000-03-26T01:00:00Z unix=954032400 wall=2000-03-26T01:00:00 gap-until(2000-03-26T02:00:00) type=7 +01 IST
|
||||
0154: 2000-10-29T01:00:00Z unix=972781200 wall=2000-10-29T01:00:00 fold-until(2000-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0155: 2001-03-25T01:00:00Z unix=985482000 wall=2001-03-25T01:00:00 gap-until(2001-03-25T02:00:00) type=7 +01 IST
|
||||
0156: 2001-10-28T01:00:00Z unix=1004230800 wall=2001-10-28T01:00:00 fold-until(2001-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0157: 2002-03-31T01:00:00Z unix=1017536400 wall=2002-03-31T01:00:00 gap-until(2002-03-31T02:00:00) type=7 +01 IST
|
||||
0158: 2002-10-27T01:00:00Z unix=1035680400 wall=2002-10-27T01:00:00 fold-until(2002-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0159: 2003-03-30T01:00:00Z unix=1048986000 wall=2003-03-30T01:00:00 gap-until(2003-03-30T02:00:00) type=7 +01 IST
|
||||
0160: 2003-10-26T01:00:00Z unix=1067130000 wall=2003-10-26T01:00:00 fold-until(2003-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0161: 2004-03-28T01:00:00Z unix=1080435600 wall=2004-03-28T01:00:00 gap-until(2004-03-28T02:00:00) type=7 +01 IST
|
||||
0162: 2004-10-31T01:00:00Z unix=1099184400 wall=2004-10-31T01:00:00 fold-until(2004-10-31T02:00:00) type=6 +00 GMT dst
|
||||
0163: 2005-03-27T01:00:00Z unix=1111885200 wall=2005-03-27T01:00:00 gap-until(2005-03-27T02:00:00) type=7 +01 IST
|
||||
0164: 2005-10-30T01:00:00Z unix=1130634000 wall=2005-10-30T01:00:00 fold-until(2005-10-30T02:00:00) type=6 +00 GMT dst
|
||||
0165: 2006-03-26T01:00:00Z unix=1143334800 wall=2006-03-26T01:00:00 gap-until(2006-03-26T02:00:00) type=7 +01 IST
|
||||
0166: 2006-10-29T01:00:00Z unix=1162083600 wall=2006-10-29T01:00:00 fold-until(2006-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0167: 2007-03-25T01:00:00Z unix=1174784400 wall=2007-03-25T01:00:00 gap-until(2007-03-25T02:00:00) type=7 +01 IST
|
||||
0168: 2007-10-28T01:00:00Z unix=1193533200 wall=2007-10-28T01:00:00 fold-until(2007-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0169: 2008-03-30T01:00:00Z unix=1206838800 wall=2008-03-30T01:00:00 gap-until(2008-03-30T02:00:00) type=7 +01 IST
|
||||
0170: 2008-10-26T01:00:00Z unix=1224982800 wall=2008-10-26T01:00:00 fold-until(2008-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0171: 2009-03-29T01:00:00Z unix=1238288400 wall=2009-03-29T01:00:00 gap-until(2009-03-29T02:00:00) type=7 +01 IST
|
||||
0172: 2009-10-25T01:00:00Z unix=1256432400 wall=2009-10-25T01:00:00 fold-until(2009-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0173: 2010-03-28T01:00:00Z unix=1269738000 wall=2010-03-28T01:00:00 gap-until(2010-03-28T02:00:00) type=7 +01 IST
|
||||
0174: 2010-10-31T01:00:00Z unix=1288486800 wall=2010-10-31T01:00:00 fold-until(2010-10-31T02:00:00) type=6 +00 GMT dst
|
||||
0175: 2011-03-27T01:00:00Z unix=1301187600 wall=2011-03-27T01:00:00 gap-until(2011-03-27T02:00:00) type=7 +01 IST
|
||||
0176: 2011-10-30T01:00:00Z unix=1319936400 wall=2011-10-30T01:00:00 fold-until(2011-10-30T02:00:00) type=6 +00 GMT dst
|
||||
0177: 2012-03-25T01:00:00Z unix=1332637200 wall=2012-03-25T01:00:00 gap-until(2012-03-25T02:00:00) type=7 +01 IST
|
||||
0178: 2012-10-28T01:00:00Z unix=1351386000 wall=2012-10-28T01:00:00 fold-until(2012-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0179: 2013-03-31T01:00:00Z unix=1364691600 wall=2013-03-31T01:00:00 gap-until(2013-03-31T02:00:00) type=7 +01 IST
|
||||
0180: 2013-10-27T01:00:00Z unix=1382835600 wall=2013-10-27T01:00:00 fold-until(2013-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0181: 2014-03-30T01:00:00Z unix=1396141200 wall=2014-03-30T01:00:00 gap-until(2014-03-30T02:00:00) type=7 +01 IST
|
||||
0182: 2014-10-26T01:00:00Z unix=1414285200 wall=2014-10-26T01:00:00 fold-until(2014-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0183: 2015-03-29T01:00:00Z unix=1427590800 wall=2015-03-29T01:00:00 gap-until(2015-03-29T02:00:00) type=7 +01 IST
|
||||
0184: 2015-10-25T01:00:00Z unix=1445734800 wall=2015-10-25T01:00:00 fold-until(2015-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0185: 2016-03-27T01:00:00Z unix=1459040400 wall=2016-03-27T01:00:00 gap-until(2016-03-27T02:00:00) type=7 +01 IST
|
||||
0186: 2016-10-30T01:00:00Z unix=1477789200 wall=2016-10-30T01:00:00 fold-until(2016-10-30T02:00:00) type=6 +00 GMT dst
|
||||
0187: 2017-03-26T01:00:00Z unix=1490490000 wall=2017-03-26T01:00:00 gap-until(2017-03-26T02:00:00) type=7 +01 IST
|
||||
0188: 2017-10-29T01:00:00Z unix=1509238800 wall=2017-10-29T01:00:00 fold-until(2017-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0189: 2018-03-25T01:00:00Z unix=1521939600 wall=2018-03-25T01:00:00 gap-until(2018-03-25T02:00:00) type=7 +01 IST
|
||||
0190: 2018-10-28T01:00:00Z unix=1540688400 wall=2018-10-28T01:00:00 fold-until(2018-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0191: 2019-03-31T01:00:00Z unix=1553994000 wall=2019-03-31T01:00:00 gap-until(2019-03-31T02:00:00) type=7 +01 IST
|
||||
0192: 2019-10-27T01:00:00Z unix=1572138000 wall=2019-10-27T01:00:00 fold-until(2019-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0193: 2020-03-29T01:00:00Z unix=1585443600 wall=2020-03-29T01:00:00 gap-until(2020-03-29T02:00:00) type=7 +01 IST
|
||||
0194: 2020-10-25T01:00:00Z unix=1603587600 wall=2020-10-25T01:00:00 fold-until(2020-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0195: 2021-03-28T01:00:00Z unix=1616893200 wall=2021-03-28T01:00:00 gap-until(2021-03-28T02:00:00) type=7 +01 IST
|
||||
0196: 2021-10-31T01:00:00Z unix=1635642000 wall=2021-10-31T01:00:00 fold-until(2021-10-31T02:00:00) type=6 +00 GMT dst
|
||||
0197: 2022-03-27T01:00:00Z unix=1648342800 wall=2022-03-27T01:00:00 gap-until(2022-03-27T02:00:00) type=7 +01 IST
|
||||
0198: 2022-10-30T01:00:00Z unix=1667091600 wall=2022-10-30T01:00:00 fold-until(2022-10-30T02:00:00) type=6 +00 GMT dst
|
||||
0199: 2023-03-26T01:00:00Z unix=1679792400 wall=2023-03-26T01:00:00 gap-until(2023-03-26T02:00:00) type=7 +01 IST
|
||||
0200: 2023-10-29T01:00:00Z unix=1698541200 wall=2023-10-29T01:00:00 fold-until(2023-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0201: 2024-03-31T01:00:00Z unix=1711846800 wall=2024-03-31T01:00:00 gap-until(2024-03-31T02:00:00) type=7 +01 IST
|
||||
0202: 2024-10-27T01:00:00Z unix=1729990800 wall=2024-10-27T01:00:00 fold-until(2024-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0203: 2025-03-30T01:00:00Z unix=1743296400 wall=2025-03-30T01:00:00 gap-until(2025-03-30T02:00:00) type=7 +01 IST
|
||||
0204: 2025-10-26T01:00:00Z unix=1761440400 wall=2025-10-26T01:00:00 fold-until(2025-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0205: 2026-03-29T01:00:00Z unix=1774746000 wall=2026-03-29T01:00:00 gap-until(2026-03-29T02:00:00) type=7 +01 IST
|
||||
0206: 2026-10-25T01:00:00Z unix=1792890000 wall=2026-10-25T01:00:00 fold-until(2026-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0207: 2027-03-28T01:00:00Z unix=1806195600 wall=2027-03-28T01:00:00 gap-until(2027-03-28T02:00:00) type=7 +01 IST
|
||||
0208: 2027-10-31T01:00:00Z unix=1824944400 wall=2027-10-31T01:00:00 fold-until(2027-10-31T02:00:00) type=6 +00 GMT dst
|
||||
0209: 2028-03-26T01:00:00Z unix=1837645200 wall=2028-03-26T01:00:00 gap-until(2028-03-26T02:00:00) type=7 +01 IST
|
||||
0210: 2028-10-29T01:00:00Z unix=1856394000 wall=2028-10-29T01:00:00 fold-until(2028-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0211: 2029-03-25T01:00:00Z unix=1869094800 wall=2029-03-25T01:00:00 gap-until(2029-03-25T02:00:00) type=7 +01 IST
|
||||
0212: 2029-10-28T01:00:00Z unix=1887843600 wall=2029-10-28T01:00:00 fold-until(2029-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0213: 2030-03-31T01:00:00Z unix=1901149200 wall=2030-03-31T01:00:00 gap-until(2030-03-31T02:00:00) type=7 +01 IST
|
||||
0214: 2030-10-27T01:00:00Z unix=1919293200 wall=2030-10-27T01:00:00 fold-until(2030-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0215: 2031-03-30T01:00:00Z unix=1932598800 wall=2031-03-30T01:00:00 gap-until(2031-03-30T02:00:00) type=7 +01 IST
|
||||
0216: 2031-10-26T01:00:00Z unix=1950742800 wall=2031-10-26T01:00:00 fold-until(2031-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0217: 2032-03-28T01:00:00Z unix=1964048400 wall=2032-03-28T01:00:00 gap-until(2032-03-28T02:00:00) type=7 +01 IST
|
||||
0218: 2032-10-31T01:00:00Z unix=1982797200 wall=2032-10-31T01:00:00 fold-until(2032-10-31T02:00:00) type=6 +00 GMT dst
|
||||
0219: 2033-03-27T01:00:00Z unix=1995498000 wall=2033-03-27T01:00:00 gap-until(2033-03-27T02:00:00) type=7 +01 IST
|
||||
0220: 2033-10-30T01:00:00Z unix=2014246800 wall=2033-10-30T01:00:00 fold-until(2033-10-30T02:00:00) type=6 +00 GMT dst
|
||||
0221: 2034-03-26T01:00:00Z unix=2026947600 wall=2034-03-26T01:00:00 gap-until(2034-03-26T02:00:00) type=7 +01 IST
|
||||
0222: 2034-10-29T01:00:00Z unix=2045696400 wall=2034-10-29T01:00:00 fold-until(2034-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0223: 2035-03-25T01:00:00Z unix=2058397200 wall=2035-03-25T01:00:00 gap-until(2035-03-25T02:00:00) type=7 +01 IST
|
||||
0224: 2035-10-28T01:00:00Z unix=2077146000 wall=2035-10-28T01:00:00 fold-until(2035-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0225: 2036-03-30T01:00:00Z unix=2090451600 wall=2036-03-30T01:00:00 gap-until(2036-03-30T02:00:00) type=7 +01 IST
|
||||
0226: 2036-10-26T01:00:00Z unix=2108595600 wall=2036-10-26T01:00:00 fold-until(2036-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0227: 2037-03-29T01:00:00Z unix=2121901200 wall=2037-03-29T01:00:00 gap-until(2037-03-29T02:00:00) type=7 +01 IST
|
||||
0228: 2037-10-25T01:00:00Z unix=2140045200 wall=2037-10-25T01:00:00 fold-until(2037-10-25T02:00:00) type=6 +00 GMT dst
|
||||
248
src/tz/snapshots/jiff__tz__tzif__tests__Europe__Dublin_v2+.snap
Normal file
248
src/tz/snapshots/jiff__tz__tzif__tests__Europe__Dublin_v2+.snap
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
Europe/Dublin
|
||||
LOCAL TIME TYPES
|
||||
000: offset=-00:25:21 designation=LMT indicator=local/wall
|
||||
001: offset=-00:25:21 designation=DMT indicator=local/wall
|
||||
002: offset=+00:34:39 designation=IST dst indicator=local/std
|
||||
003: offset=+01 designation=BST dst indicator=local/std
|
||||
004: offset=+00 designation=GMT indicator=local/std
|
||||
005: offset=+01 designation=IST dst indicator=local/std
|
||||
006: offset=+00 designation=GMT dst indicator=ut/std
|
||||
007: offset=+01 designation=IST indicator=ut/std
|
||||
008: offset=+01 designation=IST indicator=local/wall
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-02T01:34:38 unambiguous type=0 -00:25:21 LMT
|
||||
0001: 1880-08-02T00:25:21Z unix=-2821649679 wall=1880-08-02T00:00:00 unambiguous type=1 -00:25:21 DMT
|
||||
0002: 1916-05-21T02:25:21Z unix=-1691962479 wall=1916-05-21T02:00:00 gap-until(1916-05-21T03:00:00) type=2 +00:34:39 IST dst
|
||||
0003: 1916-10-01T02:25:21Z unix=-1680471279 wall=1916-10-01T02:25:21 fold-until(1916-10-01T03:00:00) type=4 +00 GMT
|
||||
0004: 1917-04-08T02:00:00Z unix=-1664143200 wall=1917-04-08T02:00:00 gap-until(1917-04-08T03:00:00) type=3 +01 BST dst
|
||||
0005: 1917-09-17T02:00:00Z unix=-1650146400 wall=1917-09-17T02:00:00 fold-until(1917-09-17T03:00:00) type=4 +00 GMT
|
||||
0006: 1918-03-24T02:00:00Z unix=-1633903200 wall=1918-03-24T02:00:00 gap-until(1918-03-24T03:00:00) type=3 +01 BST dst
|
||||
0007: 1918-09-30T02:00:00Z unix=-1617487200 wall=1918-09-30T02:00:00 fold-until(1918-09-30T03:00:00) type=4 +00 GMT
|
||||
0008: 1919-03-30T02:00:00Z unix=-1601848800 wall=1919-03-30T02:00:00 gap-until(1919-03-30T03:00:00) type=3 +01 BST dst
|
||||
0009: 1919-09-29T02:00:00Z unix=-1586037600 wall=1919-09-29T02:00:00 fold-until(1919-09-29T03:00:00) type=4 +00 GMT
|
||||
0010: 1920-03-28T02:00:00Z unix=-1570399200 wall=1920-03-28T02:00:00 gap-until(1920-03-28T03:00:00) type=3 +01 BST dst
|
||||
0011: 1920-10-25T02:00:00Z unix=-1552168800 wall=1920-10-25T02:00:00 fold-until(1920-10-25T03:00:00) type=4 +00 GMT
|
||||
0012: 1921-04-03T02:00:00Z unix=-1538344800 wall=1921-04-03T02:00:00 gap-until(1921-04-03T03:00:00) type=3 +01 BST dst
|
||||
0013: 1921-10-03T02:00:00Z unix=-1522533600 wall=1921-10-03T02:00:00 fold-until(1921-10-03T03:00:00) type=4 +00 GMT
|
||||
0014: 1922-03-26T02:00:00Z unix=-1507500000 wall=1922-03-26T02:00:00 gap-until(1922-03-26T03:00:00) type=5 +01 IST dst
|
||||
0015: 1922-10-08T02:00:00Z unix=-1490565600 wall=1922-10-08T02:00:00 fold-until(1922-10-08T03:00:00) type=4 +00 GMT
|
||||
0016: 1923-04-22T02:00:00Z unix=-1473631200 wall=1923-04-22T02:00:00 gap-until(1923-04-22T03:00:00) type=5 +01 IST dst
|
||||
0017: 1923-09-16T02:00:00Z unix=-1460930400 wall=1923-09-16T02:00:00 fold-until(1923-09-16T03:00:00) type=4 +00 GMT
|
||||
0018: 1924-04-13T02:00:00Z unix=-1442786400 wall=1924-04-13T02:00:00 gap-until(1924-04-13T03:00:00) type=5 +01 IST dst
|
||||
0019: 1924-09-21T02:00:00Z unix=-1428876000 wall=1924-09-21T02:00:00 fold-until(1924-09-21T03:00:00) type=4 +00 GMT
|
||||
0020: 1925-04-19T02:00:00Z unix=-1410732000 wall=1925-04-19T02:00:00 gap-until(1925-04-19T03:00:00) type=5 +01 IST dst
|
||||
0021: 1925-10-04T02:00:00Z unix=-1396216800 wall=1925-10-04T02:00:00 fold-until(1925-10-04T03:00:00) type=4 +00 GMT
|
||||
0022: 1926-04-18T02:00:00Z unix=-1379282400 wall=1926-04-18T02:00:00 gap-until(1926-04-18T03:00:00) type=5 +01 IST dst
|
||||
0023: 1926-10-03T02:00:00Z unix=-1364767200 wall=1926-10-03T02:00:00 fold-until(1926-10-03T03:00:00) type=4 +00 GMT
|
||||
0024: 1927-04-10T02:00:00Z unix=-1348437600 wall=1927-04-10T02:00:00 gap-until(1927-04-10T03:00:00) type=5 +01 IST dst
|
||||
0025: 1927-10-02T02:00:00Z unix=-1333317600 wall=1927-10-02T02:00:00 fold-until(1927-10-02T03:00:00) type=4 +00 GMT
|
||||
0026: 1928-04-22T02:00:00Z unix=-1315778400 wall=1928-04-22T02:00:00 gap-until(1928-04-22T03:00:00) type=5 +01 IST dst
|
||||
0027: 1928-10-07T02:00:00Z unix=-1301263200 wall=1928-10-07T02:00:00 fold-until(1928-10-07T03:00:00) type=4 +00 GMT
|
||||
0028: 1929-04-21T02:00:00Z unix=-1284328800 wall=1929-04-21T02:00:00 gap-until(1929-04-21T03:00:00) type=5 +01 IST dst
|
||||
0029: 1929-10-06T02:00:00Z unix=-1269813600 wall=1929-10-06T02:00:00 fold-until(1929-10-06T03:00:00) type=4 +00 GMT
|
||||
0030: 1930-04-13T02:00:00Z unix=-1253484000 wall=1930-04-13T02:00:00 gap-until(1930-04-13T03:00:00) type=5 +01 IST dst
|
||||
0031: 1930-10-05T02:00:00Z unix=-1238364000 wall=1930-10-05T02:00:00 fold-until(1930-10-05T03:00:00) type=4 +00 GMT
|
||||
0032: 1931-04-19T02:00:00Z unix=-1221429600 wall=1931-04-19T02:00:00 gap-until(1931-04-19T03:00:00) type=5 +01 IST dst
|
||||
0033: 1931-10-04T02:00:00Z unix=-1206914400 wall=1931-10-04T02:00:00 fold-until(1931-10-04T03:00:00) type=4 +00 GMT
|
||||
0034: 1932-04-17T02:00:00Z unix=-1189980000 wall=1932-04-17T02:00:00 gap-until(1932-04-17T03:00:00) type=5 +01 IST dst
|
||||
0035: 1932-10-02T02:00:00Z unix=-1175464800 wall=1932-10-02T02:00:00 fold-until(1932-10-02T03:00:00) type=4 +00 GMT
|
||||
0036: 1933-04-09T02:00:00Z unix=-1159135200 wall=1933-04-09T02:00:00 gap-until(1933-04-09T03:00:00) type=5 +01 IST dst
|
||||
0037: 1933-10-08T02:00:00Z unix=-1143410400 wall=1933-10-08T02:00:00 fold-until(1933-10-08T03:00:00) type=4 +00 GMT
|
||||
0038: 1934-04-22T02:00:00Z unix=-1126476000 wall=1934-04-22T02:00:00 gap-until(1934-04-22T03:00:00) type=5 +01 IST dst
|
||||
0039: 1934-10-07T02:00:00Z unix=-1111960800 wall=1934-10-07T02:00:00 fold-until(1934-10-07T03:00:00) type=4 +00 GMT
|
||||
0040: 1935-04-14T02:00:00Z unix=-1095631200 wall=1935-04-14T02:00:00 gap-until(1935-04-14T03:00:00) type=5 +01 IST dst
|
||||
0041: 1935-10-06T02:00:00Z unix=-1080511200 wall=1935-10-06T02:00:00 fold-until(1935-10-06T03:00:00) type=4 +00 GMT
|
||||
0042: 1936-04-19T02:00:00Z unix=-1063576800 wall=1936-04-19T02:00:00 gap-until(1936-04-19T03:00:00) type=5 +01 IST dst
|
||||
0043: 1936-10-04T02:00:00Z unix=-1049061600 wall=1936-10-04T02:00:00 fold-until(1936-10-04T03:00:00) type=4 +00 GMT
|
||||
0044: 1937-04-18T02:00:00Z unix=-1032127200 wall=1937-04-18T02:00:00 gap-until(1937-04-18T03:00:00) type=5 +01 IST dst
|
||||
0045: 1937-10-03T02:00:00Z unix=-1017612000 wall=1937-10-03T02:00:00 fold-until(1937-10-03T03:00:00) type=4 +00 GMT
|
||||
0046: 1938-04-10T02:00:00Z unix=-1001282400 wall=1938-04-10T02:00:00 gap-until(1938-04-10T03:00:00) type=5 +01 IST dst
|
||||
0047: 1938-10-02T02:00:00Z unix=-986162400 wall=1938-10-02T02:00:00 fold-until(1938-10-02T03:00:00) type=4 +00 GMT
|
||||
0048: 1939-04-16T02:00:00Z unix=-969228000 wall=1939-04-16T02:00:00 gap-until(1939-04-16T03:00:00) type=5 +01 IST dst
|
||||
0049: 1939-11-19T02:00:00Z unix=-950479200 wall=1939-11-19T02:00:00 fold-until(1939-11-19T03:00:00) type=4 +00 GMT
|
||||
0050: 1940-02-25T02:00:00Z unix=-942012000 wall=1940-02-25T02:00:00 gap-until(1940-02-25T03:00:00) type=5 +01 IST dst
|
||||
0051: 1946-10-06T02:00:00Z unix=-733356000 wall=1946-10-06T02:00:00 fold-until(1946-10-06T03:00:00) type=4 +00 GMT
|
||||
0052: 1947-03-16T02:00:00Z unix=-719445600 wall=1947-03-16T02:00:00 gap-until(1947-03-16T03:00:00) type=5 +01 IST dst
|
||||
0053: 1947-11-02T02:00:00Z unix=-699487200 wall=1947-11-02T02:00:00 fold-until(1947-11-02T03:00:00) type=4 +00 GMT
|
||||
0054: 1948-04-18T02:00:00Z unix=-684972000 wall=1948-04-18T02:00:00 gap-until(1948-04-18T03:00:00) type=5 +01 IST dst
|
||||
0055: 1948-10-31T02:00:00Z unix=-668037600 wall=1948-10-31T02:00:00 fold-until(1948-10-31T03:00:00) type=4 +00 GMT
|
||||
0056: 1949-04-03T02:00:00Z unix=-654732000 wall=1949-04-03T02:00:00 gap-until(1949-04-03T03:00:00) type=5 +01 IST dst
|
||||
0057: 1949-10-30T02:00:00Z unix=-636588000 wall=1949-10-30T02:00:00 fold-until(1949-10-30T03:00:00) type=4 +00 GMT
|
||||
0058: 1950-04-16T02:00:00Z unix=-622072800 wall=1950-04-16T02:00:00 gap-until(1950-04-16T03:00:00) type=5 +01 IST dst
|
||||
0059: 1950-10-22T02:00:00Z unix=-605743200 wall=1950-10-22T02:00:00 fold-until(1950-10-22T03:00:00) type=4 +00 GMT
|
||||
0060: 1951-04-15T02:00:00Z unix=-590623200 wall=1951-04-15T02:00:00 gap-until(1951-04-15T03:00:00) type=5 +01 IST dst
|
||||
0061: 1951-10-21T02:00:00Z unix=-574293600 wall=1951-10-21T02:00:00 fold-until(1951-10-21T03:00:00) type=4 +00 GMT
|
||||
0062: 1952-04-20T02:00:00Z unix=-558568800 wall=1952-04-20T02:00:00 gap-until(1952-04-20T03:00:00) type=5 +01 IST dst
|
||||
0063: 1952-10-26T02:00:00Z unix=-542239200 wall=1952-10-26T02:00:00 fold-until(1952-10-26T03:00:00) type=4 +00 GMT
|
||||
0064: 1953-04-19T02:00:00Z unix=-527119200 wall=1953-04-19T02:00:00 gap-until(1953-04-19T03:00:00) type=5 +01 IST dst
|
||||
0065: 1953-10-04T02:00:00Z unix=-512604000 wall=1953-10-04T02:00:00 fold-until(1953-10-04T03:00:00) type=4 +00 GMT
|
||||
0066: 1954-04-11T02:00:00Z unix=-496274400 wall=1954-04-11T02:00:00 gap-until(1954-04-11T03:00:00) type=5 +01 IST dst
|
||||
0067: 1954-10-03T02:00:00Z unix=-481154400 wall=1954-10-03T02:00:00 fold-until(1954-10-03T03:00:00) type=4 +00 GMT
|
||||
0068: 1955-04-17T02:00:00Z unix=-464220000 wall=1955-04-17T02:00:00 gap-until(1955-04-17T03:00:00) type=5 +01 IST dst
|
||||
0069: 1955-10-02T02:00:00Z unix=-449704800 wall=1955-10-02T02:00:00 fold-until(1955-10-02T03:00:00) type=4 +00 GMT
|
||||
0070: 1956-04-22T02:00:00Z unix=-432165600 wall=1956-04-22T02:00:00 gap-until(1956-04-22T03:00:00) type=5 +01 IST dst
|
||||
0071: 1956-10-07T02:00:00Z unix=-417650400 wall=1956-10-07T02:00:00 fold-until(1956-10-07T03:00:00) type=4 +00 GMT
|
||||
0072: 1957-04-14T02:00:00Z unix=-401320800 wall=1957-04-14T02:00:00 gap-until(1957-04-14T03:00:00) type=5 +01 IST dst
|
||||
0073: 1957-10-06T02:00:00Z unix=-386200800 wall=1957-10-06T02:00:00 fold-until(1957-10-06T03:00:00) type=4 +00 GMT
|
||||
0074: 1958-04-20T02:00:00Z unix=-369266400 wall=1958-04-20T02:00:00 gap-until(1958-04-20T03:00:00) type=5 +01 IST dst
|
||||
0075: 1958-10-05T02:00:00Z unix=-354751200 wall=1958-10-05T02:00:00 fold-until(1958-10-05T03:00:00) type=4 +00 GMT
|
||||
0076: 1959-04-19T02:00:00Z unix=-337816800 wall=1959-04-19T02:00:00 gap-until(1959-04-19T03:00:00) type=5 +01 IST dst
|
||||
0077: 1959-10-04T02:00:00Z unix=-323301600 wall=1959-10-04T02:00:00 fold-until(1959-10-04T03:00:00) type=4 +00 GMT
|
||||
0078: 1960-04-10T02:00:00Z unix=-306972000 wall=1960-04-10T02:00:00 gap-until(1960-04-10T03:00:00) type=5 +01 IST dst
|
||||
0079: 1960-10-02T02:00:00Z unix=-291852000 wall=1960-10-02T02:00:00 fold-until(1960-10-02T03:00:00) type=4 +00 GMT
|
||||
0080: 1961-03-26T02:00:00Z unix=-276732000 wall=1961-03-26T02:00:00 gap-until(1961-03-26T03:00:00) type=5 +01 IST dst
|
||||
0081: 1961-10-29T02:00:00Z unix=-257983200 wall=1961-10-29T02:00:00 fold-until(1961-10-29T03:00:00) type=4 +00 GMT
|
||||
0082: 1962-03-25T02:00:00Z unix=-245282400 wall=1962-03-25T02:00:00 gap-until(1962-03-25T03:00:00) type=5 +01 IST dst
|
||||
0083: 1962-10-28T02:00:00Z unix=-226533600 wall=1962-10-28T02:00:00 fold-until(1962-10-28T03:00:00) type=4 +00 GMT
|
||||
0084: 1963-03-31T02:00:00Z unix=-213228000 wall=1963-03-31T02:00:00 gap-until(1963-03-31T03:00:00) type=5 +01 IST dst
|
||||
0085: 1963-10-27T02:00:00Z unix=-195084000 wall=1963-10-27T02:00:00 fold-until(1963-10-27T03:00:00) type=4 +00 GMT
|
||||
0086: 1964-03-22T02:00:00Z unix=-182383200 wall=1964-03-22T02:00:00 gap-until(1964-03-22T03:00:00) type=5 +01 IST dst
|
||||
0087: 1964-10-25T02:00:00Z unix=-163634400 wall=1964-10-25T02:00:00 fold-until(1964-10-25T03:00:00) type=4 +00 GMT
|
||||
0088: 1965-03-21T02:00:00Z unix=-150933600 wall=1965-03-21T02:00:00 gap-until(1965-03-21T03:00:00) type=5 +01 IST dst
|
||||
0089: 1965-10-24T02:00:00Z unix=-132184800 wall=1965-10-24T02:00:00 fold-until(1965-10-24T03:00:00) type=4 +00 GMT
|
||||
0090: 1966-03-20T02:00:00Z unix=-119484000 wall=1966-03-20T02:00:00 gap-until(1966-03-20T03:00:00) type=5 +01 IST dst
|
||||
0091: 1966-10-23T02:00:00Z unix=-100735200 wall=1966-10-23T02:00:00 fold-until(1966-10-23T03:00:00) type=4 +00 GMT
|
||||
0092: 1967-03-19T02:00:00Z unix=-88034400 wall=1967-03-19T02:00:00 gap-until(1967-03-19T03:00:00) type=5 +01 IST dst
|
||||
0093: 1967-10-29T02:00:00Z unix=-68680800 wall=1967-10-29T02:00:00 fold-until(1967-10-29T03:00:00) type=4 +00 GMT
|
||||
0094: 1968-02-18T02:00:00Z unix=-59004000 wall=1968-02-18T02:00:00 gap-until(1968-02-18T03:00:00) type=5 +01 IST dst
|
||||
0095: 1968-10-26T23:00:00Z unix=-37242000 wall=1968-10-27T00:00:00 unambiguous type=8 +01 IST
|
||||
0096: 1971-10-31T02:00:00Z unix=57722400 wall=1971-10-31T02:00:00 fold-until(1971-10-31T03:00:00) type=6 +00 GMT dst
|
||||
0097: 1972-03-19T02:00:00Z unix=69818400 wall=1972-03-19T02:00:00 gap-until(1972-03-19T03:00:00) type=7 +01 IST
|
||||
0098: 1972-10-29T02:00:00Z unix=89172000 wall=1972-10-29T02:00:00 fold-until(1972-10-29T03:00:00) type=6 +00 GMT dst
|
||||
0099: 1973-03-18T02:00:00Z unix=101268000 wall=1973-03-18T02:00:00 gap-until(1973-03-18T03:00:00) type=7 +01 IST
|
||||
0100: 1973-10-28T02:00:00Z unix=120621600 wall=1973-10-28T02:00:00 fold-until(1973-10-28T03:00:00) type=6 +00 GMT dst
|
||||
0101: 1974-03-17T02:00:00Z unix=132717600 wall=1974-03-17T02:00:00 gap-until(1974-03-17T03:00:00) type=7 +01 IST
|
||||
0102: 1974-10-27T02:00:00Z unix=152071200 wall=1974-10-27T02:00:00 fold-until(1974-10-27T03:00:00) type=6 +00 GMT dst
|
||||
0103: 1975-03-16T02:00:00Z unix=164167200 wall=1975-03-16T02:00:00 gap-until(1975-03-16T03:00:00) type=7 +01 IST
|
||||
0104: 1975-10-26T02:00:00Z unix=183520800 wall=1975-10-26T02:00:00 fold-until(1975-10-26T03:00:00) type=6 +00 GMT dst
|
||||
0105: 1976-03-21T02:00:00Z unix=196221600 wall=1976-03-21T02:00:00 gap-until(1976-03-21T03:00:00) type=7 +01 IST
|
||||
0106: 1976-10-24T02:00:00Z unix=214970400 wall=1976-10-24T02:00:00 fold-until(1976-10-24T03:00:00) type=6 +00 GMT dst
|
||||
0107: 1977-03-20T02:00:00Z unix=227671200 wall=1977-03-20T02:00:00 gap-until(1977-03-20T03:00:00) type=7 +01 IST
|
||||
0108: 1977-10-23T02:00:00Z unix=246420000 wall=1977-10-23T02:00:00 fold-until(1977-10-23T03:00:00) type=6 +00 GMT dst
|
||||
0109: 1978-03-19T02:00:00Z unix=259120800 wall=1978-03-19T02:00:00 gap-until(1978-03-19T03:00:00) type=7 +01 IST
|
||||
0110: 1978-10-29T02:00:00Z unix=278474400 wall=1978-10-29T02:00:00 fold-until(1978-10-29T03:00:00) type=6 +00 GMT dst
|
||||
0111: 1979-03-18T02:00:00Z unix=290570400 wall=1979-03-18T02:00:00 gap-until(1979-03-18T03:00:00) type=7 +01 IST
|
||||
0112: 1979-10-28T02:00:00Z unix=309924000 wall=1979-10-28T02:00:00 fold-until(1979-10-28T03:00:00) type=6 +00 GMT dst
|
||||
0113: 1980-03-16T02:00:00Z unix=322020000 wall=1980-03-16T02:00:00 gap-until(1980-03-16T03:00:00) type=7 +01 IST
|
||||
0114: 1980-10-26T02:00:00Z unix=341373600 wall=1980-10-26T02:00:00 fold-until(1980-10-26T03:00:00) type=6 +00 GMT dst
|
||||
0115: 1981-03-29T01:00:00Z unix=354675600 wall=1981-03-29T01:00:00 gap-until(1981-03-29T02:00:00) type=7 +01 IST
|
||||
0116: 1981-10-25T01:00:00Z unix=372819600 wall=1981-10-25T01:00:00 fold-until(1981-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0117: 1982-03-28T01:00:00Z unix=386125200 wall=1982-03-28T01:00:00 gap-until(1982-03-28T02:00:00) type=7 +01 IST
|
||||
0118: 1982-10-24T01:00:00Z unix=404269200 wall=1982-10-24T01:00:00 fold-until(1982-10-24T02:00:00) type=6 +00 GMT dst
|
||||
0119: 1983-03-27T01:00:00Z unix=417574800 wall=1983-03-27T01:00:00 gap-until(1983-03-27T02:00:00) type=7 +01 IST
|
||||
0120: 1983-10-23T01:00:00Z unix=435718800 wall=1983-10-23T01:00:00 fold-until(1983-10-23T02:00:00) type=6 +00 GMT dst
|
||||
0121: 1984-03-25T01:00:00Z unix=449024400 wall=1984-03-25T01:00:00 gap-until(1984-03-25T02:00:00) type=7 +01 IST
|
||||
0122: 1984-10-28T01:00:00Z unix=467773200 wall=1984-10-28T01:00:00 fold-until(1984-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0123: 1985-03-31T01:00:00Z unix=481078800 wall=1985-03-31T01:00:00 gap-until(1985-03-31T02:00:00) type=7 +01 IST
|
||||
0124: 1985-10-27T01:00:00Z unix=499222800 wall=1985-10-27T01:00:00 fold-until(1985-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0125: 1986-03-30T01:00:00Z unix=512528400 wall=1986-03-30T01:00:00 gap-until(1986-03-30T02:00:00) type=7 +01 IST
|
||||
0126: 1986-10-26T01:00:00Z unix=530672400 wall=1986-10-26T01:00:00 fold-until(1986-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0127: 1987-03-29T01:00:00Z unix=543978000 wall=1987-03-29T01:00:00 gap-until(1987-03-29T02:00:00) type=7 +01 IST
|
||||
0128: 1987-10-25T01:00:00Z unix=562122000 wall=1987-10-25T01:00:00 fold-until(1987-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0129: 1988-03-27T01:00:00Z unix=575427600 wall=1988-03-27T01:00:00 gap-until(1988-03-27T02:00:00) type=7 +01 IST
|
||||
0130: 1988-10-23T01:00:00Z unix=593571600 wall=1988-10-23T01:00:00 fold-until(1988-10-23T02:00:00) type=6 +00 GMT dst
|
||||
0131: 1989-03-26T01:00:00Z unix=606877200 wall=1989-03-26T01:00:00 gap-until(1989-03-26T02:00:00) type=7 +01 IST
|
||||
0132: 1989-10-29T01:00:00Z unix=625626000 wall=1989-10-29T01:00:00 fold-until(1989-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0133: 1990-03-25T01:00:00Z unix=638326800 wall=1990-03-25T01:00:00 gap-until(1990-03-25T02:00:00) type=7 +01 IST
|
||||
0134: 1990-10-28T01:00:00Z unix=657075600 wall=1990-10-28T01:00:00 fold-until(1990-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0135: 1991-03-31T01:00:00Z unix=670381200 wall=1991-03-31T01:00:00 gap-until(1991-03-31T02:00:00) type=7 +01 IST
|
||||
0136: 1991-10-27T01:00:00Z unix=688525200 wall=1991-10-27T01:00:00 fold-until(1991-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0137: 1992-03-29T01:00:00Z unix=701830800 wall=1992-03-29T01:00:00 gap-until(1992-03-29T02:00:00) type=7 +01 IST
|
||||
0138: 1992-10-25T01:00:00Z unix=719974800 wall=1992-10-25T01:00:00 fold-until(1992-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0139: 1993-03-28T01:00:00Z unix=733280400 wall=1993-03-28T01:00:00 gap-until(1993-03-28T02:00:00) type=7 +01 IST
|
||||
0140: 1993-10-24T01:00:00Z unix=751424400 wall=1993-10-24T01:00:00 fold-until(1993-10-24T02:00:00) type=6 +00 GMT dst
|
||||
0141: 1994-03-27T01:00:00Z unix=764730000 wall=1994-03-27T01:00:00 gap-until(1994-03-27T02:00:00) type=7 +01 IST
|
||||
0142: 1994-10-23T01:00:00Z unix=782874000 wall=1994-10-23T01:00:00 fold-until(1994-10-23T02:00:00) type=6 +00 GMT dst
|
||||
0143: 1995-03-26T01:00:00Z unix=796179600 wall=1995-03-26T01:00:00 gap-until(1995-03-26T02:00:00) type=7 +01 IST
|
||||
0144: 1995-10-22T01:00:00Z unix=814323600 wall=1995-10-22T01:00:00 fold-until(1995-10-22T02:00:00) type=6 +00 GMT dst
|
||||
0145: 1996-03-31T01:00:00Z unix=828234000 wall=1996-03-31T01:00:00 gap-until(1996-03-31T02:00:00) type=7 +01 IST
|
||||
0146: 1996-10-27T01:00:00Z unix=846378000 wall=1996-10-27T01:00:00 fold-until(1996-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0147: 1997-03-30T01:00:00Z unix=859683600 wall=1997-03-30T01:00:00 gap-until(1997-03-30T02:00:00) type=7 +01 IST
|
||||
0148: 1997-10-26T01:00:00Z unix=877827600 wall=1997-10-26T01:00:00 fold-until(1997-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0149: 1998-03-29T01:00:00Z unix=891133200 wall=1998-03-29T01:00:00 gap-until(1998-03-29T02:00:00) type=7 +01 IST
|
||||
0150: 1998-10-25T01:00:00Z unix=909277200 wall=1998-10-25T01:00:00 fold-until(1998-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0151: 1999-03-28T01:00:00Z unix=922582800 wall=1999-03-28T01:00:00 gap-until(1999-03-28T02:00:00) type=7 +01 IST
|
||||
0152: 1999-10-31T01:00:00Z unix=941331600 wall=1999-10-31T01:00:00 fold-until(1999-10-31T02:00:00) type=6 +00 GMT dst
|
||||
0153: 2000-03-26T01:00:00Z unix=954032400 wall=2000-03-26T01:00:00 gap-until(2000-03-26T02:00:00) type=7 +01 IST
|
||||
0154: 2000-10-29T01:00:00Z unix=972781200 wall=2000-10-29T01:00:00 fold-until(2000-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0155: 2001-03-25T01:00:00Z unix=985482000 wall=2001-03-25T01:00:00 gap-until(2001-03-25T02:00:00) type=7 +01 IST
|
||||
0156: 2001-10-28T01:00:00Z unix=1004230800 wall=2001-10-28T01:00:00 fold-until(2001-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0157: 2002-03-31T01:00:00Z unix=1017536400 wall=2002-03-31T01:00:00 gap-until(2002-03-31T02:00:00) type=7 +01 IST
|
||||
0158: 2002-10-27T01:00:00Z unix=1035680400 wall=2002-10-27T01:00:00 fold-until(2002-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0159: 2003-03-30T01:00:00Z unix=1048986000 wall=2003-03-30T01:00:00 gap-until(2003-03-30T02:00:00) type=7 +01 IST
|
||||
0160: 2003-10-26T01:00:00Z unix=1067130000 wall=2003-10-26T01:00:00 fold-until(2003-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0161: 2004-03-28T01:00:00Z unix=1080435600 wall=2004-03-28T01:00:00 gap-until(2004-03-28T02:00:00) type=7 +01 IST
|
||||
0162: 2004-10-31T01:00:00Z unix=1099184400 wall=2004-10-31T01:00:00 fold-until(2004-10-31T02:00:00) type=6 +00 GMT dst
|
||||
0163: 2005-03-27T01:00:00Z unix=1111885200 wall=2005-03-27T01:00:00 gap-until(2005-03-27T02:00:00) type=7 +01 IST
|
||||
0164: 2005-10-30T01:00:00Z unix=1130634000 wall=2005-10-30T01:00:00 fold-until(2005-10-30T02:00:00) type=6 +00 GMT dst
|
||||
0165: 2006-03-26T01:00:00Z unix=1143334800 wall=2006-03-26T01:00:00 gap-until(2006-03-26T02:00:00) type=7 +01 IST
|
||||
0166: 2006-10-29T01:00:00Z unix=1162083600 wall=2006-10-29T01:00:00 fold-until(2006-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0167: 2007-03-25T01:00:00Z unix=1174784400 wall=2007-03-25T01:00:00 gap-until(2007-03-25T02:00:00) type=7 +01 IST
|
||||
0168: 2007-10-28T01:00:00Z unix=1193533200 wall=2007-10-28T01:00:00 fold-until(2007-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0169: 2008-03-30T01:00:00Z unix=1206838800 wall=2008-03-30T01:00:00 gap-until(2008-03-30T02:00:00) type=7 +01 IST
|
||||
0170: 2008-10-26T01:00:00Z unix=1224982800 wall=2008-10-26T01:00:00 fold-until(2008-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0171: 2009-03-29T01:00:00Z unix=1238288400 wall=2009-03-29T01:00:00 gap-until(2009-03-29T02:00:00) type=7 +01 IST
|
||||
0172: 2009-10-25T01:00:00Z unix=1256432400 wall=2009-10-25T01:00:00 fold-until(2009-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0173: 2010-03-28T01:00:00Z unix=1269738000 wall=2010-03-28T01:00:00 gap-until(2010-03-28T02:00:00) type=7 +01 IST
|
||||
0174: 2010-10-31T01:00:00Z unix=1288486800 wall=2010-10-31T01:00:00 fold-until(2010-10-31T02:00:00) type=6 +00 GMT dst
|
||||
0175: 2011-03-27T01:00:00Z unix=1301187600 wall=2011-03-27T01:00:00 gap-until(2011-03-27T02:00:00) type=7 +01 IST
|
||||
0176: 2011-10-30T01:00:00Z unix=1319936400 wall=2011-10-30T01:00:00 fold-until(2011-10-30T02:00:00) type=6 +00 GMT dst
|
||||
0177: 2012-03-25T01:00:00Z unix=1332637200 wall=2012-03-25T01:00:00 gap-until(2012-03-25T02:00:00) type=7 +01 IST
|
||||
0178: 2012-10-28T01:00:00Z unix=1351386000 wall=2012-10-28T01:00:00 fold-until(2012-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0179: 2013-03-31T01:00:00Z unix=1364691600 wall=2013-03-31T01:00:00 gap-until(2013-03-31T02:00:00) type=7 +01 IST
|
||||
0180: 2013-10-27T01:00:00Z unix=1382835600 wall=2013-10-27T01:00:00 fold-until(2013-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0181: 2014-03-30T01:00:00Z unix=1396141200 wall=2014-03-30T01:00:00 gap-until(2014-03-30T02:00:00) type=7 +01 IST
|
||||
0182: 2014-10-26T01:00:00Z unix=1414285200 wall=2014-10-26T01:00:00 fold-until(2014-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0183: 2015-03-29T01:00:00Z unix=1427590800 wall=2015-03-29T01:00:00 gap-until(2015-03-29T02:00:00) type=7 +01 IST
|
||||
0184: 2015-10-25T01:00:00Z unix=1445734800 wall=2015-10-25T01:00:00 fold-until(2015-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0185: 2016-03-27T01:00:00Z unix=1459040400 wall=2016-03-27T01:00:00 gap-until(2016-03-27T02:00:00) type=7 +01 IST
|
||||
0186: 2016-10-30T01:00:00Z unix=1477789200 wall=2016-10-30T01:00:00 fold-until(2016-10-30T02:00:00) type=6 +00 GMT dst
|
||||
0187: 2017-03-26T01:00:00Z unix=1490490000 wall=2017-03-26T01:00:00 gap-until(2017-03-26T02:00:00) type=7 +01 IST
|
||||
0188: 2017-10-29T01:00:00Z unix=1509238800 wall=2017-10-29T01:00:00 fold-until(2017-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0189: 2018-03-25T01:00:00Z unix=1521939600 wall=2018-03-25T01:00:00 gap-until(2018-03-25T02:00:00) type=7 +01 IST
|
||||
0190: 2018-10-28T01:00:00Z unix=1540688400 wall=2018-10-28T01:00:00 fold-until(2018-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0191: 2019-03-31T01:00:00Z unix=1553994000 wall=2019-03-31T01:00:00 gap-until(2019-03-31T02:00:00) type=7 +01 IST
|
||||
0192: 2019-10-27T01:00:00Z unix=1572138000 wall=2019-10-27T01:00:00 fold-until(2019-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0193: 2020-03-29T01:00:00Z unix=1585443600 wall=2020-03-29T01:00:00 gap-until(2020-03-29T02:00:00) type=7 +01 IST
|
||||
0194: 2020-10-25T01:00:00Z unix=1603587600 wall=2020-10-25T01:00:00 fold-until(2020-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0195: 2021-03-28T01:00:00Z unix=1616893200 wall=2021-03-28T01:00:00 gap-until(2021-03-28T02:00:00) type=7 +01 IST
|
||||
0196: 2021-10-31T01:00:00Z unix=1635642000 wall=2021-10-31T01:00:00 fold-until(2021-10-31T02:00:00) type=6 +00 GMT dst
|
||||
0197: 2022-03-27T01:00:00Z unix=1648342800 wall=2022-03-27T01:00:00 gap-until(2022-03-27T02:00:00) type=7 +01 IST
|
||||
0198: 2022-10-30T01:00:00Z unix=1667091600 wall=2022-10-30T01:00:00 fold-until(2022-10-30T02:00:00) type=6 +00 GMT dst
|
||||
0199: 2023-03-26T01:00:00Z unix=1679792400 wall=2023-03-26T01:00:00 gap-until(2023-03-26T02:00:00) type=7 +01 IST
|
||||
0200: 2023-10-29T01:00:00Z unix=1698541200 wall=2023-10-29T01:00:00 fold-until(2023-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0201: 2024-03-31T01:00:00Z unix=1711846800 wall=2024-03-31T01:00:00 gap-until(2024-03-31T02:00:00) type=7 +01 IST
|
||||
0202: 2024-10-27T01:00:00Z unix=1729990800 wall=2024-10-27T01:00:00 fold-until(2024-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0203: 2025-03-30T01:00:00Z unix=1743296400 wall=2025-03-30T01:00:00 gap-until(2025-03-30T02:00:00) type=7 +01 IST
|
||||
0204: 2025-10-26T01:00:00Z unix=1761440400 wall=2025-10-26T01:00:00 fold-until(2025-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0205: 2026-03-29T01:00:00Z unix=1774746000 wall=2026-03-29T01:00:00 gap-until(2026-03-29T02:00:00) type=7 +01 IST
|
||||
0206: 2026-10-25T01:00:00Z unix=1792890000 wall=2026-10-25T01:00:00 fold-until(2026-10-25T02:00:00) type=6 +00 GMT dst
|
||||
0207: 2027-03-28T01:00:00Z unix=1806195600 wall=2027-03-28T01:00:00 gap-until(2027-03-28T02:00:00) type=7 +01 IST
|
||||
0208: 2027-10-31T01:00:00Z unix=1824944400 wall=2027-10-31T01:00:00 fold-until(2027-10-31T02:00:00) type=6 +00 GMT dst
|
||||
0209: 2028-03-26T01:00:00Z unix=1837645200 wall=2028-03-26T01:00:00 gap-until(2028-03-26T02:00:00) type=7 +01 IST
|
||||
0210: 2028-10-29T01:00:00Z unix=1856394000 wall=2028-10-29T01:00:00 fold-until(2028-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0211: 2029-03-25T01:00:00Z unix=1869094800 wall=2029-03-25T01:00:00 gap-until(2029-03-25T02:00:00) type=7 +01 IST
|
||||
0212: 2029-10-28T01:00:00Z unix=1887843600 wall=2029-10-28T01:00:00 fold-until(2029-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0213: 2030-03-31T01:00:00Z unix=1901149200 wall=2030-03-31T01:00:00 gap-until(2030-03-31T02:00:00) type=7 +01 IST
|
||||
0214: 2030-10-27T01:00:00Z unix=1919293200 wall=2030-10-27T01:00:00 fold-until(2030-10-27T02:00:00) type=6 +00 GMT dst
|
||||
0215: 2031-03-30T01:00:00Z unix=1932598800 wall=2031-03-30T01:00:00 gap-until(2031-03-30T02:00:00) type=7 +01 IST
|
||||
0216: 2031-10-26T01:00:00Z unix=1950742800 wall=2031-10-26T01:00:00 fold-until(2031-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0217: 2032-03-28T01:00:00Z unix=1964048400 wall=2032-03-28T01:00:00 gap-until(2032-03-28T02:00:00) type=7 +01 IST
|
||||
0218: 2032-10-31T01:00:00Z unix=1982797200 wall=2032-10-31T01:00:00 fold-until(2032-10-31T02:00:00) type=6 +00 GMT dst
|
||||
0219: 2033-03-27T01:00:00Z unix=1995498000 wall=2033-03-27T01:00:00 gap-until(2033-03-27T02:00:00) type=7 +01 IST
|
||||
0220: 2033-10-30T01:00:00Z unix=2014246800 wall=2033-10-30T01:00:00 fold-until(2033-10-30T02:00:00) type=6 +00 GMT dst
|
||||
0221: 2034-03-26T01:00:00Z unix=2026947600 wall=2034-03-26T01:00:00 gap-until(2034-03-26T02:00:00) type=7 +01 IST
|
||||
0222: 2034-10-29T01:00:00Z unix=2045696400 wall=2034-10-29T01:00:00 fold-until(2034-10-29T02:00:00) type=6 +00 GMT dst
|
||||
0223: 2035-03-25T01:00:00Z unix=2058397200 wall=2035-03-25T01:00:00 gap-until(2035-03-25T02:00:00) type=7 +01 IST
|
||||
0224: 2035-10-28T01:00:00Z unix=2077146000 wall=2035-10-28T01:00:00 fold-until(2035-10-28T02:00:00) type=6 +00 GMT dst
|
||||
0225: 2036-03-30T01:00:00Z unix=2090451600 wall=2036-03-30T01:00:00 gap-until(2036-03-30T02:00:00) type=7 +01 IST
|
||||
0226: 2036-10-26T01:00:00Z unix=2108595600 wall=2036-10-26T01:00:00 fold-until(2036-10-26T02:00:00) type=6 +00 GMT dst
|
||||
0227: 2037-03-29T01:00:00Z unix=2121901200 wall=2037-03-29T01:00:00 gap-until(2037-03-29T02:00:00) type=7 +01 IST
|
||||
0228: 2037-10-25T01:00:00Z unix=2140045200 wall=2037-10-25T01:00:00 fold-until(2037-10-25T02:00:00) type=6 +00 GMT dst
|
||||
POSIX TIME ZONE STRING
|
||||
IST-1GMT0,M10.5.0,M3.5.0/1
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse_v1())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
Pacific/Honolulu
|
||||
LOCAL TIME TYPES
|
||||
000: offset=-10:31:26 designation=LMT indicator=local/wall
|
||||
001: offset=-10:30 designation=HST indicator=local/wall
|
||||
002: offset=-09:30 designation=HDT dst indicator=local/wall
|
||||
003: offset=-09:30 designation=HWT dst indicator=local/wall
|
||||
004: offset=-09:30 designation=HPT dst indicator=ut/std
|
||||
005: offset=-10 designation=HST indicator=local/wall
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-01T15:28:33 unambiguous type=0 -10:31:26 LMT
|
||||
0001: 1901-12-13T20:45:52Z unix=-2147483648 wall=1901-12-13T10:14:26 gap-until(1901-12-13T10:15:52) type=1 -10:30 HST
|
||||
0002: 1933-04-30T12:30:00Z unix=-1157283000 wall=1933-04-30T02:00:00 gap-until(1933-04-30T03:00:00) type=2 -09:30 HDT dst
|
||||
0003: 1933-05-21T21:30:00Z unix=-1155436200 wall=1933-05-21T11:00:00 fold-until(1933-05-21T12:00:00) type=1 -10:30 HST
|
||||
0004: 1942-02-09T12:30:00Z unix=-880198200 wall=1942-02-09T02:00:00 gap-until(1942-02-09T03:00:00) type=3 -09:30 HWT dst
|
||||
0005: 1945-08-14T23:00:00Z unix=-769395600 wall=1945-08-14T13:30:00 unambiguous type=4 -09:30 HPT dst
|
||||
0006: 1945-09-30T11:30:00Z unix=-765376200 wall=1945-09-30T01:00:00 fold-until(1945-09-30T02:00:00) type=1 -10:30 HST
|
||||
0007: 1947-06-08T12:30:00Z unix=-712150200 wall=1947-06-08T02:00:00 gap-until(1947-06-08T02:30:00) type=5 -10 HST
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
Pacific/Honolulu
|
||||
LOCAL TIME TYPES
|
||||
000: offset=-10:31:26 designation=LMT indicator=local/wall
|
||||
001: offset=-10:30 designation=HST indicator=local/wall
|
||||
002: offset=-09:30 designation=HDT dst indicator=local/wall
|
||||
003: offset=-09:30 designation=HWT dst indicator=local/wall
|
||||
004: offset=-09:30 designation=HPT dst indicator=ut/std
|
||||
005: offset=-10 designation=HST indicator=local/wall
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-01T15:28:33 unambiguous type=0 -10:31:26 LMT
|
||||
0001: 1896-01-13T22:31:26Z unix=-2334101314 wall=1896-01-13T12:00:00 gap-until(1896-01-13T12:01:26) type=1 -10:30 HST
|
||||
0002: 1933-04-30T12:30:00Z unix=-1157283000 wall=1933-04-30T02:00:00 gap-until(1933-04-30T03:00:00) type=2 -09:30 HDT dst
|
||||
0003: 1933-05-21T21:30:00Z unix=-1155436200 wall=1933-05-21T11:00:00 fold-until(1933-05-21T12:00:00) type=1 -10:30 HST
|
||||
0004: 1942-02-09T12:30:00Z unix=-880198200 wall=1942-02-09T02:00:00 gap-until(1942-02-09T03:00:00) type=3 -09:30 HWT dst
|
||||
0005: 1945-08-14T23:00:00Z unix=-769395600 wall=1945-08-14T13:30:00 unambiguous type=4 -09:30 HPT dst
|
||||
0006: 1945-09-30T11:30:00Z unix=-765376200 wall=1945-09-30T01:00:00 fold-until(1945-09-30T02:00:00) type=1 -10:30 HST
|
||||
0007: 1947-06-08T12:30:00Z unix=-712150200 wall=1947-06-08T02:00:00 gap-until(1947-06-08T02:30:00) type=5 -10 HST
|
||||
POSIX TIME ZONE STRING
|
||||
HST10
|
||||
|
|
@ -0,0 +1,279 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse_v1())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
right/America/New_York
|
||||
LOCAL TIME TYPES
|
||||
000: offset=-04:56:02 designation=LMT indicator=local/wall
|
||||
001: offset=-04 designation=EDT dst indicator=local/wall
|
||||
002: offset=-05 designation=EST indicator=local/wall
|
||||
003: offset=-05 designation=EST indicator=ut/std
|
||||
004: offset=-04 designation=EWT dst indicator=local/wall
|
||||
005: offset=-04 designation=EPT dst indicator=ut/std
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-01T21:03:57 unambiguous type=0 -04:56:02 LMT
|
||||
0001: 1901-12-13T20:45:52Z unix=-2147483648 wall=1901-12-13T15:45:52 fold-until(1901-12-13T15:49:50) type=3 -05 EST
|
||||
0002: 1918-03-31T07:00:00Z unix=-1633280400 wall=1918-03-31T02:00:00 gap-until(1918-03-31T03:00:00) type=1 -04 EDT dst
|
||||
0003: 1918-10-27T06:00:00Z unix=-1615140000 wall=1918-10-27T01:00:00 fold-until(1918-10-27T02:00:00) type=2 -05 EST
|
||||
0004: 1919-03-30T07:00:00Z unix=-1601830800 wall=1919-03-30T02:00:00 gap-until(1919-03-30T03:00:00) type=1 -04 EDT dst
|
||||
0005: 1919-10-26T06:00:00Z unix=-1583690400 wall=1919-10-26T01:00:00 fold-until(1919-10-26T02:00:00) type=2 -05 EST
|
||||
0006: 1920-03-28T07:00:00Z unix=-1570381200 wall=1920-03-28T02:00:00 gap-until(1920-03-28T03:00:00) type=1 -04 EDT dst
|
||||
0007: 1920-10-31T06:00:00Z unix=-1551636000 wall=1920-10-31T01:00:00 fold-until(1920-10-31T02:00:00) type=2 -05 EST
|
||||
0008: 1921-04-24T07:00:00Z unix=-1536512400 wall=1921-04-24T02:00:00 gap-until(1921-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0009: 1921-09-25T06:00:00Z unix=-1523210400 wall=1921-09-25T01:00:00 fold-until(1921-09-25T02:00:00) type=2 -05 EST
|
||||
0010: 1922-04-30T07:00:00Z unix=-1504458000 wall=1922-04-30T02:00:00 gap-until(1922-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0011: 1922-09-24T06:00:00Z unix=-1491760800 wall=1922-09-24T01:00:00 fold-until(1922-09-24T02:00:00) type=2 -05 EST
|
||||
0012: 1923-04-29T07:00:00Z unix=-1473008400 wall=1923-04-29T02:00:00 gap-until(1923-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0013: 1923-09-30T06:00:00Z unix=-1459706400 wall=1923-09-30T01:00:00 fold-until(1923-09-30T02:00:00) type=2 -05 EST
|
||||
0014: 1924-04-27T07:00:00Z unix=-1441558800 wall=1924-04-27T02:00:00 gap-until(1924-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0015: 1924-09-28T06:00:00Z unix=-1428256800 wall=1924-09-28T01:00:00 fold-until(1924-09-28T02:00:00) type=2 -05 EST
|
||||
0016: 1925-04-26T07:00:00Z unix=-1410109200 wall=1925-04-26T02:00:00 gap-until(1925-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0017: 1925-09-27T06:00:00Z unix=-1396807200 wall=1925-09-27T01:00:00 fold-until(1925-09-27T02:00:00) type=2 -05 EST
|
||||
0018: 1926-04-25T07:00:00Z unix=-1378659600 wall=1926-04-25T02:00:00 gap-until(1926-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0019: 1926-09-26T06:00:00Z unix=-1365357600 wall=1926-09-26T01:00:00 fold-until(1926-09-26T02:00:00) type=2 -05 EST
|
||||
0020: 1927-04-24T07:00:00Z unix=-1347210000 wall=1927-04-24T02:00:00 gap-until(1927-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0021: 1927-09-25T06:00:00Z unix=-1333908000 wall=1927-09-25T01:00:00 fold-until(1927-09-25T02:00:00) type=2 -05 EST
|
||||
0022: 1928-04-29T07:00:00Z unix=-1315155600 wall=1928-04-29T02:00:00 gap-until(1928-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0023: 1928-09-30T06:00:00Z unix=-1301853600 wall=1928-09-30T01:00:00 fold-until(1928-09-30T02:00:00) type=2 -05 EST
|
||||
0024: 1929-04-28T07:00:00Z unix=-1283706000 wall=1929-04-28T02:00:00 gap-until(1929-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0025: 1929-09-29T06:00:00Z unix=-1270404000 wall=1929-09-29T01:00:00 fold-until(1929-09-29T02:00:00) type=2 -05 EST
|
||||
0026: 1930-04-27T07:00:00Z unix=-1252256400 wall=1930-04-27T02:00:00 gap-until(1930-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0027: 1930-09-28T06:00:00Z unix=-1238954400 wall=1930-09-28T01:00:00 fold-until(1930-09-28T02:00:00) type=2 -05 EST
|
||||
0028: 1931-04-26T07:00:00Z unix=-1220806800 wall=1931-04-26T02:00:00 gap-until(1931-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0029: 1931-09-27T06:00:00Z unix=-1207504800 wall=1931-09-27T01:00:00 fold-until(1931-09-27T02:00:00) type=2 -05 EST
|
||||
0030: 1932-04-24T07:00:00Z unix=-1189357200 wall=1932-04-24T02:00:00 gap-until(1932-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0031: 1932-09-25T06:00:00Z unix=-1176055200 wall=1932-09-25T01:00:00 fold-until(1932-09-25T02:00:00) type=2 -05 EST
|
||||
0032: 1933-04-30T07:00:00Z unix=-1157302800 wall=1933-04-30T02:00:00 gap-until(1933-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0033: 1933-09-24T06:00:00Z unix=-1144605600 wall=1933-09-24T01:00:00 fold-until(1933-09-24T02:00:00) type=2 -05 EST
|
||||
0034: 1934-04-29T07:00:00Z unix=-1125853200 wall=1934-04-29T02:00:00 gap-until(1934-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0035: 1934-09-30T06:00:00Z unix=-1112551200 wall=1934-09-30T01:00:00 fold-until(1934-09-30T02:00:00) type=2 -05 EST
|
||||
0036: 1935-04-28T07:00:00Z unix=-1094403600 wall=1935-04-28T02:00:00 gap-until(1935-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0037: 1935-09-29T06:00:00Z unix=-1081101600 wall=1935-09-29T01:00:00 fold-until(1935-09-29T02:00:00) type=2 -05 EST
|
||||
0038: 1936-04-26T07:00:00Z unix=-1062954000 wall=1936-04-26T02:00:00 gap-until(1936-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0039: 1936-09-27T06:00:00Z unix=-1049652000 wall=1936-09-27T01:00:00 fold-until(1936-09-27T02:00:00) type=2 -05 EST
|
||||
0040: 1937-04-25T07:00:00Z unix=-1031504400 wall=1937-04-25T02:00:00 gap-until(1937-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0041: 1937-09-26T06:00:00Z unix=-1018202400 wall=1937-09-26T01:00:00 fold-until(1937-09-26T02:00:00) type=2 -05 EST
|
||||
0042: 1938-04-24T07:00:00Z unix=-1000054800 wall=1938-04-24T02:00:00 gap-until(1938-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0043: 1938-09-25T06:00:00Z unix=-986752800 wall=1938-09-25T01:00:00 fold-until(1938-09-25T02:00:00) type=2 -05 EST
|
||||
0044: 1939-04-30T07:00:00Z unix=-968000400 wall=1939-04-30T02:00:00 gap-until(1939-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0045: 1939-09-24T06:00:00Z unix=-955303200 wall=1939-09-24T01:00:00 fold-until(1939-09-24T02:00:00) type=2 -05 EST
|
||||
0046: 1940-04-28T07:00:00Z unix=-936550800 wall=1940-04-28T02:00:00 gap-until(1940-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0047: 1940-09-29T06:00:00Z unix=-923248800 wall=1940-09-29T01:00:00 fold-until(1940-09-29T02:00:00) type=2 -05 EST
|
||||
0048: 1941-04-27T07:00:00Z unix=-905101200 wall=1941-04-27T02:00:00 gap-until(1941-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0049: 1941-09-28T06:00:00Z unix=-891799200 wall=1941-09-28T01:00:00 fold-until(1941-09-28T02:00:00) type=2 -05 EST
|
||||
0050: 1942-02-09T07:00:00Z unix=-880218000 wall=1942-02-09T02:00:00 gap-until(1942-02-09T03:00:00) type=4 -04 EWT dst
|
||||
0051: 1945-08-14T23:00:00Z unix=-769395600 wall=1945-08-14T19:00:00 unambiguous type=5 -04 EPT dst
|
||||
0052: 1945-09-30T06:00:00Z unix=-765396000 wall=1945-09-30T01:00:00 fold-until(1945-09-30T02:00:00) type=2 -05 EST
|
||||
0053: 1946-04-28T07:00:00Z unix=-747248400 wall=1946-04-28T02:00:00 gap-until(1946-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0054: 1946-09-29T06:00:00Z unix=-733946400 wall=1946-09-29T01:00:00 fold-until(1946-09-29T02:00:00) type=2 -05 EST
|
||||
0055: 1947-04-27T07:00:00Z unix=-715798800 wall=1947-04-27T02:00:00 gap-until(1947-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0056: 1947-09-28T06:00:00Z unix=-702496800 wall=1947-09-28T01:00:00 fold-until(1947-09-28T02:00:00) type=2 -05 EST
|
||||
0057: 1948-04-25T07:00:00Z unix=-684349200 wall=1948-04-25T02:00:00 gap-until(1948-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0058: 1948-09-26T06:00:00Z unix=-671047200 wall=1948-09-26T01:00:00 fold-until(1948-09-26T02:00:00) type=2 -05 EST
|
||||
0059: 1949-04-24T07:00:00Z unix=-652899600 wall=1949-04-24T02:00:00 gap-until(1949-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0060: 1949-09-25T06:00:00Z unix=-639597600 wall=1949-09-25T01:00:00 fold-until(1949-09-25T02:00:00) type=2 -05 EST
|
||||
0061: 1950-04-30T07:00:00Z unix=-620845200 wall=1950-04-30T02:00:00 gap-until(1950-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0062: 1950-09-24T06:00:00Z unix=-608148000 wall=1950-09-24T01:00:00 fold-until(1950-09-24T02:00:00) type=2 -05 EST
|
||||
0063: 1951-04-29T07:00:00Z unix=-589395600 wall=1951-04-29T02:00:00 gap-until(1951-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0064: 1951-09-30T06:00:00Z unix=-576093600 wall=1951-09-30T01:00:00 fold-until(1951-09-30T02:00:00) type=2 -05 EST
|
||||
0065: 1952-04-27T07:00:00Z unix=-557946000 wall=1952-04-27T02:00:00 gap-until(1952-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0066: 1952-09-28T06:00:00Z unix=-544644000 wall=1952-09-28T01:00:00 fold-until(1952-09-28T02:00:00) type=2 -05 EST
|
||||
0067: 1953-04-26T07:00:00Z unix=-526496400 wall=1953-04-26T02:00:00 gap-until(1953-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0068: 1953-09-27T06:00:00Z unix=-513194400 wall=1953-09-27T01:00:00 fold-until(1953-09-27T02:00:00) type=2 -05 EST
|
||||
0069: 1954-04-25T07:00:00Z unix=-495046800 wall=1954-04-25T02:00:00 gap-until(1954-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0070: 1954-09-26T06:00:00Z unix=-481744800 wall=1954-09-26T01:00:00 fold-until(1954-09-26T02:00:00) type=2 -05 EST
|
||||
0071: 1955-04-24T07:00:00Z unix=-463597200 wall=1955-04-24T02:00:00 gap-until(1955-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0072: 1955-10-30T06:00:00Z unix=-447271200 wall=1955-10-30T01:00:00 fold-until(1955-10-30T02:00:00) type=2 -05 EST
|
||||
0073: 1956-04-29T07:00:00Z unix=-431542800 wall=1956-04-29T02:00:00 gap-until(1956-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0074: 1956-10-28T06:00:00Z unix=-415821600 wall=1956-10-28T01:00:00 fold-until(1956-10-28T02:00:00) type=2 -05 EST
|
||||
0075: 1957-04-28T07:00:00Z unix=-400093200 wall=1957-04-28T02:00:00 gap-until(1957-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0076: 1957-10-27T06:00:00Z unix=-384372000 wall=1957-10-27T01:00:00 fold-until(1957-10-27T02:00:00) type=2 -05 EST
|
||||
0077: 1958-04-27T07:00:00Z unix=-368643600 wall=1958-04-27T02:00:00 gap-until(1958-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0078: 1958-10-26T06:00:00Z unix=-352922400 wall=1958-10-26T01:00:00 fold-until(1958-10-26T02:00:00) type=2 -05 EST
|
||||
0079: 1959-04-26T07:00:00Z unix=-337194000 wall=1959-04-26T02:00:00 gap-until(1959-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0080: 1959-10-25T06:00:00Z unix=-321472800 wall=1959-10-25T01:00:00 fold-until(1959-10-25T02:00:00) type=2 -05 EST
|
||||
0081: 1960-04-24T07:00:00Z unix=-305744400 wall=1960-04-24T02:00:00 gap-until(1960-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0082: 1960-10-30T06:00:00Z unix=-289418400 wall=1960-10-30T01:00:00 fold-until(1960-10-30T02:00:00) type=2 -05 EST
|
||||
0083: 1961-04-30T07:00:00Z unix=-273690000 wall=1961-04-30T02:00:00 gap-until(1961-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0084: 1961-10-29T06:00:00Z unix=-257968800 wall=1961-10-29T01:00:00 fold-until(1961-10-29T02:00:00) type=2 -05 EST
|
||||
0085: 1962-04-29T07:00:00Z unix=-242240400 wall=1962-04-29T02:00:00 gap-until(1962-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0086: 1962-10-28T06:00:00Z unix=-226519200 wall=1962-10-28T01:00:00 fold-until(1962-10-28T02:00:00) type=2 -05 EST
|
||||
0087: 1963-04-28T07:00:00Z unix=-210790800 wall=1963-04-28T02:00:00 gap-until(1963-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0088: 1963-10-27T06:00:00Z unix=-195069600 wall=1963-10-27T01:00:00 fold-until(1963-10-27T02:00:00) type=2 -05 EST
|
||||
0089: 1964-04-26T07:00:00Z unix=-179341200 wall=1964-04-26T02:00:00 gap-until(1964-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0090: 1964-10-25T06:00:00Z unix=-163620000 wall=1964-10-25T01:00:00 fold-until(1964-10-25T02:00:00) type=2 -05 EST
|
||||
0091: 1965-04-25T07:00:00Z unix=-147891600 wall=1965-04-25T02:00:00 gap-until(1965-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0092: 1965-10-31T06:00:00Z unix=-131565600 wall=1965-10-31T01:00:00 fold-until(1965-10-31T02:00:00) type=2 -05 EST
|
||||
0093: 1966-04-24T07:00:00Z unix=-116442000 wall=1966-04-24T02:00:00 gap-until(1966-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0094: 1966-10-30T06:00:00Z unix=-100116000 wall=1966-10-30T01:00:00 fold-until(1966-10-30T02:00:00) type=2 -05 EST
|
||||
0095: 1967-04-30T07:00:00Z unix=-84387600 wall=1967-04-30T02:00:00 gap-until(1967-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0096: 1967-10-29T06:00:00Z unix=-68666400 wall=1967-10-29T01:00:00 fold-until(1967-10-29T02:00:00) type=2 -05 EST
|
||||
0097: 1968-04-28T07:00:00Z unix=-52938000 wall=1968-04-28T02:00:00 gap-until(1968-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0098: 1968-10-27T06:00:00Z unix=-37216800 wall=1968-10-27T01:00:00 fold-until(1968-10-27T02:00:00) type=2 -05 EST
|
||||
0099: 1969-04-27T07:00:00Z unix=-21488400 wall=1969-04-27T02:00:00 gap-until(1969-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0100: 1969-10-26T06:00:00Z unix=-5767200 wall=1969-10-26T01:00:00 fold-until(1969-10-26T02:00:00) type=2 -05 EST
|
||||
0101: 1970-04-26T07:00:00Z unix=9961200 wall=1970-04-26T02:00:00 gap-until(1970-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0102: 1970-10-25T06:00:00Z unix=25682400 wall=1970-10-25T01:00:00 fold-until(1970-10-25T02:00:00) type=2 -05 EST
|
||||
0103: 1971-04-25T07:00:00Z unix=41410800 wall=1971-04-25T02:00:00 gap-until(1971-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0104: 1971-10-31T06:00:00Z unix=57736800 wall=1971-10-31T01:00:00 fold-until(1971-10-31T02:00:00) type=2 -05 EST
|
||||
0105: 1972-04-30T07:00:00Z unix=73465200 wall=1972-04-30T02:00:00 gap-until(1972-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0106: 1972-10-29T06:00:01Z unix=89186401 wall=1972-10-29T01:00:01 fold-until(1972-10-29T02:00:01) type=2 -05 EST
|
||||
0107: 1973-04-29T07:00:02Z unix=104914802 wall=1973-04-29T02:00:02 gap-until(1973-04-29T03:00:02) type=1 -04 EDT dst
|
||||
0108: 1973-10-28T06:00:02Z unix=120636002 wall=1973-10-28T01:00:02 fold-until(1973-10-28T02:00:02) type=2 -05 EST
|
||||
0109: 1974-01-06T07:00:03Z unix=126687603 wall=1974-01-06T02:00:03 gap-until(1974-01-06T03:00:03) type=1 -04 EDT dst
|
||||
0110: 1974-10-27T06:00:03Z unix=152085603 wall=1974-10-27T01:00:03 fold-until(1974-10-27T02:00:03) type=2 -05 EST
|
||||
0111: 1975-02-23T07:00:04Z unix=162370804 wall=1975-02-23T02:00:04 gap-until(1975-02-23T03:00:04) type=1 -04 EDT dst
|
||||
0112: 1975-10-26T06:00:04Z unix=183535204 wall=1975-10-26T01:00:04 fold-until(1975-10-26T02:00:04) type=2 -05 EST
|
||||
0113: 1976-04-25T07:00:05Z unix=199263605 wall=1976-04-25T02:00:05 gap-until(1976-04-25T03:00:05) type=1 -04 EDT dst
|
||||
0114: 1976-10-31T06:00:05Z unix=215589605 wall=1976-10-31T01:00:05 fold-until(1976-10-31T02:00:05) type=2 -05 EST
|
||||
0115: 1977-04-24T07:00:06Z unix=230713206 wall=1977-04-24T02:00:06 gap-until(1977-04-24T03:00:06) type=1 -04 EDT dst
|
||||
0116: 1977-10-30T06:00:06Z unix=247039206 wall=1977-10-30T01:00:06 fold-until(1977-10-30T02:00:06) type=2 -05 EST
|
||||
0117: 1978-04-30T07:00:07Z unix=262767607 wall=1978-04-30T02:00:07 gap-until(1978-04-30T03:00:07) type=1 -04 EDT dst
|
||||
0118: 1978-10-29T06:00:07Z unix=278488807 wall=1978-10-29T01:00:07 fold-until(1978-10-29T02:00:07) type=2 -05 EST
|
||||
0119: 1979-04-29T07:00:08Z unix=294217208 wall=1979-04-29T02:00:08 gap-until(1979-04-29T03:00:08) type=1 -04 EDT dst
|
||||
0120: 1979-10-28T06:00:08Z unix=309938408 wall=1979-10-28T01:00:08 fold-until(1979-10-28T02:00:08) type=2 -05 EST
|
||||
0121: 1980-04-27T07:00:09Z unix=325666809 wall=1980-04-27T02:00:09 gap-until(1980-04-27T03:00:09) type=1 -04 EDT dst
|
||||
0122: 1980-10-26T06:00:09Z unix=341388009 wall=1980-10-26T01:00:09 fold-until(1980-10-26T02:00:09) type=2 -05 EST
|
||||
0123: 1981-04-26T07:00:09Z unix=357116409 wall=1981-04-26T02:00:09 gap-until(1981-04-26T03:00:09) type=1 -04 EDT dst
|
||||
0124: 1981-10-25T06:00:10Z unix=372837610 wall=1981-10-25T01:00:10 fold-until(1981-10-25T02:00:10) type=2 -05 EST
|
||||
0125: 1982-04-25T07:00:10Z unix=388566010 wall=1982-04-25T02:00:10 gap-until(1982-04-25T03:00:10) type=1 -04 EDT dst
|
||||
0126: 1982-10-31T06:00:11Z unix=404892011 wall=1982-10-31T01:00:11 fold-until(1982-10-31T02:00:11) type=2 -05 EST
|
||||
0127: 1983-04-24T07:00:11Z unix=420015611 wall=1983-04-24T02:00:11 gap-until(1983-04-24T03:00:11) type=1 -04 EDT dst
|
||||
0128: 1983-10-30T06:00:12Z unix=436341612 wall=1983-10-30T01:00:12 fold-until(1983-10-30T02:00:12) type=2 -05 EST
|
||||
0129: 1984-04-29T07:00:12Z unix=452070012 wall=1984-04-29T02:00:12 gap-until(1984-04-29T03:00:12) type=1 -04 EDT dst
|
||||
0130: 1984-10-28T06:00:12Z unix=467791212 wall=1984-10-28T01:00:12 fold-until(1984-10-28T02:00:12) type=2 -05 EST
|
||||
0131: 1985-04-28T07:00:12Z unix=483519612 wall=1985-04-28T02:00:12 gap-until(1985-04-28T03:00:12) type=1 -04 EDT dst
|
||||
0132: 1985-10-27T06:00:13Z unix=499240813 wall=1985-10-27T01:00:13 fold-until(1985-10-27T02:00:13) type=2 -05 EST
|
||||
0133: 1986-04-27T07:00:13Z unix=514969213 wall=1986-04-27T02:00:13 gap-until(1986-04-27T03:00:13) type=1 -04 EDT dst
|
||||
0134: 1986-10-26T06:00:13Z unix=530690413 wall=1986-10-26T01:00:13 fold-until(1986-10-26T02:00:13) type=2 -05 EST
|
||||
0135: 1987-04-05T07:00:13Z unix=544604413 wall=1987-04-05T02:00:13 gap-until(1987-04-05T03:00:13) type=1 -04 EDT dst
|
||||
0136: 1987-10-25T06:00:13Z unix=562140013 wall=1987-10-25T01:00:13 fold-until(1987-10-25T02:00:13) type=2 -05 EST
|
||||
0137: 1988-04-03T07:00:14Z unix=576054014 wall=1988-04-03T02:00:14 gap-until(1988-04-03T03:00:14) type=1 -04 EDT dst
|
||||
0138: 1988-10-30T06:00:14Z unix=594194414 wall=1988-10-30T01:00:14 fold-until(1988-10-30T02:00:14) type=2 -05 EST
|
||||
0139: 1989-04-02T07:00:14Z unix=607503614 wall=1989-04-02T02:00:14 gap-until(1989-04-02T03:00:14) type=1 -04 EDT dst
|
||||
0140: 1989-10-29T06:00:14Z unix=625644014 wall=1989-10-29T01:00:14 fold-until(1989-10-29T02:00:14) type=2 -05 EST
|
||||
0141: 1990-04-01T07:00:15Z unix=638953215 wall=1990-04-01T02:00:15 gap-until(1990-04-01T03:00:15) type=1 -04 EDT dst
|
||||
0142: 1990-10-28T06:00:15Z unix=657093615 wall=1990-10-28T01:00:15 fold-until(1990-10-28T02:00:15) type=2 -05 EST
|
||||
0143: 1991-04-07T07:00:16Z unix=671007616 wall=1991-04-07T02:00:16 gap-until(1991-04-07T03:00:16) type=1 -04 EDT dst
|
||||
0144: 1991-10-27T06:00:16Z unix=688543216 wall=1991-10-27T01:00:16 fold-until(1991-10-27T02:00:16) type=2 -05 EST
|
||||
0145: 1992-04-05T07:00:16Z unix=702457216 wall=1992-04-05T02:00:16 gap-until(1992-04-05T03:00:16) type=1 -04 EDT dst
|
||||
0146: 1992-10-25T06:00:17Z unix=719992817 wall=1992-10-25T01:00:17 fold-until(1992-10-25T02:00:17) type=2 -05 EST
|
||||
0147: 1993-04-04T07:00:17Z unix=733906817 wall=1993-04-04T02:00:17 gap-until(1993-04-04T03:00:17) type=1 -04 EDT dst
|
||||
0148: 1993-10-31T06:00:18Z unix=752047218 wall=1993-10-31T01:00:18 fold-until(1993-10-31T02:00:18) type=2 -05 EST
|
||||
0149: 1994-04-03T07:00:18Z unix=765356418 wall=1994-04-03T02:00:18 gap-until(1994-04-03T03:00:18) type=1 -04 EDT dst
|
||||
0150: 1994-10-30T06:00:19Z unix=783496819 wall=1994-10-30T01:00:19 fold-until(1994-10-30T02:00:19) type=2 -05 EST
|
||||
0151: 1995-04-02T07:00:19Z unix=796806019 wall=1995-04-02T02:00:19 gap-until(1995-04-02T03:00:19) type=1 -04 EDT dst
|
||||
0152: 1995-10-29T06:00:19Z unix=814946419 wall=1995-10-29T01:00:19 fold-until(1995-10-29T02:00:19) type=2 -05 EST
|
||||
0153: 1996-04-07T07:00:20Z unix=828860420 wall=1996-04-07T02:00:20 gap-until(1996-04-07T03:00:20) type=1 -04 EDT dst
|
||||
0154: 1996-10-27T06:00:20Z unix=846396020 wall=1996-10-27T01:00:20 fold-until(1996-10-27T02:00:20) type=2 -05 EST
|
||||
0155: 1997-04-06T07:00:20Z unix=860310020 wall=1997-04-06T02:00:20 gap-until(1997-04-06T03:00:20) type=1 -04 EDT dst
|
||||
0156: 1997-10-26T06:00:21Z unix=877845621 wall=1997-10-26T01:00:21 fold-until(1997-10-26T02:00:21) type=2 -05 EST
|
||||
0157: 1998-04-05T07:00:21Z unix=891759621 wall=1998-04-05T02:00:21 gap-until(1998-04-05T03:00:21) type=1 -04 EDT dst
|
||||
0158: 1998-10-25T06:00:21Z unix=909295221 wall=1998-10-25T01:00:21 fold-until(1998-10-25T02:00:21) type=2 -05 EST
|
||||
0159: 1999-04-04T07:00:22Z unix=923209222 wall=1999-04-04T02:00:22 gap-until(1999-04-04T03:00:22) type=1 -04 EDT dst
|
||||
0160: 1999-10-31T06:00:22Z unix=941349622 wall=1999-10-31T01:00:22 fold-until(1999-10-31T02:00:22) type=2 -05 EST
|
||||
0161: 2000-04-02T07:00:22Z unix=954658822 wall=2000-04-02T02:00:22 gap-until(2000-04-02T03:00:22) type=1 -04 EDT dst
|
||||
0162: 2000-10-29T06:00:22Z unix=972799222 wall=2000-10-29T01:00:22 fold-until(2000-10-29T02:00:22) type=2 -05 EST
|
||||
0163: 2001-04-01T07:00:22Z unix=986108422 wall=2001-04-01T02:00:22 gap-until(2001-04-01T03:00:22) type=1 -04 EDT dst
|
||||
0164: 2001-10-28T06:00:22Z unix=1004248822 wall=2001-10-28T01:00:22 fold-until(2001-10-28T02:00:22) type=2 -05 EST
|
||||
0165: 2002-04-07T07:00:22Z unix=1018162822 wall=2002-04-07T02:00:22 gap-until(2002-04-07T03:00:22) type=1 -04 EDT dst
|
||||
0166: 2002-10-27T06:00:22Z unix=1035698422 wall=2002-10-27T01:00:22 fold-until(2002-10-27T02:00:22) type=2 -05 EST
|
||||
0167: 2003-04-06T07:00:22Z unix=1049612422 wall=2003-04-06T02:00:22 gap-until(2003-04-06T03:00:22) type=1 -04 EDT dst
|
||||
0168: 2003-10-26T06:00:22Z unix=1067148022 wall=2003-10-26T01:00:22 fold-until(2003-10-26T02:00:22) type=2 -05 EST
|
||||
0169: 2004-04-04T07:00:22Z unix=1081062022 wall=2004-04-04T02:00:22 gap-until(2004-04-04T03:00:22) type=1 -04 EDT dst
|
||||
0170: 2004-10-31T06:00:22Z unix=1099202422 wall=2004-10-31T01:00:22 fold-until(2004-10-31T02:00:22) type=2 -05 EST
|
||||
0171: 2005-04-03T07:00:22Z unix=1112511622 wall=2005-04-03T02:00:22 gap-until(2005-04-03T03:00:22) type=1 -04 EDT dst
|
||||
0172: 2005-10-30T06:00:22Z unix=1130652022 wall=2005-10-30T01:00:22 fold-until(2005-10-30T02:00:22) type=2 -05 EST
|
||||
0173: 2006-04-02T07:00:23Z unix=1143961223 wall=2006-04-02T02:00:23 gap-until(2006-04-02T03:00:23) type=1 -04 EDT dst
|
||||
0174: 2006-10-29T06:00:23Z unix=1162101623 wall=2006-10-29T01:00:23 fold-until(2006-10-29T02:00:23) type=2 -05 EST
|
||||
0175: 2007-03-11T07:00:23Z unix=1173596423 wall=2007-03-11T02:00:23 gap-until(2007-03-11T03:00:23) type=1 -04 EDT dst
|
||||
0176: 2007-11-04T06:00:23Z unix=1194156023 wall=2007-11-04T01:00:23 fold-until(2007-11-04T02:00:23) type=2 -05 EST
|
||||
0177: 2008-03-09T07:00:23Z unix=1205046023 wall=2008-03-09T02:00:23 gap-until(2008-03-09T03:00:23) type=1 -04 EDT dst
|
||||
0178: 2008-11-02T06:00:23Z unix=1225605623 wall=2008-11-02T01:00:23 fold-until(2008-11-02T02:00:23) type=2 -05 EST
|
||||
0179: 2009-03-08T07:00:24Z unix=1236495624 wall=2009-03-08T02:00:24 gap-until(2009-03-08T03:00:24) type=1 -04 EDT dst
|
||||
0180: 2009-11-01T06:00:24Z unix=1257055224 wall=2009-11-01T01:00:24 fold-until(2009-11-01T02:00:24) type=2 -05 EST
|
||||
0181: 2010-03-14T07:00:24Z unix=1268550024 wall=2010-03-14T02:00:24 gap-until(2010-03-14T03:00:24) type=1 -04 EDT dst
|
||||
0182: 2010-11-07T06:00:24Z unix=1289109624 wall=2010-11-07T01:00:24 fold-until(2010-11-07T02:00:24) type=2 -05 EST
|
||||
0183: 2011-03-13T07:00:24Z unix=1299999624 wall=2011-03-13T02:00:24 gap-until(2011-03-13T03:00:24) type=1 -04 EDT dst
|
||||
0184: 2011-11-06T06:00:24Z unix=1320559224 wall=2011-11-06T01:00:24 fold-until(2011-11-06T02:00:24) type=2 -05 EST
|
||||
0185: 2012-03-11T07:00:24Z unix=1331449224 wall=2012-03-11T02:00:24 gap-until(2012-03-11T03:00:24) type=1 -04 EDT dst
|
||||
0186: 2012-11-04T06:00:25Z unix=1352008825 wall=2012-11-04T01:00:25 fold-until(2012-11-04T02:00:25) type=2 -05 EST
|
||||
0187: 2013-03-10T07:00:25Z unix=1362898825 wall=2013-03-10T02:00:25 gap-until(2013-03-10T03:00:25) type=1 -04 EDT dst
|
||||
0188: 2013-11-03T06:00:25Z unix=1383458425 wall=2013-11-03T01:00:25 fold-until(2013-11-03T02:00:25) type=2 -05 EST
|
||||
0189: 2014-03-09T07:00:25Z unix=1394348425 wall=2014-03-09T02:00:25 gap-until(2014-03-09T03:00:25) type=1 -04 EDT dst
|
||||
0190: 2014-11-02T06:00:25Z unix=1414908025 wall=2014-11-02T01:00:25 fold-until(2014-11-02T02:00:25) type=2 -05 EST
|
||||
0191: 2015-03-08T07:00:25Z unix=1425798025 wall=2015-03-08T02:00:25 gap-until(2015-03-08T03:00:25) type=1 -04 EDT dst
|
||||
0192: 2015-11-01T06:00:26Z unix=1446357626 wall=2015-11-01T01:00:26 fold-until(2015-11-01T02:00:26) type=2 -05 EST
|
||||
0193: 2016-03-13T07:00:26Z unix=1457852426 wall=2016-03-13T02:00:26 gap-until(2016-03-13T03:00:26) type=1 -04 EDT dst
|
||||
0194: 2016-11-06T06:00:26Z unix=1478412026 wall=2016-11-06T01:00:26 fold-until(2016-11-06T02:00:26) type=2 -05 EST
|
||||
0195: 2017-03-12T07:00:27Z unix=1489302027 wall=2017-03-12T02:00:27 gap-until(2017-03-12T03:00:27) type=1 -04 EDT dst
|
||||
0196: 2017-11-05T06:00:27Z unix=1509861627 wall=2017-11-05T01:00:27 fold-until(2017-11-05T02:00:27) type=2 -05 EST
|
||||
0197: 2018-03-11T07:00:27Z unix=1520751627 wall=2018-03-11T02:00:27 gap-until(2018-03-11T03:00:27) type=1 -04 EDT dst
|
||||
0198: 2018-11-04T06:00:27Z unix=1541311227 wall=2018-11-04T01:00:27 fold-until(2018-11-04T02:00:27) type=2 -05 EST
|
||||
0199: 2019-03-10T07:00:27Z unix=1552201227 wall=2019-03-10T02:00:27 gap-until(2019-03-10T03:00:27) type=1 -04 EDT dst
|
||||
0200: 2019-11-03T06:00:27Z unix=1572760827 wall=2019-11-03T01:00:27 fold-until(2019-11-03T02:00:27) type=2 -05 EST
|
||||
0201: 2020-03-08T07:00:27Z unix=1583650827 wall=2020-03-08T02:00:27 gap-until(2020-03-08T03:00:27) type=1 -04 EDT dst
|
||||
0202: 2020-11-01T06:00:27Z unix=1604210427 wall=2020-11-01T01:00:27 fold-until(2020-11-01T02:00:27) type=2 -05 EST
|
||||
0203: 2021-03-14T07:00:27Z unix=1615705227 wall=2021-03-14T02:00:27 gap-until(2021-03-14T03:00:27) type=1 -04 EDT dst
|
||||
0204: 2021-11-07T06:00:27Z unix=1636264827 wall=2021-11-07T01:00:27 fold-until(2021-11-07T02:00:27) type=2 -05 EST
|
||||
0205: 2022-03-13T07:00:27Z unix=1647154827 wall=2022-03-13T02:00:27 gap-until(2022-03-13T03:00:27) type=1 -04 EDT dst
|
||||
0206: 2022-11-06T06:00:27Z unix=1667714427 wall=2022-11-06T01:00:27 fold-until(2022-11-06T02:00:27) type=2 -05 EST
|
||||
0207: 2023-03-12T07:00:27Z unix=1678604427 wall=2023-03-12T02:00:27 gap-until(2023-03-12T03:00:27) type=1 -04 EDT dst
|
||||
0208: 2023-11-05T06:00:27Z unix=1699164027 wall=2023-11-05T01:00:27 fold-until(2023-11-05T02:00:27) type=2 -05 EST
|
||||
0209: 2024-03-10T07:00:27Z unix=1710054027 wall=2024-03-10T02:00:27 gap-until(2024-03-10T03:00:27) type=1 -04 EDT dst
|
||||
0210: 2024-11-03T06:00:27Z unix=1730613627 wall=2024-11-03T01:00:27 fold-until(2024-11-03T02:00:27) type=2 -05 EST
|
||||
0211: 2025-03-09T07:00:27Z unix=1741503627 wall=2025-03-09T02:00:27 gap-until(2025-03-09T03:00:27) type=1 -04 EDT dst
|
||||
0212: 2025-11-02T06:00:27Z unix=1762063227 wall=2025-11-02T01:00:27 fold-until(2025-11-02T02:00:27) type=2 -05 EST
|
||||
0213: 2026-03-08T07:00:27Z unix=1772953227 wall=2026-03-08T02:00:27 gap-until(2026-03-08T03:00:27) type=1 -04 EDT dst
|
||||
0214: 2026-11-01T06:00:27Z unix=1793512827 wall=2026-11-01T01:00:27 fold-until(2026-11-01T02:00:27) type=2 -05 EST
|
||||
0215: 2027-03-14T07:00:27Z unix=1805007627 wall=2027-03-14T02:00:27 gap-until(2027-03-14T03:00:27) type=1 -04 EDT dst
|
||||
0216: 2027-11-07T06:00:27Z unix=1825567227 wall=2027-11-07T01:00:27 fold-until(2027-11-07T02:00:27) type=2 -05 EST
|
||||
0217: 2028-03-12T07:00:27Z unix=1836457227 wall=2028-03-12T02:00:27 gap-until(2028-03-12T03:00:27) type=1 -04 EDT dst
|
||||
0218: 2028-11-05T06:00:27Z unix=1857016827 wall=2028-11-05T01:00:27 fold-until(2028-11-05T02:00:27) type=2 -05 EST
|
||||
0219: 2029-03-11T07:00:27Z unix=1867906827 wall=2029-03-11T02:00:27 gap-until(2029-03-11T03:00:27) type=1 -04 EDT dst
|
||||
0220: 2029-11-04T06:00:27Z unix=1888466427 wall=2029-11-04T01:00:27 fold-until(2029-11-04T02:00:27) type=2 -05 EST
|
||||
0221: 2030-03-10T07:00:27Z unix=1899356427 wall=2030-03-10T02:00:27 gap-until(2030-03-10T03:00:27) type=1 -04 EDT dst
|
||||
0222: 2030-11-03T06:00:27Z unix=1919916027 wall=2030-11-03T01:00:27 fold-until(2030-11-03T02:00:27) type=2 -05 EST
|
||||
0223: 2031-03-09T07:00:27Z unix=1930806027 wall=2031-03-09T02:00:27 gap-until(2031-03-09T03:00:27) type=1 -04 EDT dst
|
||||
0224: 2031-11-02T06:00:27Z unix=1951365627 wall=2031-11-02T01:00:27 fold-until(2031-11-02T02:00:27) type=2 -05 EST
|
||||
0225: 2032-03-14T07:00:27Z unix=1962860427 wall=2032-03-14T02:00:27 gap-until(2032-03-14T03:00:27) type=1 -04 EDT dst
|
||||
0226: 2032-11-07T06:00:27Z unix=1983420027 wall=2032-11-07T01:00:27 fold-until(2032-11-07T02:00:27) type=2 -05 EST
|
||||
0227: 2033-03-13T07:00:27Z unix=1994310027 wall=2033-03-13T02:00:27 gap-until(2033-03-13T03:00:27) type=1 -04 EDT dst
|
||||
0228: 2033-11-06T06:00:27Z unix=2014869627 wall=2033-11-06T01:00:27 fold-until(2033-11-06T02:00:27) type=2 -05 EST
|
||||
0229: 2034-03-12T07:00:27Z unix=2025759627 wall=2034-03-12T02:00:27 gap-until(2034-03-12T03:00:27) type=1 -04 EDT dst
|
||||
0230: 2034-11-05T06:00:27Z unix=2046319227 wall=2034-11-05T01:00:27 fold-until(2034-11-05T02:00:27) type=2 -05 EST
|
||||
0231: 2035-03-11T07:00:27Z unix=2057209227 wall=2035-03-11T02:00:27 gap-until(2035-03-11T03:00:27) type=1 -04 EDT dst
|
||||
0232: 2035-11-04T06:00:27Z unix=2077768827 wall=2035-11-04T01:00:27 fold-until(2035-11-04T02:00:27) type=2 -05 EST
|
||||
0233: 2036-03-09T07:00:27Z unix=2088658827 wall=2036-03-09T02:00:27 gap-until(2036-03-09T03:00:27) type=1 -04 EDT dst
|
||||
0234: 2036-11-02T06:00:27Z unix=2109218427 wall=2036-11-02T01:00:27 fold-until(2036-11-02T02:00:27) type=2 -05 EST
|
||||
0235: 2037-03-08T07:00:27Z unix=2120108427 wall=2037-03-08T02:00:27 gap-until(2037-03-08T03:00:27) type=1 -04 EDT dst
|
||||
0236: 2037-11-01T06:00:27Z unix=2140668027 wall=2037-11-01T01:00:27 fold-until(2037-11-01T02:00:27) type=2 -05 EST
|
||||
LEAP SECONDS
|
||||
1972-07-01T00:00:00 correction=1
|
||||
1973-01-01T00:00:01 correction=2
|
||||
1974-01-01T00:00:02 correction=3
|
||||
1975-01-01T00:00:03 correction=4
|
||||
1976-01-01T00:00:04 correction=5
|
||||
1977-01-01T00:00:05 correction=6
|
||||
1978-01-01T00:00:06 correction=7
|
||||
1979-01-01T00:00:07 correction=8
|
||||
1980-01-01T00:00:08 correction=9
|
||||
1981-07-01T00:00:09 correction=10
|
||||
1982-07-01T00:00:10 correction=11
|
||||
1983-07-01T00:00:11 correction=12
|
||||
1985-07-01T00:00:12 correction=13
|
||||
1988-01-01T00:00:13 correction=14
|
||||
1990-01-01T00:00:14 correction=15
|
||||
1991-01-01T00:00:15 correction=16
|
||||
1992-07-01T00:00:16 correction=17
|
||||
1993-07-01T00:00:17 correction=18
|
||||
1994-07-01T00:00:18 correction=19
|
||||
1996-01-01T00:00:19 correction=20
|
||||
1997-07-01T00:00:20 correction=21
|
||||
1999-01-01T00:00:21 correction=22
|
||||
2006-01-01T00:00:22 correction=23
|
||||
2009-01-01T00:00:23 correction=24
|
||||
2012-07-01T00:00:24 correction=25
|
||||
2015-07-01T00:00:25 correction=26
|
||||
2017-01-01T00:00:26 correction=27
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
---
|
||||
source: src/tz/tzif.rs
|
||||
expression: tzif_to_human_readable(&tzif_test.parse())
|
||||
---
|
||||
TIME ZONE NAME
|
||||
right/America/New_York
|
||||
LOCAL TIME TYPES
|
||||
000: offset=-04:56:02 designation=LMT indicator=local/wall
|
||||
001: offset=-04 designation=EDT dst indicator=local/wall
|
||||
002: offset=-05 designation=EST indicator=local/wall
|
||||
003: offset=-05 designation=EST indicator=ut/std
|
||||
004: offset=-04 designation=EWT dst indicator=local/wall
|
||||
005: offset=-04 designation=EPT dst indicator=ut/std
|
||||
TRANSITIONS
|
||||
0000: -9999-01-02T01:59:59Z unix=-377705023201 wall=-9999-01-01T21:03:57 unambiguous type=0 -04:56:02 LMT
|
||||
0001: 1883-11-18T17:00:00Z unix=-2717650800 wall=1883-11-18T12:00:00 fold-until(1883-11-18T12:03:58) type=3 -05 EST
|
||||
0002: 1918-03-31T07:00:00Z unix=-1633280400 wall=1918-03-31T02:00:00 gap-until(1918-03-31T03:00:00) type=1 -04 EDT dst
|
||||
0003: 1918-10-27T06:00:00Z unix=-1615140000 wall=1918-10-27T01:00:00 fold-until(1918-10-27T02:00:00) type=2 -05 EST
|
||||
0004: 1919-03-30T07:00:00Z unix=-1601830800 wall=1919-03-30T02:00:00 gap-until(1919-03-30T03:00:00) type=1 -04 EDT dst
|
||||
0005: 1919-10-26T06:00:00Z unix=-1583690400 wall=1919-10-26T01:00:00 fold-until(1919-10-26T02:00:00) type=2 -05 EST
|
||||
0006: 1920-03-28T07:00:00Z unix=-1570381200 wall=1920-03-28T02:00:00 gap-until(1920-03-28T03:00:00) type=1 -04 EDT dst
|
||||
0007: 1920-10-31T06:00:00Z unix=-1551636000 wall=1920-10-31T01:00:00 fold-until(1920-10-31T02:00:00) type=2 -05 EST
|
||||
0008: 1921-04-24T07:00:00Z unix=-1536512400 wall=1921-04-24T02:00:00 gap-until(1921-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0009: 1921-09-25T06:00:00Z unix=-1523210400 wall=1921-09-25T01:00:00 fold-until(1921-09-25T02:00:00) type=2 -05 EST
|
||||
0010: 1922-04-30T07:00:00Z unix=-1504458000 wall=1922-04-30T02:00:00 gap-until(1922-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0011: 1922-09-24T06:00:00Z unix=-1491760800 wall=1922-09-24T01:00:00 fold-until(1922-09-24T02:00:00) type=2 -05 EST
|
||||
0012: 1923-04-29T07:00:00Z unix=-1473008400 wall=1923-04-29T02:00:00 gap-until(1923-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0013: 1923-09-30T06:00:00Z unix=-1459706400 wall=1923-09-30T01:00:00 fold-until(1923-09-30T02:00:00) type=2 -05 EST
|
||||
0014: 1924-04-27T07:00:00Z unix=-1441558800 wall=1924-04-27T02:00:00 gap-until(1924-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0015: 1924-09-28T06:00:00Z unix=-1428256800 wall=1924-09-28T01:00:00 fold-until(1924-09-28T02:00:00) type=2 -05 EST
|
||||
0016: 1925-04-26T07:00:00Z unix=-1410109200 wall=1925-04-26T02:00:00 gap-until(1925-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0017: 1925-09-27T06:00:00Z unix=-1396807200 wall=1925-09-27T01:00:00 fold-until(1925-09-27T02:00:00) type=2 -05 EST
|
||||
0018: 1926-04-25T07:00:00Z unix=-1378659600 wall=1926-04-25T02:00:00 gap-until(1926-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0019: 1926-09-26T06:00:00Z unix=-1365357600 wall=1926-09-26T01:00:00 fold-until(1926-09-26T02:00:00) type=2 -05 EST
|
||||
0020: 1927-04-24T07:00:00Z unix=-1347210000 wall=1927-04-24T02:00:00 gap-until(1927-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0021: 1927-09-25T06:00:00Z unix=-1333908000 wall=1927-09-25T01:00:00 fold-until(1927-09-25T02:00:00) type=2 -05 EST
|
||||
0022: 1928-04-29T07:00:00Z unix=-1315155600 wall=1928-04-29T02:00:00 gap-until(1928-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0023: 1928-09-30T06:00:00Z unix=-1301853600 wall=1928-09-30T01:00:00 fold-until(1928-09-30T02:00:00) type=2 -05 EST
|
||||
0024: 1929-04-28T07:00:00Z unix=-1283706000 wall=1929-04-28T02:00:00 gap-until(1929-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0025: 1929-09-29T06:00:00Z unix=-1270404000 wall=1929-09-29T01:00:00 fold-until(1929-09-29T02:00:00) type=2 -05 EST
|
||||
0026: 1930-04-27T07:00:00Z unix=-1252256400 wall=1930-04-27T02:00:00 gap-until(1930-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0027: 1930-09-28T06:00:00Z unix=-1238954400 wall=1930-09-28T01:00:00 fold-until(1930-09-28T02:00:00) type=2 -05 EST
|
||||
0028: 1931-04-26T07:00:00Z unix=-1220806800 wall=1931-04-26T02:00:00 gap-until(1931-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0029: 1931-09-27T06:00:00Z unix=-1207504800 wall=1931-09-27T01:00:00 fold-until(1931-09-27T02:00:00) type=2 -05 EST
|
||||
0030: 1932-04-24T07:00:00Z unix=-1189357200 wall=1932-04-24T02:00:00 gap-until(1932-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0031: 1932-09-25T06:00:00Z unix=-1176055200 wall=1932-09-25T01:00:00 fold-until(1932-09-25T02:00:00) type=2 -05 EST
|
||||
0032: 1933-04-30T07:00:00Z unix=-1157302800 wall=1933-04-30T02:00:00 gap-until(1933-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0033: 1933-09-24T06:00:00Z unix=-1144605600 wall=1933-09-24T01:00:00 fold-until(1933-09-24T02:00:00) type=2 -05 EST
|
||||
0034: 1934-04-29T07:00:00Z unix=-1125853200 wall=1934-04-29T02:00:00 gap-until(1934-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0035: 1934-09-30T06:00:00Z unix=-1112551200 wall=1934-09-30T01:00:00 fold-until(1934-09-30T02:00:00) type=2 -05 EST
|
||||
0036: 1935-04-28T07:00:00Z unix=-1094403600 wall=1935-04-28T02:00:00 gap-until(1935-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0037: 1935-09-29T06:00:00Z unix=-1081101600 wall=1935-09-29T01:00:00 fold-until(1935-09-29T02:00:00) type=2 -05 EST
|
||||
0038: 1936-04-26T07:00:00Z unix=-1062954000 wall=1936-04-26T02:00:00 gap-until(1936-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0039: 1936-09-27T06:00:00Z unix=-1049652000 wall=1936-09-27T01:00:00 fold-until(1936-09-27T02:00:00) type=2 -05 EST
|
||||
0040: 1937-04-25T07:00:00Z unix=-1031504400 wall=1937-04-25T02:00:00 gap-until(1937-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0041: 1937-09-26T06:00:00Z unix=-1018202400 wall=1937-09-26T01:00:00 fold-until(1937-09-26T02:00:00) type=2 -05 EST
|
||||
0042: 1938-04-24T07:00:00Z unix=-1000054800 wall=1938-04-24T02:00:00 gap-until(1938-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0043: 1938-09-25T06:00:00Z unix=-986752800 wall=1938-09-25T01:00:00 fold-until(1938-09-25T02:00:00) type=2 -05 EST
|
||||
0044: 1939-04-30T07:00:00Z unix=-968000400 wall=1939-04-30T02:00:00 gap-until(1939-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0045: 1939-09-24T06:00:00Z unix=-955303200 wall=1939-09-24T01:00:00 fold-until(1939-09-24T02:00:00) type=2 -05 EST
|
||||
0046: 1940-04-28T07:00:00Z unix=-936550800 wall=1940-04-28T02:00:00 gap-until(1940-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0047: 1940-09-29T06:00:00Z unix=-923248800 wall=1940-09-29T01:00:00 fold-until(1940-09-29T02:00:00) type=2 -05 EST
|
||||
0048: 1941-04-27T07:00:00Z unix=-905101200 wall=1941-04-27T02:00:00 gap-until(1941-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0049: 1941-09-28T06:00:00Z unix=-891799200 wall=1941-09-28T01:00:00 fold-until(1941-09-28T02:00:00) type=2 -05 EST
|
||||
0050: 1942-02-09T07:00:00Z unix=-880218000 wall=1942-02-09T02:00:00 gap-until(1942-02-09T03:00:00) type=4 -04 EWT dst
|
||||
0051: 1945-08-14T23:00:00Z unix=-769395600 wall=1945-08-14T19:00:00 unambiguous type=5 -04 EPT dst
|
||||
0052: 1945-09-30T06:00:00Z unix=-765396000 wall=1945-09-30T01:00:00 fold-until(1945-09-30T02:00:00) type=2 -05 EST
|
||||
0053: 1946-04-28T07:00:00Z unix=-747248400 wall=1946-04-28T02:00:00 gap-until(1946-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0054: 1946-09-29T06:00:00Z unix=-733946400 wall=1946-09-29T01:00:00 fold-until(1946-09-29T02:00:00) type=2 -05 EST
|
||||
0055: 1947-04-27T07:00:00Z unix=-715798800 wall=1947-04-27T02:00:00 gap-until(1947-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0056: 1947-09-28T06:00:00Z unix=-702496800 wall=1947-09-28T01:00:00 fold-until(1947-09-28T02:00:00) type=2 -05 EST
|
||||
0057: 1948-04-25T07:00:00Z unix=-684349200 wall=1948-04-25T02:00:00 gap-until(1948-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0058: 1948-09-26T06:00:00Z unix=-671047200 wall=1948-09-26T01:00:00 fold-until(1948-09-26T02:00:00) type=2 -05 EST
|
||||
0059: 1949-04-24T07:00:00Z unix=-652899600 wall=1949-04-24T02:00:00 gap-until(1949-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0060: 1949-09-25T06:00:00Z unix=-639597600 wall=1949-09-25T01:00:00 fold-until(1949-09-25T02:00:00) type=2 -05 EST
|
||||
0061: 1950-04-30T07:00:00Z unix=-620845200 wall=1950-04-30T02:00:00 gap-until(1950-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0062: 1950-09-24T06:00:00Z unix=-608148000 wall=1950-09-24T01:00:00 fold-until(1950-09-24T02:00:00) type=2 -05 EST
|
||||
0063: 1951-04-29T07:00:00Z unix=-589395600 wall=1951-04-29T02:00:00 gap-until(1951-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0064: 1951-09-30T06:00:00Z unix=-576093600 wall=1951-09-30T01:00:00 fold-until(1951-09-30T02:00:00) type=2 -05 EST
|
||||
0065: 1952-04-27T07:00:00Z unix=-557946000 wall=1952-04-27T02:00:00 gap-until(1952-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0066: 1952-09-28T06:00:00Z unix=-544644000 wall=1952-09-28T01:00:00 fold-until(1952-09-28T02:00:00) type=2 -05 EST
|
||||
0067: 1953-04-26T07:00:00Z unix=-526496400 wall=1953-04-26T02:00:00 gap-until(1953-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0068: 1953-09-27T06:00:00Z unix=-513194400 wall=1953-09-27T01:00:00 fold-until(1953-09-27T02:00:00) type=2 -05 EST
|
||||
0069: 1954-04-25T07:00:00Z unix=-495046800 wall=1954-04-25T02:00:00 gap-until(1954-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0070: 1954-09-26T06:00:00Z unix=-481744800 wall=1954-09-26T01:00:00 fold-until(1954-09-26T02:00:00) type=2 -05 EST
|
||||
0071: 1955-04-24T07:00:00Z unix=-463597200 wall=1955-04-24T02:00:00 gap-until(1955-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0072: 1955-10-30T06:00:00Z unix=-447271200 wall=1955-10-30T01:00:00 fold-until(1955-10-30T02:00:00) type=2 -05 EST
|
||||
0073: 1956-04-29T07:00:00Z unix=-431542800 wall=1956-04-29T02:00:00 gap-until(1956-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0074: 1956-10-28T06:00:00Z unix=-415821600 wall=1956-10-28T01:00:00 fold-until(1956-10-28T02:00:00) type=2 -05 EST
|
||||
0075: 1957-04-28T07:00:00Z unix=-400093200 wall=1957-04-28T02:00:00 gap-until(1957-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0076: 1957-10-27T06:00:00Z unix=-384372000 wall=1957-10-27T01:00:00 fold-until(1957-10-27T02:00:00) type=2 -05 EST
|
||||
0077: 1958-04-27T07:00:00Z unix=-368643600 wall=1958-04-27T02:00:00 gap-until(1958-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0078: 1958-10-26T06:00:00Z unix=-352922400 wall=1958-10-26T01:00:00 fold-until(1958-10-26T02:00:00) type=2 -05 EST
|
||||
0079: 1959-04-26T07:00:00Z unix=-337194000 wall=1959-04-26T02:00:00 gap-until(1959-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0080: 1959-10-25T06:00:00Z unix=-321472800 wall=1959-10-25T01:00:00 fold-until(1959-10-25T02:00:00) type=2 -05 EST
|
||||
0081: 1960-04-24T07:00:00Z unix=-305744400 wall=1960-04-24T02:00:00 gap-until(1960-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0082: 1960-10-30T06:00:00Z unix=-289418400 wall=1960-10-30T01:00:00 fold-until(1960-10-30T02:00:00) type=2 -05 EST
|
||||
0083: 1961-04-30T07:00:00Z unix=-273690000 wall=1961-04-30T02:00:00 gap-until(1961-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0084: 1961-10-29T06:00:00Z unix=-257968800 wall=1961-10-29T01:00:00 fold-until(1961-10-29T02:00:00) type=2 -05 EST
|
||||
0085: 1962-04-29T07:00:00Z unix=-242240400 wall=1962-04-29T02:00:00 gap-until(1962-04-29T03:00:00) type=1 -04 EDT dst
|
||||
0086: 1962-10-28T06:00:00Z unix=-226519200 wall=1962-10-28T01:00:00 fold-until(1962-10-28T02:00:00) type=2 -05 EST
|
||||
0087: 1963-04-28T07:00:00Z unix=-210790800 wall=1963-04-28T02:00:00 gap-until(1963-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0088: 1963-10-27T06:00:00Z unix=-195069600 wall=1963-10-27T01:00:00 fold-until(1963-10-27T02:00:00) type=2 -05 EST
|
||||
0089: 1964-04-26T07:00:00Z unix=-179341200 wall=1964-04-26T02:00:00 gap-until(1964-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0090: 1964-10-25T06:00:00Z unix=-163620000 wall=1964-10-25T01:00:00 fold-until(1964-10-25T02:00:00) type=2 -05 EST
|
||||
0091: 1965-04-25T07:00:00Z unix=-147891600 wall=1965-04-25T02:00:00 gap-until(1965-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0092: 1965-10-31T06:00:00Z unix=-131565600 wall=1965-10-31T01:00:00 fold-until(1965-10-31T02:00:00) type=2 -05 EST
|
||||
0093: 1966-04-24T07:00:00Z unix=-116442000 wall=1966-04-24T02:00:00 gap-until(1966-04-24T03:00:00) type=1 -04 EDT dst
|
||||
0094: 1966-10-30T06:00:00Z unix=-100116000 wall=1966-10-30T01:00:00 fold-until(1966-10-30T02:00:00) type=2 -05 EST
|
||||
0095: 1967-04-30T07:00:00Z unix=-84387600 wall=1967-04-30T02:00:00 gap-until(1967-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0096: 1967-10-29T06:00:00Z unix=-68666400 wall=1967-10-29T01:00:00 fold-until(1967-10-29T02:00:00) type=2 -05 EST
|
||||
0097: 1968-04-28T07:00:00Z unix=-52938000 wall=1968-04-28T02:00:00 gap-until(1968-04-28T03:00:00) type=1 -04 EDT dst
|
||||
0098: 1968-10-27T06:00:00Z unix=-37216800 wall=1968-10-27T01:00:00 fold-until(1968-10-27T02:00:00) type=2 -05 EST
|
||||
0099: 1969-04-27T07:00:00Z unix=-21488400 wall=1969-04-27T02:00:00 gap-until(1969-04-27T03:00:00) type=1 -04 EDT dst
|
||||
0100: 1969-10-26T06:00:00Z unix=-5767200 wall=1969-10-26T01:00:00 fold-until(1969-10-26T02:00:00) type=2 -05 EST
|
||||
0101: 1970-04-26T07:00:00Z unix=9961200 wall=1970-04-26T02:00:00 gap-until(1970-04-26T03:00:00) type=1 -04 EDT dst
|
||||
0102: 1970-10-25T06:00:00Z unix=25682400 wall=1970-10-25T01:00:00 fold-until(1970-10-25T02:00:00) type=2 -05 EST
|
||||
0103: 1971-04-25T07:00:00Z unix=41410800 wall=1971-04-25T02:00:00 gap-until(1971-04-25T03:00:00) type=1 -04 EDT dst
|
||||
0104: 1971-10-31T06:00:00Z unix=57736800 wall=1971-10-31T01:00:00 fold-until(1971-10-31T02:00:00) type=2 -05 EST
|
||||
0105: 1972-04-30T07:00:00Z unix=73465200 wall=1972-04-30T02:00:00 gap-until(1972-04-30T03:00:00) type=1 -04 EDT dst
|
||||
0106: 1972-10-29T06:00:01Z unix=89186401 wall=1972-10-29T01:00:01 fold-until(1972-10-29T02:00:01) type=2 -05 EST
|
||||
0107: 1973-04-29T07:00:02Z unix=104914802 wall=1973-04-29T02:00:02 gap-until(1973-04-29T03:00:02) type=1 -04 EDT dst
|
||||
0108: 1973-10-28T06:00:02Z unix=120636002 wall=1973-10-28T01:00:02 fold-until(1973-10-28T02:00:02) type=2 -05 EST
|
||||
0109: 1974-01-06T07:00:03Z unix=126687603 wall=1974-01-06T02:00:03 gap-until(1974-01-06T03:00:03) type=1 -04 EDT dst
|
||||
0110: 1974-10-27T06:00:03Z unix=152085603 wall=1974-10-27T01:00:03 fold-until(1974-10-27T02:00:03) type=2 -05 EST
|
||||
0111: 1975-02-23T07:00:04Z unix=162370804 wall=1975-02-23T02:00:04 gap-until(1975-02-23T03:00:04) type=1 -04 EDT dst
|
||||
0112: 1975-10-26T06:00:04Z unix=183535204 wall=1975-10-26T01:00:04 fold-until(1975-10-26T02:00:04) type=2 -05 EST
|
||||
0113: 1976-04-25T07:00:05Z unix=199263605 wall=1976-04-25T02:00:05 gap-until(1976-04-25T03:00:05) type=1 -04 EDT dst
|
||||
0114: 1976-10-31T06:00:05Z unix=215589605 wall=1976-10-31T01:00:05 fold-until(1976-10-31T02:00:05) type=2 -05 EST
|
||||
0115: 1977-04-24T07:00:06Z unix=230713206 wall=1977-04-24T02:00:06 gap-until(1977-04-24T03:00:06) type=1 -04 EDT dst
|
||||
0116: 1977-10-30T06:00:06Z unix=247039206 wall=1977-10-30T01:00:06 fold-until(1977-10-30T02:00:06) type=2 -05 EST
|
||||
0117: 1978-04-30T07:00:07Z unix=262767607 wall=1978-04-30T02:00:07 gap-until(1978-04-30T03:00:07) type=1 -04 EDT dst
|
||||
0118: 1978-10-29T06:00:07Z unix=278488807 wall=1978-10-29T01:00:07 fold-until(1978-10-29T02:00:07) type=2 -05 EST
|
||||
0119: 1979-04-29T07:00:08Z unix=294217208 wall=1979-04-29T02:00:08 gap-until(1979-04-29T03:00:08) type=1 -04 EDT dst
|
||||
0120: 1979-10-28T06:00:08Z unix=309938408 wall=1979-10-28T01:00:08 fold-until(1979-10-28T02:00:08) type=2 -05 EST
|
||||
0121: 1980-04-27T07:00:09Z unix=325666809 wall=1980-04-27T02:00:09 gap-until(1980-04-27T03:00:09) type=1 -04 EDT dst
|
||||
0122: 1980-10-26T06:00:09Z unix=341388009 wall=1980-10-26T01:00:09 fold-until(1980-10-26T02:00:09) type=2 -05 EST
|
||||
0123: 1981-04-26T07:00:09Z unix=357116409 wall=1981-04-26T02:00:09 gap-until(1981-04-26T03:00:09) type=1 -04 EDT dst
|
||||
0124: 1981-10-25T06:00:10Z unix=372837610 wall=1981-10-25T01:00:10 fold-until(1981-10-25T02:00:10) type=2 -05 EST
|
||||
0125: 1982-04-25T07:00:10Z unix=388566010 wall=1982-04-25T02:00:10 gap-until(1982-04-25T03:00:10) type=1 -04 EDT dst
|
||||
0126: 1982-10-31T06:00:11Z unix=404892011 wall=1982-10-31T01:00:11 fold-until(1982-10-31T02:00:11) type=2 -05 EST
|
||||
0127: 1983-04-24T07:00:11Z unix=420015611 wall=1983-04-24T02:00:11 gap-until(1983-04-24T03:00:11) type=1 -04 EDT dst
|
||||
0128: 1983-10-30T06:00:12Z unix=436341612 wall=1983-10-30T01:00:12 fold-until(1983-10-30T02:00:12) type=2 -05 EST
|
||||
0129: 1984-04-29T07:00:12Z unix=452070012 wall=1984-04-29T02:00:12 gap-until(1984-04-29T03:00:12) type=1 -04 EDT dst
|
||||
0130: 1984-10-28T06:00:12Z unix=467791212 wall=1984-10-28T01:00:12 fold-until(1984-10-28T02:00:12) type=2 -05 EST
|
||||
0131: 1985-04-28T07:00:12Z unix=483519612 wall=1985-04-28T02:00:12 gap-until(1985-04-28T03:00:12) type=1 -04 EDT dst
|
||||
0132: 1985-10-27T06:00:13Z unix=499240813 wall=1985-10-27T01:00:13 fold-until(1985-10-27T02:00:13) type=2 -05 EST
|
||||
0133: 1986-04-27T07:00:13Z unix=514969213 wall=1986-04-27T02:00:13 gap-until(1986-04-27T03:00:13) type=1 -04 EDT dst
|
||||
0134: 1986-10-26T06:00:13Z unix=530690413 wall=1986-10-26T01:00:13 fold-until(1986-10-26T02:00:13) type=2 -05 EST
|
||||
0135: 1987-04-05T07:00:13Z unix=544604413 wall=1987-04-05T02:00:13 gap-until(1987-04-05T03:00:13) type=1 -04 EDT dst
|
||||
0136: 1987-10-25T06:00:13Z unix=562140013 wall=1987-10-25T01:00:13 fold-until(1987-10-25T02:00:13) type=2 -05 EST
|
||||
0137: 1988-04-03T07:00:14Z unix=576054014 wall=1988-04-03T02:00:14 gap-until(1988-04-03T03:00:14) type=1 -04 EDT dst
|
||||
0138: 1988-10-30T06:00:14Z unix=594194414 wall=1988-10-30T01:00:14 fold-until(1988-10-30T02:00:14) type=2 -05 EST
|
||||
0139: 1989-04-02T07:00:14Z unix=607503614 wall=1989-04-02T02:00:14 gap-until(1989-04-02T03:00:14) type=1 -04 EDT dst
|
||||
0140: 1989-10-29T06:00:14Z unix=625644014 wall=1989-10-29T01:00:14 fold-until(1989-10-29T02:00:14) type=2 -05 EST
|
||||
0141: 1990-04-01T07:00:15Z unix=638953215 wall=1990-04-01T02:00:15 gap-until(1990-04-01T03:00:15) type=1 -04 EDT dst
|
||||
0142: 1990-10-28T06:00:15Z unix=657093615 wall=1990-10-28T01:00:15 fold-until(1990-10-28T02:00:15) type=2 -05 EST
|
||||
0143: 1991-04-07T07:00:16Z unix=671007616 wall=1991-04-07T02:00:16 gap-until(1991-04-07T03:00:16) type=1 -04 EDT dst
|
||||
0144: 1991-10-27T06:00:16Z unix=688543216 wall=1991-10-27T01:00:16 fold-until(1991-10-27T02:00:16) type=2 -05 EST
|
||||
0145: 1992-04-05T07:00:16Z unix=702457216 wall=1992-04-05T02:00:16 gap-until(1992-04-05T03:00:16) type=1 -04 EDT dst
|
||||
0146: 1992-10-25T06:00:17Z unix=719992817 wall=1992-10-25T01:00:17 fold-until(1992-10-25T02:00:17) type=2 -05 EST
|
||||
0147: 1993-04-04T07:00:17Z unix=733906817 wall=1993-04-04T02:00:17 gap-until(1993-04-04T03:00:17) type=1 -04 EDT dst
|
||||
0148: 1993-10-31T06:00:18Z unix=752047218 wall=1993-10-31T01:00:18 fold-until(1993-10-31T02:00:18) type=2 -05 EST
|
||||
0149: 1994-04-03T07:00:18Z unix=765356418 wall=1994-04-03T02:00:18 gap-until(1994-04-03T03:00:18) type=1 -04 EDT dst
|
||||
0150: 1994-10-30T06:00:19Z unix=783496819 wall=1994-10-30T01:00:19 fold-until(1994-10-30T02:00:19) type=2 -05 EST
|
||||
0151: 1995-04-02T07:00:19Z unix=796806019 wall=1995-04-02T02:00:19 gap-until(1995-04-02T03:00:19) type=1 -04 EDT dst
|
||||
0152: 1995-10-29T06:00:19Z unix=814946419 wall=1995-10-29T01:00:19 fold-until(1995-10-29T02:00:19) type=2 -05 EST
|
||||
0153: 1996-04-07T07:00:20Z unix=828860420 wall=1996-04-07T02:00:20 gap-until(1996-04-07T03:00:20) type=1 -04 EDT dst
|
||||
0154: 1996-10-27T06:00:20Z unix=846396020 wall=1996-10-27T01:00:20 fold-until(1996-10-27T02:00:20) type=2 -05 EST
|
||||
0155: 1997-04-06T07:00:20Z unix=860310020 wall=1997-04-06T02:00:20 gap-until(1997-04-06T03:00:20) type=1 -04 EDT dst
|
||||
0156: 1997-10-26T06:00:21Z unix=877845621 wall=1997-10-26T01:00:21 fold-until(1997-10-26T02:00:21) type=2 -05 EST
|
||||
0157: 1998-04-05T07:00:21Z unix=891759621 wall=1998-04-05T02:00:21 gap-until(1998-04-05T03:00:21) type=1 -04 EDT dst
|
||||
0158: 1998-10-25T06:00:21Z unix=909295221 wall=1998-10-25T01:00:21 fold-until(1998-10-25T02:00:21) type=2 -05 EST
|
||||
0159: 1999-04-04T07:00:22Z unix=923209222 wall=1999-04-04T02:00:22 gap-until(1999-04-04T03:00:22) type=1 -04 EDT dst
|
||||
0160: 1999-10-31T06:00:22Z unix=941349622 wall=1999-10-31T01:00:22 fold-until(1999-10-31T02:00:22) type=2 -05 EST
|
||||
0161: 2000-04-02T07:00:22Z unix=954658822 wall=2000-04-02T02:00:22 gap-until(2000-04-02T03:00:22) type=1 -04 EDT dst
|
||||
0162: 2000-10-29T06:00:22Z unix=972799222 wall=2000-10-29T01:00:22 fold-until(2000-10-29T02:00:22) type=2 -05 EST
|
||||
0163: 2001-04-01T07:00:22Z unix=986108422 wall=2001-04-01T02:00:22 gap-until(2001-04-01T03:00:22) type=1 -04 EDT dst
|
||||
0164: 2001-10-28T06:00:22Z unix=1004248822 wall=2001-10-28T01:00:22 fold-until(2001-10-28T02:00:22) type=2 -05 EST
|
||||
0165: 2002-04-07T07:00:22Z unix=1018162822 wall=2002-04-07T02:00:22 gap-until(2002-04-07T03:00:22) type=1 -04 EDT dst
|
||||
0166: 2002-10-27T06:00:22Z unix=1035698422 wall=2002-10-27T01:00:22 fold-until(2002-10-27T02:00:22) type=2 -05 EST
|
||||
0167: 2003-04-06T07:00:22Z unix=1049612422 wall=2003-04-06T02:00:22 gap-until(2003-04-06T03:00:22) type=1 -04 EDT dst
|
||||
0168: 2003-10-26T06:00:22Z unix=1067148022 wall=2003-10-26T01:00:22 fold-until(2003-10-26T02:00:22) type=2 -05 EST
|
||||
0169: 2004-04-04T07:00:22Z unix=1081062022 wall=2004-04-04T02:00:22 gap-until(2004-04-04T03:00:22) type=1 -04 EDT dst
|
||||
0170: 2004-10-31T06:00:22Z unix=1099202422 wall=2004-10-31T01:00:22 fold-until(2004-10-31T02:00:22) type=2 -05 EST
|
||||
0171: 2005-04-03T07:00:22Z unix=1112511622 wall=2005-04-03T02:00:22 gap-until(2005-04-03T03:00:22) type=1 -04 EDT dst
|
||||
0172: 2005-10-30T06:00:22Z unix=1130652022 wall=2005-10-30T01:00:22 fold-until(2005-10-30T02:00:22) type=2 -05 EST
|
||||
0173: 2006-04-02T07:00:23Z unix=1143961223 wall=2006-04-02T02:00:23 gap-until(2006-04-02T03:00:23) type=1 -04 EDT dst
|
||||
0174: 2006-10-29T06:00:23Z unix=1162101623 wall=2006-10-29T01:00:23 fold-until(2006-10-29T02:00:23) type=2 -05 EST
|
||||
0175: 2007-03-11T07:00:23Z unix=1173596423 wall=2007-03-11T02:00:23 gap-until(2007-03-11T03:00:23) type=1 -04 EDT dst
|
||||
0176: 2007-11-04T06:00:23Z unix=1194156023 wall=2007-11-04T01:00:23 fold-until(2007-11-04T02:00:23) type=2 -05 EST
|
||||
0177: 2008-03-09T07:00:23Z unix=1205046023 wall=2008-03-09T02:00:23 gap-until(2008-03-09T03:00:23) type=1 -04 EDT dst
|
||||
0178: 2008-11-02T06:00:23Z unix=1225605623 wall=2008-11-02T01:00:23 fold-until(2008-11-02T02:00:23) type=2 -05 EST
|
||||
0179: 2009-03-08T07:00:24Z unix=1236495624 wall=2009-03-08T02:00:24 gap-until(2009-03-08T03:00:24) type=1 -04 EDT dst
|
||||
0180: 2009-11-01T06:00:24Z unix=1257055224 wall=2009-11-01T01:00:24 fold-until(2009-11-01T02:00:24) type=2 -05 EST
|
||||
0181: 2010-03-14T07:00:24Z unix=1268550024 wall=2010-03-14T02:00:24 gap-until(2010-03-14T03:00:24) type=1 -04 EDT dst
|
||||
0182: 2010-11-07T06:00:24Z unix=1289109624 wall=2010-11-07T01:00:24 fold-until(2010-11-07T02:00:24) type=2 -05 EST
|
||||
0183: 2011-03-13T07:00:24Z unix=1299999624 wall=2011-03-13T02:00:24 gap-until(2011-03-13T03:00:24) type=1 -04 EDT dst
|
||||
0184: 2011-11-06T06:00:24Z unix=1320559224 wall=2011-11-06T01:00:24 fold-until(2011-11-06T02:00:24) type=2 -05 EST
|
||||
0185: 2012-03-11T07:00:24Z unix=1331449224 wall=2012-03-11T02:00:24 gap-until(2012-03-11T03:00:24) type=1 -04 EDT dst
|
||||
0186: 2012-11-04T06:00:25Z unix=1352008825 wall=2012-11-04T01:00:25 fold-until(2012-11-04T02:00:25) type=2 -05 EST
|
||||
0187: 2013-03-10T07:00:25Z unix=1362898825 wall=2013-03-10T02:00:25 gap-until(2013-03-10T03:00:25) type=1 -04 EDT dst
|
||||
0188: 2013-11-03T06:00:25Z unix=1383458425 wall=2013-11-03T01:00:25 fold-until(2013-11-03T02:00:25) type=2 -05 EST
|
||||
0189: 2014-03-09T07:00:25Z unix=1394348425 wall=2014-03-09T02:00:25 gap-until(2014-03-09T03:00:25) type=1 -04 EDT dst
|
||||
0190: 2014-11-02T06:00:25Z unix=1414908025 wall=2014-11-02T01:00:25 fold-until(2014-11-02T02:00:25) type=2 -05 EST
|
||||
0191: 2015-03-08T07:00:25Z unix=1425798025 wall=2015-03-08T02:00:25 gap-until(2015-03-08T03:00:25) type=1 -04 EDT dst
|
||||
0192: 2015-11-01T06:00:26Z unix=1446357626 wall=2015-11-01T01:00:26 fold-until(2015-11-01T02:00:26) type=2 -05 EST
|
||||
0193: 2016-03-13T07:00:26Z unix=1457852426 wall=2016-03-13T02:00:26 gap-until(2016-03-13T03:00:26) type=1 -04 EDT dst
|
||||
0194: 2016-11-06T06:00:26Z unix=1478412026 wall=2016-11-06T01:00:26 fold-until(2016-11-06T02:00:26) type=2 -05 EST
|
||||
0195: 2017-03-12T07:00:27Z unix=1489302027 wall=2017-03-12T02:00:27 gap-until(2017-03-12T03:00:27) type=1 -04 EDT dst
|
||||
0196: 2017-11-05T06:00:27Z unix=1509861627 wall=2017-11-05T01:00:27 fold-until(2017-11-05T02:00:27) type=2 -05 EST
|
||||
0197: 2018-03-11T07:00:27Z unix=1520751627 wall=2018-03-11T02:00:27 gap-until(2018-03-11T03:00:27) type=1 -04 EDT dst
|
||||
0198: 2018-11-04T06:00:27Z unix=1541311227 wall=2018-11-04T01:00:27 fold-until(2018-11-04T02:00:27) type=2 -05 EST
|
||||
0199: 2019-03-10T07:00:27Z unix=1552201227 wall=2019-03-10T02:00:27 gap-until(2019-03-10T03:00:27) type=1 -04 EDT dst
|
||||
0200: 2019-11-03T06:00:27Z unix=1572760827 wall=2019-11-03T01:00:27 fold-until(2019-11-03T02:00:27) type=2 -05 EST
|
||||
0201: 2020-03-08T07:00:27Z unix=1583650827 wall=2020-03-08T02:00:27 gap-until(2020-03-08T03:00:27) type=1 -04 EDT dst
|
||||
0202: 2020-11-01T06:00:27Z unix=1604210427 wall=2020-11-01T01:00:27 fold-until(2020-11-01T02:00:27) type=2 -05 EST
|
||||
0203: 2021-03-14T07:00:27Z unix=1615705227 wall=2021-03-14T02:00:27 gap-until(2021-03-14T03:00:27) type=1 -04 EDT dst
|
||||
0204: 2021-11-07T06:00:27Z unix=1636264827 wall=2021-11-07T01:00:27 fold-until(2021-11-07T02:00:27) type=2 -05 EST
|
||||
0205: 2022-03-13T07:00:27Z unix=1647154827 wall=2022-03-13T02:00:27 gap-until(2022-03-13T03:00:27) type=1 -04 EDT dst
|
||||
0206: 2022-11-06T06:00:27Z unix=1667714427 wall=2022-11-06T01:00:27 fold-until(2022-11-06T02:00:27) type=2 -05 EST
|
||||
0207: 2023-03-12T07:00:27Z unix=1678604427 wall=2023-03-12T02:00:27 gap-until(2023-03-12T03:00:27) type=1 -04 EDT dst
|
||||
0208: 2023-11-05T06:00:27Z unix=1699164027 wall=2023-11-05T01:00:27 fold-until(2023-11-05T02:00:27) type=2 -05 EST
|
||||
0209: 2024-03-10T07:00:27Z unix=1710054027 wall=2024-03-10T02:00:27 gap-until(2024-03-10T03:00:27) type=1 -04 EDT dst
|
||||
0210: 2024-11-03T06:00:27Z unix=1730613627 wall=2024-11-03T01:00:27 fold-until(2024-11-03T02:00:27) type=2 -05 EST
|
||||
0211: 2025-03-09T07:00:27Z unix=1741503627 wall=2025-03-09T02:00:27 gap-until(2025-03-09T03:00:27) type=1 -04 EDT dst
|
||||
0212: 2025-11-02T06:00:27Z unix=1762063227 wall=2025-11-02T01:00:27 fold-until(2025-11-02T02:00:27) type=2 -05 EST
|
||||
0213: 2026-03-08T07:00:27Z unix=1772953227 wall=2026-03-08T02:00:27 gap-until(2026-03-08T03:00:27) type=1 -04 EDT dst
|
||||
0214: 2026-11-01T06:00:27Z unix=1793512827 wall=2026-11-01T01:00:27 fold-until(2026-11-01T02:00:27) type=2 -05 EST
|
||||
0215: 2027-03-14T07:00:27Z unix=1805007627 wall=2027-03-14T02:00:27 gap-until(2027-03-14T03:00:27) type=1 -04 EDT dst
|
||||
0216: 2027-11-07T06:00:27Z unix=1825567227 wall=2027-11-07T01:00:27 fold-until(2027-11-07T02:00:27) type=2 -05 EST
|
||||
0217: 2028-03-12T07:00:27Z unix=1836457227 wall=2028-03-12T02:00:27 gap-until(2028-03-12T03:00:27) type=1 -04 EDT dst
|
||||
0218: 2028-11-05T06:00:27Z unix=1857016827 wall=2028-11-05T01:00:27 fold-until(2028-11-05T02:00:27) type=2 -05 EST
|
||||
0219: 2029-03-11T07:00:27Z unix=1867906827 wall=2029-03-11T02:00:27 gap-until(2029-03-11T03:00:27) type=1 -04 EDT dst
|
||||
0220: 2029-11-04T06:00:27Z unix=1888466427 wall=2029-11-04T01:00:27 fold-until(2029-11-04T02:00:27) type=2 -05 EST
|
||||
0221: 2030-03-10T07:00:27Z unix=1899356427 wall=2030-03-10T02:00:27 gap-until(2030-03-10T03:00:27) type=1 -04 EDT dst
|
||||
0222: 2030-11-03T06:00:27Z unix=1919916027 wall=2030-11-03T01:00:27 fold-until(2030-11-03T02:00:27) type=2 -05 EST
|
||||
0223: 2031-03-09T07:00:27Z unix=1930806027 wall=2031-03-09T02:00:27 gap-until(2031-03-09T03:00:27) type=1 -04 EDT dst
|
||||
0224: 2031-11-02T06:00:27Z unix=1951365627 wall=2031-11-02T01:00:27 fold-until(2031-11-02T02:00:27) type=2 -05 EST
|
||||
0225: 2032-03-14T07:00:27Z unix=1962860427 wall=2032-03-14T02:00:27 gap-until(2032-03-14T03:00:27) type=1 -04 EDT dst
|
||||
0226: 2032-11-07T06:00:27Z unix=1983420027 wall=2032-11-07T01:00:27 fold-until(2032-11-07T02:00:27) type=2 -05 EST
|
||||
0227: 2033-03-13T07:00:27Z unix=1994310027 wall=2033-03-13T02:00:27 gap-until(2033-03-13T03:00:27) type=1 -04 EDT dst
|
||||
0228: 2033-11-06T06:00:27Z unix=2014869627 wall=2033-11-06T01:00:27 fold-until(2033-11-06T02:00:27) type=2 -05 EST
|
||||
0229: 2034-03-12T07:00:27Z unix=2025759627 wall=2034-03-12T02:00:27 gap-until(2034-03-12T03:00:27) type=1 -04 EDT dst
|
||||
0230: 2034-11-05T06:00:27Z unix=2046319227 wall=2034-11-05T01:00:27 fold-until(2034-11-05T02:00:27) type=2 -05 EST
|
||||
0231: 2035-03-11T07:00:27Z unix=2057209227 wall=2035-03-11T02:00:27 gap-until(2035-03-11T03:00:27) type=1 -04 EDT dst
|
||||
0232: 2035-11-04T06:00:27Z unix=2077768827 wall=2035-11-04T01:00:27 fold-until(2035-11-04T02:00:27) type=2 -05 EST
|
||||
0233: 2036-03-09T07:00:27Z unix=2088658827 wall=2036-03-09T02:00:27 gap-until(2036-03-09T03:00:27) type=1 -04 EDT dst
|
||||
0234: 2036-11-02T06:00:27Z unix=2109218427 wall=2036-11-02T01:00:27 fold-until(2036-11-02T02:00:27) type=2 -05 EST
|
||||
0235: 2037-03-08T07:00:27Z unix=2120108427 wall=2037-03-08T02:00:27 gap-until(2037-03-08T03:00:27) type=1 -04 EDT dst
|
||||
0236: 2037-11-01T06:00:27Z unix=2140668027 wall=2037-11-01T01:00:27 fold-until(2037-11-01T02:00:27) type=2 -05 EST
|
||||
LEAP SECONDS
|
||||
1972-07-01T00:00:00 correction=1
|
||||
1973-01-01T00:00:01 correction=2
|
||||
1974-01-01T00:00:02 correction=3
|
||||
1975-01-01T00:00:03 correction=4
|
||||
1976-01-01T00:00:04 correction=5
|
||||
1977-01-01T00:00:05 correction=6
|
||||
1978-01-01T00:00:06 correction=7
|
||||
1979-01-01T00:00:07 correction=8
|
||||
1980-01-01T00:00:08 correction=9
|
||||
1981-07-01T00:00:09 correction=10
|
||||
1982-07-01T00:00:10 correction=11
|
||||
1983-07-01T00:00:11 correction=12
|
||||
1985-07-01T00:00:12 correction=13
|
||||
1988-01-01T00:00:13 correction=14
|
||||
1990-01-01T00:00:14 correction=15
|
||||
1991-01-01T00:00:15 correction=16
|
||||
1992-07-01T00:00:16 correction=17
|
||||
1993-07-01T00:00:17 correction=18
|
||||
1994-07-01T00:00:18 correction=19
|
||||
1996-01-01T00:00:19 correction=20
|
||||
1997-07-01T00:00:20 correction=21
|
||||
1999-01-01T00:00:21 correction=22
|
||||
2006-01-01T00:00:22 correction=23
|
||||
2009-01-01T00:00:23 correction=24
|
||||
2012-07-01T00:00:24 correction=25
|
||||
2015-07-01T00:00:25 correction=26
|
||||
2017-01-01T00:00:26 correction=27
|
||||
POSIX TIME ZONE STRING
|
||||
EST5EDT,M3.2.0,M11.1.0
|
||||
89
src/tz/testdata.rs
Normal file
89
src/tz/testdata.rs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
use crate::tz::Tzif;
|
||||
|
||||
/// A list of all TZif files in our testdata directory.
|
||||
///
|
||||
/// Feel free to add more if there are other "interesting" cases. Note that
|
||||
/// some tests iterate over this slice to check each entry. So adding a new
|
||||
/// test file here might require updating some tests.
|
||||
///
|
||||
/// # Revisions
|
||||
///
|
||||
/// * `2024-03-27`: Initial set pulled from my local copy of `tzdata 2024a`.
|
||||
pub(crate) const TZIF_TEST_FILES: &[TzifTestFile] = &[
|
||||
TzifTestFile {
|
||||
name: "America/New_York",
|
||||
data: include_bytes!("testdata/america-new-york.tzif"),
|
||||
},
|
||||
TzifTestFile {
|
||||
name: "America/Sitka",
|
||||
data: include_bytes!("testdata/america-sitka.tzif"),
|
||||
},
|
||||
TzifTestFile {
|
||||
name: "America/St_Johns",
|
||||
data: include_bytes!("testdata/america-st-johns.tzif"),
|
||||
},
|
||||
TzifTestFile {
|
||||
name: "right/America/New_York",
|
||||
data: include_bytes!("testdata/right-america-new-york.tzif"),
|
||||
},
|
||||
TzifTestFile {
|
||||
name: "Antarctica/Troll",
|
||||
data: include_bytes!("testdata/antarctica-troll.tzif"),
|
||||
},
|
||||
TzifTestFile {
|
||||
name: "Australia/Tasmania",
|
||||
data: include_bytes!("testdata/australia-tasmania.tzif"),
|
||||
},
|
||||
TzifTestFile {
|
||||
name: "Europe/Dublin",
|
||||
data: include_bytes!("testdata/europe-dublin.tzif"),
|
||||
},
|
||||
TzifTestFile {
|
||||
name: "Pacific/Honolulu",
|
||||
data: include_bytes!("testdata/pacific-honolulu.tzif"),
|
||||
},
|
||||
];
|
||||
|
||||
/// A single TZif datum.
|
||||
///
|
||||
/// It contains the name of the time zone and the raw bytes of the
|
||||
/// corresponding TZif file.
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) struct TzifTestFile {
|
||||
pub(crate) name: &'static str,
|
||||
pub(crate) data: &'static [u8],
|
||||
}
|
||||
|
||||
impl TzifTestFile {
|
||||
/// Look up the TZif test file for the given time zone name.
|
||||
///
|
||||
/// If one doesn't exist, then this panics and fails the current
|
||||
/// test.
|
||||
pub(crate) fn get(name: &str) -> TzifTestFile {
|
||||
for &tzif_file in TZIF_TEST_FILES {
|
||||
if tzif_file.name == name {
|
||||
return tzif_file;
|
||||
}
|
||||
}
|
||||
panic!("could not find TZif test file for {name:?}")
|
||||
}
|
||||
|
||||
/// Parse this test TZif data into a structured representation.
|
||||
pub(crate) fn parse(self) -> Tzif {
|
||||
Tzif::parse(self.name, self.data).unwrap_or_else(|err| {
|
||||
panic!("failed to parse TZif test file for {:?}: {err}", self.name)
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse this test TZif data as if it were V1.
|
||||
pub(crate) fn parse_v1(self) -> Tzif {
|
||||
let mut data = self.data.to_vec();
|
||||
data[4] = 0;
|
||||
Tzif::parse(self.name, &data).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"failed to parse V1 TZif test file for {:?}: {err}",
|
||||
self.name
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
BIN
src/tz/testdata/america-new-york.tzif
vendored
Normal file
BIN
src/tz/testdata/america-new-york.tzif
vendored
Normal file
Binary file not shown.
BIN
src/tz/testdata/america-sitka.tzif
vendored
Normal file
BIN
src/tz/testdata/america-sitka.tzif
vendored
Normal file
Binary file not shown.
BIN
src/tz/testdata/america-st-johns.tzif
vendored
Normal file
BIN
src/tz/testdata/america-st-johns.tzif
vendored
Normal file
Binary file not shown.
BIN
src/tz/testdata/antarctica-troll.tzif
vendored
Normal file
BIN
src/tz/testdata/antarctica-troll.tzif
vendored
Normal file
Binary file not shown.
BIN
src/tz/testdata/australia-tasmania.tzif
vendored
Normal file
BIN
src/tz/testdata/australia-tasmania.tzif
vendored
Normal file
Binary file not shown.
BIN
src/tz/testdata/europe-dublin.tzif
vendored
Normal file
BIN
src/tz/testdata/europe-dublin.tzif
vendored
Normal file
Binary file not shown.
BIN
src/tz/testdata/pacific-honolulu.tzif
vendored
Normal file
BIN
src/tz/testdata/pacific-honolulu.tzif
vendored
Normal file
Binary file not shown.
BIN
src/tz/testdata/right-america-new-york.tzif
vendored
Normal file
BIN
src/tz/testdata/right-america-new-york.tzif
vendored
Normal file
Binary file not shown.
1424
src/tz/tzif.rs
Normal file
1424
src/tz/tzif.rs
Normal file
File diff suppressed because it is too large
Load diff
2770
src/tz/zic.rs
Normal file
2770
src/tz/zic.rs
Normal file
File diff suppressed because it is too large
Load diff
57
src/util/alloc.rs
Normal file
57
src/util/alloc.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// The `MaybeBox` type is kind of suspect. It's mostly used to shrink error
|
||||
// types whenever we have `alloc` available. But it might actually make more
|
||||
// sense to reduce the amount of error information available when `alloc`
|
||||
// isn't enabled, since presumably the size of types is *more* of an issue in
|
||||
// environments without `alloc`. If you find yourself in this conundrum, please
|
||||
// file an issue.
|
||||
|
||||
/// A conditional `Box` for some type.
|
||||
///
|
||||
/// This uses a `Box` internally when the `alloc` crate feature is enabled,
|
||||
/// and inlines the `T` into this type otherwise. This is useful for reducing
|
||||
/// the size of types when dynamic memory allocation is available.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub(crate) struct MaybeBox<T>(
|
||||
#[cfg(feature = "alloc")] alloc::boxed::Box<T>,
|
||||
#[cfg(not(feature = "alloc"))] T,
|
||||
);
|
||||
|
||||
impl<T> MaybeBox<T> {
|
||||
/// Create a new conditional box for `T`.
|
||||
pub(crate) fn new(t: T) -> MaybeBox<T> {
|
||||
#[cfg(feature = "alloc")]
|
||||
{
|
||||
MaybeBox(alloc::boxed::Box::new(t))
|
||||
}
|
||||
#[cfg(not(feature = "alloc"))]
|
||||
{
|
||||
MaybeBox(t)
|
||||
}
|
||||
}
|
||||
|
||||
/// Move out of this box.
|
||||
pub(crate) fn into_inner(this: MaybeBox<T>) -> T {
|
||||
#[cfg(feature = "alloc")]
|
||||
{
|
||||
*this.0
|
||||
}
|
||||
#[cfg(not(feature = "alloc"))]
|
||||
{
|
||||
this.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> core::ops::Deref for MaybeBox<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> core::ops::DerefMut for MaybeBox<T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
175
src/util/common.rs
Normal file
175
src/util/common.rs
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/// A collection of datetime related utility functions.
|
||||
///
|
||||
/// # Constant functions
|
||||
///
|
||||
/// This module also contains some utilities for making some API items `const`.
|
||||
///
|
||||
/// One of the main reasons why more of this crate isn't `const` is because of
|
||||
/// our ranged integer types. We very specifically use those types wherever we
|
||||
/// do arithmetic as a mitigation for the absolute insance boundary conditions
|
||||
/// that one must deal with in a datetime library. Unfortunately, these range
|
||||
/// integer types are very difficult to make use of in `const` context. One of
|
||||
/// the main blockers is the fact that Rust doesn't support `const` methods in
|
||||
/// traits. That means we'd be unable to do `x + y` where `x` and `y` are range
|
||||
/// integers. (Normal `x + y` arithmetic only works in `const` today because of
|
||||
/// special support for Rust's standard integer types.)
|
||||
///
|
||||
/// With that said, it is sometimes useful to provide APIs that are const. For
|
||||
/// example, `Date::new`. But we still need to do some checking on the inputs
|
||||
/// to ensure they are valid. Since most of our arithmetic code is defined
|
||||
/// using range integers, we have to re-write some it here using standard
|
||||
/// primitive types.
|
||||
///
|
||||
/// In general, this code should not be used unless it is specifically required
|
||||
/// to make something `const` AND if it is worth making it `const` in the first
|
||||
/// place. Remember, much of this library _could_ be `const` if we were willing
|
||||
/// to write `const`-compatible code, but I deemed it far too annoying to do
|
||||
/// so.
|
||||
use crate::util::{
|
||||
rangeint::{self, ri16, ri32, ri64, ri8},
|
||||
t::{Day, Month, Year, C},
|
||||
};
|
||||
|
||||
/// Returns true if and only if the given year is a leap year.
|
||||
///
|
||||
/// A leap year is a year with 366 days. Typical years have 365 days.
|
||||
pub(crate) fn is_leap_year(year: Year) -> bool {
|
||||
year % C(4) == 0 && (year % C(100) != 0 || year % C(400) == 0)
|
||||
}
|
||||
|
||||
/// Returns true if and only if the given year is a leap year.
|
||||
///
|
||||
/// A leap year is a year with 366 days. Typical years have 365 days.
|
||||
///
|
||||
/// This doesn't used range integers and is thus `const`.
|
||||
pub(crate) const fn is_leap_year_unranged(year: i16) -> bool {
|
||||
year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
|
||||
}
|
||||
|
||||
/// Saturates the given day in the month.
|
||||
///
|
||||
/// That is, if the day exceeds the maximum number of days in the given year
|
||||
/// and month, then this returns the maximum. Otherwise, it returns the day
|
||||
/// given.
|
||||
pub(crate) fn saturate_day_in_month(
|
||||
year: Year,
|
||||
month: Month,
|
||||
day: Day,
|
||||
) -> Day {
|
||||
day.min(days_in_month(year, month))
|
||||
}
|
||||
|
||||
/// Returns the number of days in the given year and month.
|
||||
///
|
||||
/// This correctly returns `29` when the year is a leap year and the month is
|
||||
/// February.
|
||||
pub(crate) fn days_in_month(year: Year, month: Month) -> Day {
|
||||
if month == 2 && is_leap_year(year) {
|
||||
Day::N::<29>()
|
||||
} else {
|
||||
days_in_month_common_year(month)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the number of days in the given month.
|
||||
///
|
||||
/// When the given month is invalid, this returns `0`.
|
||||
pub(crate) const fn days_in_month_unranged(year: i16, month: i8) -> i8 {
|
||||
match month {
|
||||
1 => 31,
|
||||
2 if is_leap_year_unranged(year) => 29,
|
||||
2 => 28,
|
||||
3 => 31,
|
||||
4 => 30,
|
||||
5 => 31,
|
||||
6 => 30,
|
||||
7 => 31,
|
||||
8 => 31,
|
||||
9 => 30,
|
||||
10 => 31,
|
||||
11 => 30,
|
||||
12 => 31,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of days in the given month for a non-leap year.
|
||||
pub(crate) fn days_in_month_common_year(month: Month) -> Day {
|
||||
const BY_MONTH: [Day; 13] = [
|
||||
Day::N::<0>(),
|
||||
Day::N::<31>(),
|
||||
Day::N::<28>(),
|
||||
Day::N::<31>(),
|
||||
Day::N::<30>(),
|
||||
Day::N::<31>(),
|
||||
Day::N::<30>(),
|
||||
Day::N::<31>(),
|
||||
Day::N::<31>(),
|
||||
Day::N::<30>(),
|
||||
Day::N::<31>(),
|
||||
Day::N::<30>(),
|
||||
Day::N::<31>(),
|
||||
];
|
||||
// FIXME: How do we want to handle indexing with range integers more
|
||||
// generally? At the very least add `as_usize()`...
|
||||
BY_MONTH[usize::from(month.get() as u8)]
|
||||
}
|
||||
|
||||
/// Returns the number of days in the given month for a leap year.
|
||||
pub(crate) fn days_in_month_leap_year(month: Month) -> Day {
|
||||
const BY_MONTH: [Day; 13] = [
|
||||
Day::N::<0>(),
|
||||
Day::N::<31>(),
|
||||
Day::N::<29>(),
|
||||
Day::N::<31>(),
|
||||
Day::N::<30>(),
|
||||
Day::N::<31>(),
|
||||
Day::N::<30>(),
|
||||
Day::N::<31>(),
|
||||
Day::N::<31>(),
|
||||
Day::N::<30>(),
|
||||
Day::N::<31>(),
|
||||
Day::N::<30>(),
|
||||
Day::N::<31>(),
|
||||
];
|
||||
// FIXME: How do we want to handle indexing with range integers more
|
||||
// generally? At the very least add `as_usize()`...
|
||||
BY_MONTH[usize::from(month.get() as u8)]
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn t_is_leap_year() {
|
||||
let is_leap_year = |y: i16| is_leap_year(Year::new(y).unwrap());
|
||||
assert!(is_leap_year(2024));
|
||||
assert!(!is_leap_year(2023));
|
||||
assert!(!is_leap_year(2025));
|
||||
assert!(is_leap_year(2000));
|
||||
assert!(!is_leap_year(1900));
|
||||
assert!(!is_leap_year(1800));
|
||||
assert!(!is_leap_year(1700));
|
||||
assert!(is_leap_year(1600));
|
||||
assert!(is_leap_year(0));
|
||||
assert!(!is_leap_year(-1));
|
||||
assert!(!is_leap_year(-2));
|
||||
assert!(!is_leap_year(-3));
|
||||
assert!(is_leap_year(-4));
|
||||
assert!(!is_leap_year(-100));
|
||||
assert!(!is_leap_year(-200));
|
||||
assert!(!is_leap_year(-300));
|
||||
assert!(is_leap_year(400));
|
||||
assert!(!is_leap_year(9999));
|
||||
assert!(!is_leap_year(-9999));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn t_days_in_month() {
|
||||
let days_in_month = |year: i16, month| {
|
||||
days_in_month(Year::new(year).unwrap(), Month::new(month).unwrap())
|
||||
};
|
||||
assert_eq!(28, days_in_month(-9999, 2).get());
|
||||
}
|
||||
}
|
||||
140
src/util/escape.rs
Normal file
140
src/util/escape.rs
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*!
|
||||
Provides convenience routines for escaping raw bytes.
|
||||
|
||||
This was copied from `regex-automata` with a few light edits.
|
||||
*/
|
||||
|
||||
/// Provides a convenient `Debug` implementation for a `u8`.
|
||||
///
|
||||
/// The `Debug` impl treats the byte as an ASCII, and emits a human readable
|
||||
/// representation of it. If the byte isn't ASCII, then it's emitted as a hex
|
||||
/// escape sequence.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Byte(pub u8);
|
||||
|
||||
impl core::fmt::Display for Byte {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
core::fmt::Debug::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for Byte {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
// Special case ASCII space. It's too hard to read otherwise, so
|
||||
// put quotes around it. I sometimes wonder whether just '\x20' would
|
||||
// be better...
|
||||
if self.0 == b' ' {
|
||||
return write!(f, "' '");
|
||||
}
|
||||
// 10 bytes is enough to cover any output from ascii::escape_default.
|
||||
let mut bytes = [0u8; 10];
|
||||
let mut len = 0;
|
||||
for (i, mut b) in core::ascii::escape_default(self.0).enumerate() {
|
||||
// capitalize \xab to \xAB
|
||||
if i >= 2 && b'a' <= b && b <= b'f' {
|
||||
b -= 32;
|
||||
}
|
||||
bytes[len] = b;
|
||||
len += 1;
|
||||
}
|
||||
write!(f, "{}", core::str::from_utf8(&bytes[..len]).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides a convenient `Debug` implementation for `&[u8]`.
|
||||
///
|
||||
/// This generally works best when the bytes are presumed to be mostly UTF-8,
|
||||
/// but will work for anything. For any bytes that aren't UTF-8, they are
|
||||
/// emitted as hex escape sequences.
|
||||
pub struct Bytes<'a>(pub &'a [u8]);
|
||||
|
||||
impl<'a> core::fmt::Display for Bytes<'a> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
// This is a sad re-implementation of a similar impl found in bstr.
|
||||
let mut bytes = self.0;
|
||||
while let Some(result) = utf8_decode(bytes) {
|
||||
let ch = match result {
|
||||
Ok(ch) => ch,
|
||||
Err(byte) => {
|
||||
write!(f, r"\x{:02x}", byte)?;
|
||||
bytes = &bytes[1..];
|
||||
continue;
|
||||
}
|
||||
};
|
||||
bytes = &bytes[ch.len_utf8()..];
|
||||
match ch {
|
||||
'\0' => write!(f, "\\0")?,
|
||||
// ASCII control characters except \0, \n, \r, \t
|
||||
'\x01'..='\x08'
|
||||
| '\x0b'
|
||||
| '\x0c'
|
||||
| '\x0e'..='\x19'
|
||||
| '\x7f' => {
|
||||
write!(f, "\\x{:02x}", u32::from(ch))?;
|
||||
}
|
||||
'\n' | '\r' | '\t' | _ => {
|
||||
write!(f, "{}", ch.escape_debug())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> core::fmt::Debug for Bytes<'a> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
write!(f, "\"")?;
|
||||
core::fmt::Display::fmt(self, f)?;
|
||||
write!(f, "\"")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Decodes the next UTF-8 encoded codepoint from the given byte slice.
|
||||
///
|
||||
/// If no valid encoding of a codepoint exists at the beginning of the given
|
||||
/// byte slice, then the first byte is returned instead.
|
||||
///
|
||||
/// This returns `None` if and only if `bytes` is empty.
|
||||
///
|
||||
/// This never panics.
|
||||
///
|
||||
/// *WARNING*: This is not designed for performance. If you're looking for a
|
||||
/// fast UTF-8 decoder, this is not it. If you feel like you need one in this
|
||||
/// crate, then please file an issue and discuss your use case.
|
||||
fn utf8_decode(bytes: &[u8]) -> Option<Result<char, u8>> {
|
||||
if bytes.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let len = match utf8_len(bytes[0]) {
|
||||
None => return Some(Err(bytes[0])),
|
||||
Some(len) if len > bytes.len() => return Some(Err(bytes[0])),
|
||||
Some(1) => return Some(Ok(char::from(bytes[0]))),
|
||||
Some(len) => len,
|
||||
};
|
||||
match core::str::from_utf8(&bytes[..len]) {
|
||||
Ok(s) => Some(Ok(s.chars().next().unwrap())),
|
||||
Err(_) => Some(Err(bytes[0])),
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a UTF-8 leading byte, this returns the total number of code units
|
||||
/// in the following encoded codepoint.
|
||||
///
|
||||
/// If the given byte is not a valid UTF-8 leading byte, then this returns
|
||||
/// `None`.
|
||||
fn utf8_len(byte: u8) -> Option<usize> {
|
||||
if byte <= 0x7F {
|
||||
return Some(1);
|
||||
} else if byte & 0b1100_0000 == 0b1000_0000 {
|
||||
return None;
|
||||
} else if byte <= 0b1101_1111 {
|
||||
Some(2)
|
||||
} else if byte <= 0b1110_1111 {
|
||||
Some(3)
|
||||
} else if byte <= 0b1111_0111 {
|
||||
Some(4)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
6
src/util/mod.rs
Normal file
6
src/util/mod.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
pub(crate) mod alloc;
|
||||
pub(crate) mod common;
|
||||
pub(crate) mod escape;
|
||||
pub(crate) mod parse;
|
||||
pub(crate) mod rangeint;
|
||||
pub(crate) mod t;
|
||||
218
src/util/parse.rs
Normal file
218
src/util/parse.rs
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
use alloc::{
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::{err, Error},
|
||||
util::escape::{Byte, Bytes},
|
||||
};
|
||||
|
||||
/// Parses an `i64` number from the beginning to the end of the given slice of
|
||||
/// ASCII digit characters.
|
||||
///
|
||||
/// If any byte in the given slice is not `[0-9]`, then this returns an error.
|
||||
/// Similarly, if the number parsed does not fit into a `i64`, then this
|
||||
/// returns an error. Notably, this routine does not permit parsing a negative
|
||||
/// integer. (We use `i64` because everything in this crate uses signed
|
||||
/// integers, and because a higher level routine might want to parse the sign
|
||||
/// and then apply it to the result of this routine.)
|
||||
pub(crate) fn i64(bytes: &[u8]) -> Result<i64, Error> {
|
||||
if bytes.is_empty() {
|
||||
return Err(err!("invalid number, no digits found"));
|
||||
}
|
||||
let mut n: i64 = 0;
|
||||
for &byte in bytes {
|
||||
let digit = match byte.checked_sub(b'0') {
|
||||
None => {
|
||||
return Err(err!(
|
||||
"invalid digit, expected 0-9 but got {}",
|
||||
Byte(byte),
|
||||
));
|
||||
}
|
||||
Some(digit) if digit > 9 => {
|
||||
return Err(err!(
|
||||
"invalid digit, expected 0-9 but got {}",
|
||||
Byte(byte),
|
||||
))
|
||||
}
|
||||
Some(digit) => {
|
||||
debug_assert!((0..=9).contains(&digit));
|
||||
i64::from(digit)
|
||||
}
|
||||
};
|
||||
n = n.checked_mul(10).and_then(|n| n.checked_add(digit)).ok_or_else(
|
||||
|| {
|
||||
err!(
|
||||
"number '{}' too big to parse into 64-bit integer",
|
||||
Bytes(bytes),
|
||||
)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
Ok(n)
|
||||
}
|
||||
|
||||
/// Parses an `i64` fractional number from the beginning to the end of the
|
||||
/// given slice of ASCII digit characters.
|
||||
///
|
||||
/// The fraction's maximum precision must be provided. The returned integer
|
||||
/// will always be in units of `10^{max_precision}`. For example, to parse a
|
||||
/// fractional amount of seconds with a maximum precision of nanoseconds, then
|
||||
/// use `max_precision=9`.
|
||||
///
|
||||
/// If any byte in the given slice is not `[0-9]`, then this returns an error.
|
||||
/// Similarly, if the fraction parsed does not fit into a `i64`, then this
|
||||
/// returns an error. Notably, this routine does not permit parsing a negative
|
||||
/// integer. (We use `i64` because everything in this crate uses signed
|
||||
/// integers, and because a higher level routine might want to parse the sign
|
||||
/// and then apply it to the result of this routine.)
|
||||
pub(crate) fn fraction(
|
||||
bytes: &[u8],
|
||||
max_precision: usize,
|
||||
) -> Result<i64, Error> {
|
||||
if bytes.is_empty() {
|
||||
return Err(err!("invalid fraction, no digits found"));
|
||||
} else if bytes.len() > max_precision {
|
||||
return Err(err!(
|
||||
"invalid fraction, too many digits \
|
||||
(at most {max_precision} are allowed"
|
||||
));
|
||||
}
|
||||
let mut n: i64 = 0;
|
||||
for &byte in bytes {
|
||||
let digit = match byte.checked_sub(b'0') {
|
||||
None => {
|
||||
return Err(err!(
|
||||
"invalid fractional digit, expected 0-9 but got {}",
|
||||
Byte(byte),
|
||||
));
|
||||
}
|
||||
Some(digit) if digit > 9 => {
|
||||
return Err(err!(
|
||||
"invalid fractional digit, expected 0-9 but got {}",
|
||||
Byte(byte),
|
||||
))
|
||||
}
|
||||
Some(digit) => {
|
||||
debug_assert!((0..=9).contains(&digit));
|
||||
i64::from(digit)
|
||||
}
|
||||
};
|
||||
n = n.checked_mul(10).and_then(|n| n.checked_add(digit)).ok_or_else(
|
||||
|| {
|
||||
err!(
|
||||
"fractional '{}' too big to parse into 64-bit integer",
|
||||
Bytes(bytes),
|
||||
)
|
||||
},
|
||||
)?;
|
||||
}
|
||||
for _ in bytes.len()..max_precision {
|
||||
n = n.checked_mul(10).ok_or_else(|| {
|
||||
err!(
|
||||
"fractional '{}' too big to parse into 64-bit integer \
|
||||
(too much precision supported)",
|
||||
Bytes(bytes)
|
||||
)
|
||||
})?;
|
||||
}
|
||||
Ok(n)
|
||||
}
|
||||
|
||||
/// Parses an `OsStr` into a `&str` when `&[u8]` isn't easily available.
|
||||
///
|
||||
/// This is effectively `OsStr::to_str`, but with a slightly better error
|
||||
/// message.
|
||||
pub(crate) fn os_str_utf8<'o, O>(os_str: &'o O) -> Result<&'o str, Error>
|
||||
where
|
||||
O: ?Sized + AsRef<std::ffi::OsStr>,
|
||||
{
|
||||
let os_str = os_str.as_ref();
|
||||
os_str
|
||||
.to_str()
|
||||
.ok_or_else(|| err!("environment value {os_str:?} is not valid UTF-8"))
|
||||
}
|
||||
|
||||
/// Parses an `OsStr` into a `&str` when `&[u8]` isn't easily available.
|
||||
///
|
||||
/// The main difference between this and `OsStr::to_str` is that this will
|
||||
/// be a zero-cost conversion on Unix platforms to `&[u8]`. On Windows, this
|
||||
/// will do UTF-8 validation and return an error if it's invalid UTF-8.
|
||||
pub(crate) fn os_str_bytes<'o, O>(os_str: &'o O) -> Result<&'o [u8], Error>
|
||||
where
|
||||
O: ?Sized + AsRef<std::ffi::OsStr>,
|
||||
{
|
||||
let os_str = os_str.as_ref();
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
Ok(os_str.as_bytes())
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
{
|
||||
let string = os_str.to_str().ok_or_else(|| {
|
||||
err!("environment value {os_str:?} is not valid UTF-8")
|
||||
})?;
|
||||
// It is suspect that we're doing UTF-8 validation and then throwing
|
||||
// away the fact that we did UTF-8 validation. So this could lead
|
||||
// to an extra UTF-8 check if the caller ultimately needs UTF-8. If
|
||||
// that's important, we can add a new API that returns a `&str`. But it
|
||||
// probably won't matter because an `OsStr` in this crate is usually
|
||||
// just an environment variable.
|
||||
Ok(string.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits the given input into two slices at the given position.
|
||||
///
|
||||
/// If the position is greater than the length of the slice given, then this
|
||||
/// returns `None`.
|
||||
pub(crate) fn split(input: &[u8], at: usize) -> Option<(&[u8], &[u8])> {
|
||||
if at > input.len() {
|
||||
None
|
||||
} else {
|
||||
Some(input.split_at(at))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a function that converts two slices to an offset.
|
||||
///
|
||||
/// It takes the starting point as input and returns a function that, when
|
||||
/// given an ending point (greater than or equal to the starting point), then
|
||||
/// the corresponding pointers are subtracted and an offset relative to the
|
||||
/// starting point is returned.
|
||||
///
|
||||
/// This is useful as a helper function in parsing routines that use slices
|
||||
/// but want to report offsets.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if the ending point is not a suffix slice of `start`.
|
||||
pub(crate) fn offseter<'a>(
|
||||
start: &'a [u8],
|
||||
) -> impl Fn(&'a [u8]) -> usize + 'a {
|
||||
move |end| (end.as_ptr() as usize) - (start.as_ptr() as usize)
|
||||
}
|
||||
|
||||
/// Returns a function that converts two slices to the slice between them.
|
||||
///
|
||||
/// This takes a starting point as input and returns a function that, when
|
||||
/// given an ending point (greater than or equal to the starting point), it
|
||||
/// returns a slice beginning at the starting point and ending just at the
|
||||
/// ending point.
|
||||
///
|
||||
/// This is useful as a helper function in parsing routines.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This may panic if the ending point is not a suffix slice of `start`.
|
||||
pub(crate) fn slicer<'a>(
|
||||
start: &'a [u8],
|
||||
) -> impl Fn(&'a [u8]) -> &'a [u8] + 'a {
|
||||
let mkoffset = offseter(start);
|
||||
move |end| {
|
||||
let offset = mkoffset(end);
|
||||
&start[..offset]
|
||||
}
|
||||
}
|
||||
2420
src/util/rangeint.rs
Normal file
2420
src/util/rangeint.rs
Normal file
File diff suppressed because it is too large
Load diff
635
src/util/t.rs
Normal file
635
src/util/t.rs
Normal file
|
|
@ -0,0 +1,635 @@
|
|||
use crate::util::rangeint::{self, ri128, ri16, ri32, ri64, ri8, RInto};
|
||||
|
||||
/// A type alias for the sign of a number.
|
||||
///
|
||||
/// It can be -1 for a negative sign, 1 for a positive sign or 0 for no sign.
|
||||
pub(crate) type Sign = ri8<-1, 1>;
|
||||
|
||||
/// A type alias for a ranged integer with no units.
|
||||
///
|
||||
/// In particular, the range of this type is just the range of an `i64`. This
|
||||
/// is useful when too many things with different units need to be combined at
|
||||
/// once, and it's just too painful to keep them straight. In cases like that,
|
||||
/// it's useful to just convert everything to `NoUnits`, do the necessary math,
|
||||
/// and then convert back to the appropriate ranged types.
|
||||
///
|
||||
/// Note that we don't actually lose much by doing this, since the computed
|
||||
/// min/max values are retained even when converting *to and from* this type.
|
||||
/// In general, this type is just about making some math easier by making
|
||||
/// everything uniform.
|
||||
pub(crate) type NoUnits = ri64<{ i64::MIN as i128 }, { i64::MAX as i128 }>;
|
||||
|
||||
/// A type alias for a ranged 128-bit integer with no units.
|
||||
///
|
||||
/// This is like `NoUnits`, but useful in contexts where one wants to limit
|
||||
/// values to what can be represented by an `i128`.
|
||||
pub(crate) type NoUnits128 = ri128<{ i128::MIN }, { i128::MAX }>;
|
||||
|
||||
/// A type alias for a ranged 32-bit integer with no units.
|
||||
///
|
||||
/// This is like `NoUnits`, but useful in contexts where one wants to limit
|
||||
/// values to what can be represented by an `i32`.
|
||||
pub(crate) type NoUnits32 = ri32<{ i32::MIN as i128 }, { i32::MAX as i128 }>;
|
||||
|
||||
/// A type alias for a ranged 16-bit integer with no units.
|
||||
///
|
||||
/// This is like `NoUnits`, but useful in contexts where one wants to limit
|
||||
/// values to what can be represented by an `i16`.
|
||||
pub(crate) type NoUnits16 = ri16<{ i16::MIN as i128 }, { i16::MAX as i128 }>;
|
||||
|
||||
/// A type alias for a ranged 8-bit integer with no units.
|
||||
///
|
||||
/// This is like `NoUnits`, but useful in contexts where one wants to limit
|
||||
/// values to what can be represented by an `i8`.
|
||||
pub(crate) type NoUnits8 = ri8<{ i8::MIN as i128 }, { i8::MAX as i128 }>;
|
||||
|
||||
/// The range of years supported by jiff.
|
||||
///
|
||||
/// This is ultimately where some of the other ranges (like `UnixSeconds`)
|
||||
/// were determined from. That is, the range of years is the primary point at
|
||||
/// which the space of supported time instants is derived from. If one wanted
|
||||
/// to expand this range, you'd need to change it here and then compute the
|
||||
/// corresponding min/max values for `UnixSeconds`.
|
||||
pub(crate) type Year = ri16<-9999, 9999>;
|
||||
|
||||
/// The range of BCE years supported by jiff.
|
||||
pub(crate) type YearBCE = ri16<1, { Year::MAX + 1 }>;
|
||||
|
||||
/// The range of Unix seconds supported by Jiff.
|
||||
///
|
||||
/// This range should correspond to the first second of `Year::MIN` up through
|
||||
/// (and including) the last second of `Year::MAX`. Actually computing that is
|
||||
/// non-trivial, however, it can be computed easily enough using Unix programs
|
||||
/// like `date`:
|
||||
///
|
||||
/// ```text
|
||||
/// $ TZ=0 date -d 'Mon Jan 1 12:00:00 AM -9999' +'%s'
|
||||
/// date: invalid date ‘Mon Jan 1 12:00:00 AM -9999’
|
||||
/// $ TZ=0 date -d 'Fri Dec 31 23:59:59 9999' +'%s'
|
||||
/// 253402300799
|
||||
/// ```
|
||||
///
|
||||
/// Well, almost easily enough. `date` apparently doesn't support negative
|
||||
/// years. But it does support negative timestamps:
|
||||
///
|
||||
/// ```text
|
||||
/// $ TZ=0 date -d '@-377705116800'
|
||||
/// Mon Jan 1 12:00:00 AM -9999
|
||||
/// $ TZ=0 date -d '@253402300799'
|
||||
/// Fri Dec 31 11:59:59 PM 9999
|
||||
/// ```
|
||||
///
|
||||
/// With that said, we actually end up restricting the range a bit more than
|
||||
/// what's above. Namely, what's above is what we support for civil datetimes.
|
||||
/// Because of time zones, we need to choose whether all `Instant` values
|
||||
/// can be infallibly converted to `civil::DateTime` values, or whether all
|
||||
/// `civil::DateTime` values can be infallibly converted to `Instant` values.
|
||||
/// I chose the former because getting a civil datetime is important for
|
||||
/// formatting. If I didn't choose the former, there would be some instants
|
||||
/// that could not be formatted. Thus, we make room by shrinking the range of
|
||||
/// allowed instants by precisely the maximum supported time zone offset.
|
||||
pub(crate) type UnixSeconds = ri64<
|
||||
{ -377705116800 - SpanZoneOffset::MIN },
|
||||
{ 253402300799 - SpanZoneOffset::MAX },
|
||||
>;
|
||||
|
||||
/// Like UnixSeconds, but expressed in units of nanoseconds.
|
||||
pub(crate) type UnixNanoseconds = ri128<
|
||||
{ UnixSeconds::MIN * NANOS_PER_SECOND.bound() },
|
||||
{
|
||||
UnixSeconds::MAX * NANOS_PER_SECOND.bound() + FractionalNanosecond::MAX
|
||||
},
|
||||
>;
|
||||
|
||||
/// A timestamp representing time since 1970-01-01T00:00:00Z, but in TAI.
|
||||
///
|
||||
/// TAI stands for "International Atomic Time." It doesn't bother with things
|
||||
/// like leap seconds because there is no requirement that it line up with
|
||||
/// mean solar time. The advantage of TAI over Unix time is that it can be
|
||||
/// unambiguously converted to and from UTC. The disadvantage is that you need
|
||||
/// a table of leap second offsets to work with it effectively.
|
||||
///
|
||||
/// Since leap second offsets can be added to Unix time to get TAI (or
|
||||
/// subtracted), we "make room" by shrinking the range of TAI time by 1 day on
|
||||
/// both ends when compared to Unix time. This makes it possible to convert all
|
||||
/// TAI timestamps to Unix timestamps. But, the reverse is fallible. (This is
|
||||
/// similar to the time zone offset dance. We need to choose one direction to
|
||||
/// be fallible and the other to be infallible. Unix timestamps tend to be used
|
||||
/// in more places, and it's also the default, so I deemed it more important to
|
||||
/// have infallible conversions *to* Unix time.)
|
||||
///
|
||||
/// We use 1 day here because it keeps things nice and even and because it
|
||||
/// will be a long time before leap second offsets (or whatever replaces it)
|
||||
/// tally up to more than 1 day.
|
||||
pub(crate) type TaiSeconds = ri64<
|
||||
{ UnixSeconds::MIN - LeapSecondOffset::MIN },
|
||||
{ UnixSeconds::MAX - LeapSecondOffset::MAX },
|
||||
>;
|
||||
|
||||
/// Like TaiSeconds, but expressed in units of nanoseconds.
|
||||
pub(crate) type TaiNanoseconds = ri128<
|
||||
{ TaiSeconds::MIN * NANOS_PER_SECOND.bound() },
|
||||
{ TaiSeconds::MAX * NANOS_PER_SECOND.bound() + FractionalNanosecond::MAX },
|
||||
>;
|
||||
|
||||
/// The maximum leap second offset that Jiff supports.
|
||||
///
|
||||
/// This could be bigger, but this seems big enough to last a long time.
|
||||
pub(crate) type LeapSecondOffset = ri64<
|
||||
{ -SECONDS_PER_CIVIL_DAY.bound() },
|
||||
{ SECONDS_PER_CIVIL_DAY.bound() },
|
||||
>;
|
||||
|
||||
/// The range of possible month values.
|
||||
pub(crate) type Month = ri8<1, 12>;
|
||||
|
||||
/// The range of a weekday, offset from zero.
|
||||
pub(crate) type WeekdayZero = ri8<0, 6>;
|
||||
|
||||
/// The range of a weekday, offset from one.
|
||||
pub(crate) type WeekdayOne = ri8<1, 7>;
|
||||
|
||||
/// The range of possible day values.
|
||||
///
|
||||
/// Obviously this range is not valid for every month. Therefore, code working
|
||||
/// with days needs to be careful to check that it is valid for whatever month
|
||||
/// is being used.
|
||||
pub(crate) type Day = ri8<1, 31>;
|
||||
|
||||
pub(crate) type ISOYear = ri16<-9999, 9999>;
|
||||
|
||||
pub(crate) type ISOWeek = ri8<1, 53>;
|
||||
|
||||
/// The range of possible hour values.
|
||||
pub(crate) type Hour = ri8<0, 23>;
|
||||
|
||||
/// The range of possible minute values.
|
||||
pub(crate) type Minute = ri8<0, 59>;
|
||||
|
||||
/// The range of possible second values for UTC.
|
||||
pub(crate) type UtcSecond = ri8<0, 60>;
|
||||
|
||||
/// The range of possible second values not accounting for leap seconds.
|
||||
pub(crate) type Second = ri8<0, 59>;
|
||||
|
||||
/// The range of possible millisecond values.
|
||||
pub(crate) type Millisecond = ri16<0, 999>;
|
||||
|
||||
/// The range of possible microsecond values.
|
||||
pub(crate) type Microsecond = ri16<0, 999>;
|
||||
|
||||
/// The range of possible nanosecond values.
|
||||
pub(crate) type Nanosecond = ri16<0, 999>;
|
||||
|
||||
/// The range of possible nanosecond values.
|
||||
pub(crate) type SubsecNanosecond = ri32<0, { NANOS_PER_SECOND.bound() - 1 }>;
|
||||
|
||||
/// A range representing each possible nanosecond in a single civil day.
|
||||
pub(crate) type CivilDayNanosecond =
|
||||
ri64<0, { NANOS_PER_CIVIL_DAY.bound() - 1 }>;
|
||||
|
||||
/// The number of seconds permitted in a single day.
|
||||
///
|
||||
/// This is mostly just a "sensible" cap on what is possible. We allow one day
|
||||
/// to span up to 7 civil days.
|
||||
///
|
||||
/// It must also be at least 1 second long.
|
||||
pub(crate) type ZonedDaySeconds =
|
||||
ri64<{ 1 }, { 7 * SECONDS_PER_CIVIL_DAY.bound() }>;
|
||||
|
||||
/// The number of nanoseconds permitted in a single day.
|
||||
///
|
||||
/// This is mostly just a "sensible" cap on what is possible. We allow one day
|
||||
/// to span up to 7 civil days.
|
||||
///
|
||||
/// It must also be at least 1 second long.
|
||||
pub(crate) type ZonedDayNanoseconds = ri64<
|
||||
{ ZonedDaySeconds::MIN * NANOS_PER_SECOND.bound() },
|
||||
{ ZonedDaySeconds::MAX * NANOS_PER_SECOND.bound() },
|
||||
>;
|
||||
|
||||
/// The number of days from the Unix epoch for the Gregorian calendar.
|
||||
///
|
||||
/// The range supported is based on the range of Unix timestamps that we
|
||||
/// support.
|
||||
///
|
||||
/// While I had originally used the "rate die" concept from Calendrical
|
||||
/// Calculations, I found [Howard Hinnant's formulation][date-algorithms]
|
||||
/// much more straight-forward. And while I didn't benchmark them, it also
|
||||
/// appears faster.
|
||||
///
|
||||
/// [date-algorithms]: http://howardhinnant.github.io/date_algorithms.html
|
||||
pub(crate) type UnixEpochDays = ri32<
|
||||
{
|
||||
(UnixSeconds::MIN + SpanZoneOffset::MIN)
|
||||
.div_euclid(SECONDS_PER_CIVIL_DAY.bound())
|
||||
},
|
||||
{
|
||||
(UnixSeconds::MAX + SpanZoneOffset::MAX)
|
||||
.div_euclid(SECONDS_PER_CIVIL_DAY.bound())
|
||||
},
|
||||
>;
|
||||
|
||||
/// A precise min/max of the allowed range of a duration in years.
|
||||
pub(crate) type SpanYears = ri16<{ -(Year::LEN - 1) }, { Year::LEN - 1 }>;
|
||||
|
||||
/// A precise min/max of the allowed range of a duration in months.
|
||||
pub(crate) type SpanMonths = ri32<
|
||||
{ SpanYears::MIN * MONTHS_PER_YEAR.bound() },
|
||||
{ SpanYears::MAX * MONTHS_PER_YEAR.bound() },
|
||||
>;
|
||||
|
||||
/// A range of the allowed number of weeks.
|
||||
///
|
||||
/// This is an upper bound and not actually a precise maximum. I believe a
|
||||
/// precise max could be fractional and not an integer.
|
||||
pub(crate) type SpanWeeks = ri32<{ SpanDays::MIN * 7 }, { SpanDays::MAX * 7 }>;
|
||||
|
||||
/// A range of the allowed number of days.
|
||||
pub(crate) type SpanDays =
|
||||
ri32<{ SpanHours::MIN / 24 }, { SpanHours::MAX / 24 }>;
|
||||
|
||||
/// A range of the allowed number of hours.
|
||||
///
|
||||
/// Like days, this is an upper bound because some days (because of DST) have
|
||||
/// 25 hours.
|
||||
pub(crate) type SpanHours =
|
||||
ri32<{ SpanMinutes::MIN / 60 }, { SpanMinutes::MAX / 60 }>;
|
||||
|
||||
/// A range of the allowed number of minutes.
|
||||
pub(crate) type SpanMinutes =
|
||||
ri64<{ SpanSeconds::MIN / 60 }, { SpanSeconds::MAX / 60 }>;
|
||||
|
||||
/// The maximum number of seconds that can be expressed with a span.
|
||||
///
|
||||
/// All of our span types (except for years and months, since they have
|
||||
/// variable length even in civil datetimes) are defined in terms of this
|
||||
/// constant. The way it's defined is a little odd, so let's break it down.
|
||||
///
|
||||
/// Firstly, a span of seconds should be able to represent at least
|
||||
/// the complete span supported by `Instant`. Thus, it's based off of
|
||||
/// `UnixSeconds::LEN`. That is, a span should be able to represent the value
|
||||
/// `UnixSeconds::MAX - UnixSeconds::MIN`.
|
||||
///
|
||||
/// Secondly, a span should also be able to account for any amount of possible
|
||||
/// time that a time zone offset might add or subtract to an `Instant`. This
|
||||
/// also means it can account for any difference between two `civil::DateTime`
|
||||
/// values.
|
||||
///
|
||||
/// Thirdly, the span should also be able to represent differences between
|
||||
/// times that take leap seconds into account. At present, there are 37 of them
|
||||
/// when converting between TAI and UTC. For this, we add our standard maximum
|
||||
/// allotted range of leap second offset (at time of writing, it's 1 day).
|
||||
///
|
||||
/// Fourthly, we would like our span to be divisible by
|
||||
/// `SECONDS_PER_CIVIL_DAY`. This isn't strictly required, but it makes
|
||||
/// defining boundaries a little smoother. If it weren't divisible, then the
|
||||
/// lower bounds on some types would need to be adjusted by one.
|
||||
///
|
||||
/// Note that neither the existence of this constant nor defining our spans
|
||||
/// based on it impacts the correctness of doing arithmetic on zoned instants.
|
||||
/// Artihemetic on zoned instants still uses "civil" spans, but the length
|
||||
/// of time for some units (like a day) might vary. The arithmetic for zoned
|
||||
/// instants accounts for this explicitly. But it still must obey the limits
|
||||
/// set here.
|
||||
const SPAN_CIVIL_SECONDS: i128 = next_multiple_of(
|
||||
UnixSeconds::LEN + SpanZoneOffset::MAX + LeapSecondOffset::MAX,
|
||||
SECONDS_PER_CIVIL_DAY.bound(),
|
||||
);
|
||||
|
||||
/// A range of the allowed number of seconds.
|
||||
///
|
||||
/// Note that we specifically add a ~day's worth of seconds to either end
|
||||
/// of the range to account for the fact that some time scales might exceed
|
||||
/// the range of UnixSeconds because of leap seconds. More specifically,
|
||||
/// we'd like to reuse the span logic in this module to do arithmetic on
|
||||
/// jiff::Instant values, and so want to represent the full span of possible
|
||||
/// seconds between any two points in time. If all we cared about was unix
|
||||
/// time, then `(-(UnixSeconds::LEN - 1))..=(UnixSeconds::LEN - 1)` would
|
||||
/// be sufficient.
|
||||
pub(crate) type SpanSeconds =
|
||||
ri64<{ -SPAN_CIVIL_SECONDS }, SPAN_CIVIL_SECONDS>;
|
||||
|
||||
/// A range of the allowed number of milliseconds.
|
||||
pub(crate) type SpanMilliseconds =
|
||||
ri64<{ SpanSeconds::MIN * 1_000 }, { SpanSeconds::MAX * 1_000 }>;
|
||||
|
||||
/// A range of the allowed number of microseconds.
|
||||
pub(crate) type SpanMicroseconds =
|
||||
ri64<{ SpanMilliseconds::MIN * 1_000 }, { SpanMilliseconds::MAX * 1_000 }>;
|
||||
|
||||
/// A range of the allowed number of nanoseconds.
|
||||
///
|
||||
/// For this, we cannot cover the full span of supported time instants since
|
||||
/// `UnixSeconds::MAX * NANOSECONDS_PER_SECOND` cannot fit into 64-bits. We
|
||||
/// could use a `i128`, but it doesn't seem worth it.
|
||||
///
|
||||
/// Also note that our min is equal to -max, so that the total number of values
|
||||
/// in this range is one less than the number of distinct `i64` values. We do
|
||||
/// that so that the absolute value is always defined.
|
||||
pub(crate) type SpanNanoseconds =
|
||||
ri64<{ (i64::MIN + 1) as i128 }, { i64::MAX as i128 }>;
|
||||
|
||||
/// The range of allowable fractional nanoseconds.
|
||||
///
|
||||
/// That is, this corresponds to the range of nanoseconds allowable within a
|
||||
/// single second. It can be either positive or negative.
|
||||
pub(crate) type FractionalNanosecond = ri32<
|
||||
{ -(NANOS_PER_SECOND.bound() - 1) },
|
||||
{ NANOS_PER_SECOND.bound() - 1 },
|
||||
>;
|
||||
|
||||
/// The span of seconds permitted for expressing the offset of a time zone.
|
||||
pub(crate) type SpanZoneOffset =
|
||||
ri32<{ -SPAN_ZONE_OFFSET_TOTAL_SECONDS }, SPAN_ZONE_OFFSET_TOTAL_SECONDS>;
|
||||
|
||||
/// The max number of seconds that can be expressed in a time zone offset.
|
||||
///
|
||||
/// This is computed here based on the span offset types below for convenience
|
||||
/// use in the `SpanZoneOffset` definition above.
|
||||
const SPAN_ZONE_OFFSET_TOTAL_SECONDS: i128 =
|
||||
(SpanZoneOffsetHours::MAX * 60 * 60)
|
||||
+ (SpanZoneOffsetMinutes::MAX * 60)
|
||||
+ SpanZoneOffsetSeconds::MAX;
|
||||
|
||||
/// The number of hours allowed in a time zone offset.
|
||||
///
|
||||
/// This number was somewhat arbitrarily chosen. In part because it's
|
||||
/// bigger than any current offset by a wide margin, and in part because
|
||||
/// POSIX `TZ` strings require the ability to store offsets in the range
|
||||
/// `-24:59:59..=25:59:59`. Note though that we make the range a little bigger
|
||||
/// with `-25:59:59..=25:59:59` so that negating an offset always produces a
|
||||
/// valid offset.
|
||||
///
|
||||
/// Note that RFC 8536 actually allows offsets to be much bigger, namely, in
|
||||
/// the range `(-2^31, 2^31)`, where both ends are _exclusive_ (`-2^31` is
|
||||
/// explicitly disallowed, and `2^31` overflows a signed 32-bit integer). But
|
||||
/// RFC 8536 does say that it *should* be in the range `[-89999, 93599]`, which
|
||||
/// matches POSIX. In order to keep our offset small, we stick roughly to what
|
||||
/// POSIX requires.
|
||||
pub(crate) type SpanZoneOffsetHours = ri8<-25, 25>;
|
||||
|
||||
/// The number of minutes allowed in a time zone offset.
|
||||
pub(crate) type SpanZoneOffsetMinutes = ri8<-59, 59>;
|
||||
|
||||
/// The number of seconds allowed in a time zone offset.
|
||||
pub(crate) type SpanZoneOffsetSeconds = ri8<-59, 59>;
|
||||
|
||||
/// The number of months in a year.
|
||||
pub(crate) const MONTHS_PER_YEAR: Constant = Constant(12);
|
||||
|
||||
/// The number of whole hours in one day.
|
||||
pub(crate) const HOURS_PER_CIVIL_DAY: Constant = Constant(24);
|
||||
|
||||
/// The number of minutes in a civil day.
|
||||
pub(crate) const MINUTES_PER_CIVIL_DAY: Constant =
|
||||
Constant(HOURS_PER_CIVIL_DAY.value() * MINUTES_PER_HOUR.value());
|
||||
|
||||
/// The number of minutes in an hour.
|
||||
pub(crate) const MINUTES_PER_HOUR: Constant = Constant(60);
|
||||
|
||||
/// The number of seconds in a civil day.
|
||||
///
|
||||
/// Some days will have more or less seconds because of DST transitions (or
|
||||
/// even leap seconds). But such things are ignored when dealing with civil
|
||||
/// time, and so this constant is still useful.
|
||||
pub(crate) const SECONDS_PER_CIVIL_DAY: Constant =
|
||||
Constant(HOURS_PER_CIVIL_DAY.value() * SECONDS_PER_HOUR.value());
|
||||
|
||||
/// The number of seconds in a typical week.
|
||||
///
|
||||
/// Some weeks will have more or less seconds because of DST transitions (or
|
||||
/// even leap seconds). But such things are ignored when dealing with civil
|
||||
/// time, and so this constant is still useful.
|
||||
pub(crate) const SECONDS_PER_CIVIL_WEEK: Constant =
|
||||
Constant(7 * SECONDS_PER_CIVIL_DAY.value());
|
||||
|
||||
/// The number of seconds in a single hour.
|
||||
pub(crate) const SECONDS_PER_HOUR: Constant =
|
||||
Constant(SECONDS_PER_MINUTE.value() * 60);
|
||||
|
||||
/// The number of seconds in a single minute.
|
||||
pub(crate) const SECONDS_PER_MINUTE: Constant = Constant(60);
|
||||
|
||||
/// The number of microseconds in a civil day.
|
||||
pub(crate) const MILLIS_PER_CIVIL_DAY: Constant =
|
||||
Constant(SECONDS_PER_CIVIL_DAY.value() * MILLIS_PER_SECOND.value());
|
||||
|
||||
/// The number of milliseconds in a single second.
|
||||
pub(crate) const MILLIS_PER_SECOND: Constant = Constant(1_000);
|
||||
|
||||
/// The number of microseconds in a civil day.
|
||||
pub(crate) const MICROS_PER_CIVIL_DAY: Constant =
|
||||
Constant(SECONDS_PER_CIVIL_DAY.value() * MICROS_PER_SECOND.value());
|
||||
|
||||
/// The number of microseconds in a single second.
|
||||
pub(crate) const MICROS_PER_SECOND: Constant = Constant(1_000_000);
|
||||
|
||||
/// The number of microseconds in a single millisecond.
|
||||
pub(crate) const MICROS_PER_MILLI: Constant = Constant(1_000);
|
||||
|
||||
/// The number of nanoseconds in a civil day.
|
||||
///
|
||||
/// Some days will have more or less seconds because of DST transitions (or
|
||||
/// even leap seconds). But such things are ignored when dealing with civil
|
||||
/// time, and so this constant is still useful.
|
||||
pub(crate) const NANOS_PER_CIVIL_DAY: Constant =
|
||||
Constant(SECONDS_PER_CIVIL_DAY.value() * NANOS_PER_SECOND.value());
|
||||
|
||||
/// The number of nanoseconds in a single hour.
|
||||
pub(crate) const NANOS_PER_HOUR: Constant =
|
||||
Constant(SECONDS_PER_HOUR.value() * NANOS_PER_SECOND.value());
|
||||
|
||||
/// The number of nanoseconds in a single minute.
|
||||
pub(crate) const NANOS_PER_MINUTE: Constant =
|
||||
Constant(SECONDS_PER_MINUTE.value() * NANOS_PER_SECOND.value());
|
||||
|
||||
/// The number of nanoseconds in a single second.
|
||||
pub(crate) const NANOS_PER_SECOND: Constant = Constant(1_000_000_000);
|
||||
|
||||
/// The number of nanoseconds in a single millisecond.
|
||||
pub(crate) const NANOS_PER_MILLI: Constant = Constant(1_000_000);
|
||||
|
||||
/// The number of nanoseconds in a single microsecond.
|
||||
pub(crate) const NANOS_PER_MICRO: Constant = Constant(1_000);
|
||||
|
||||
pub(crate) fn sign<T: Ord>(t1: T, t2: T) -> Sign {
|
||||
use core::cmp::Ordering::*;
|
||||
match t1.cmp(&t2) {
|
||||
Less => Sign::N::<-1>(),
|
||||
Equal => Sign::N::<0>(),
|
||||
Greater => Sign::N::<1>(),
|
||||
}
|
||||
}
|
||||
|
||||
/// A constant value for use in arithmetic in this crate.
|
||||
///
|
||||
/// This type is basically a bunch of shenanigans to make constants work in
|
||||
/// a sensible way with our range integers. Essentially, we really want
|
||||
/// constants to satisfy the following criteria:
|
||||
///
|
||||
/// 1. Defined in one place.
|
||||
/// 2. Composable in that we can define constants in terms of other constants.
|
||||
/// 3. Easy to use with any kind of range integer type.
|
||||
/// 4. Specially constructed when used with ranged integers. That is, a ranged
|
||||
/// integer value build from a constant should have computed min/max bounds
|
||||
/// equivalent to the constant itself. (Normally, a `rN::new` will set the
|
||||
/// computed min/max bounds to the MIN/MAX bounds overall, since it is assumed
|
||||
/// that `rN::new` accepts a value that can vary to any legal value in the
|
||||
/// range. But a constant needs tight bounds because, well, it can literally
|
||||
/// never vary.)
|
||||
///
|
||||
/// # Trait implementations
|
||||
///
|
||||
/// It'd be nice to impl `Add/Sub/Mul/Div` for `Constant` itself, but they
|
||||
/// can't be used in a const context... which is where it would be most useful.
|
||||
/// Otherwise, we just define `Add/Sub/Mul/Div` impls for all of the ranged
|
||||
/// integer types so that constants can be used on the left-hand side of
|
||||
/// arithmetic expressions. (The ranged integer types have impls that are
|
||||
/// generic enough to support arithmetic with constants on the right hand
|
||||
/// side.)
|
||||
///
|
||||
/// We do a similar thing for the `Partial{Eq,Ord}` traits. The ranged integers
|
||||
/// already have impls for `Constant` on the right-hand side. Below are the
|
||||
/// impls for `Constant` on the left-hand side.
|
||||
///
|
||||
/// All of the trait impls that deal with constants and ranged integers are
|
||||
/// implemented with the ranged integer types.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub(crate) struct Constant(pub(crate) i64);
|
||||
|
||||
/// A short-hand creating a generic `Constant` value as a ranged integer.
|
||||
///
|
||||
/// Callers do need to ensure that the `MIN` and `MAX` bounds are specified (or
|
||||
/// more likely inferred), but otherwise, the `ri64` returned will be usable
|
||||
/// in most contexts even with other ranged integers (like `ri8`).
|
||||
#[allow(non_snake_case)]
|
||||
pub(crate) fn C(
|
||||
constant: i64,
|
||||
) -> ri64<{ i64::MIN as i128 }, { i64::MAX as i128 }> {
|
||||
Constant(constant).rinto()
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub(crate) fn C128(constant: i64) -> ri128<{ i128::MIN }, { i128::MAX }> {
|
||||
Constant(constant).rinto()
|
||||
}
|
||||
|
||||
impl Constant {
|
||||
/// Return the primitive value of this constant.
|
||||
pub(crate) const fn value(self) -> i64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Return this constant as a bound intended to be used in const generics.
|
||||
pub(crate) const fn bound(self) -> i128 {
|
||||
self.value() as i128
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Neg for Constant {
|
||||
type Output = Constant;
|
||||
|
||||
fn neg(self) -> Constant {
|
||||
Constant(-self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Constant> for i8 {
|
||||
fn from(c: Constant) -> i8 {
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
c.value() as i8
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
i8::try_from(c.value()).unwrap_or_else(|_| {
|
||||
panic!("{c:?} is out of range {:?}..={:?}", i8::MIN, i8::MAX);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Constant> for i16 {
|
||||
fn from(c: Constant) -> i16 {
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
c.value() as i16
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
i16::try_from(c.value()).unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"{c:?} is out of range {:?}..={:?}",
|
||||
i16::MIN,
|
||||
i16::MAX
|
||||
);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Constant> for i32 {
|
||||
fn from(c: Constant) -> i32 {
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
c.value() as i32
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
i32::try_from(c.value()).unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"{c:?} is out of range {:?}..={:?}",
|
||||
i32::MIN,
|
||||
i32::MAX
|
||||
);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Constant> for i64 {
|
||||
fn from(c: Constant) -> i64 {
|
||||
c.value()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Constant> for i128 {
|
||||
fn from(c: Constant) -> i128 {
|
||||
i128::from(c.value())
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the next multiple of `rhs` that is greater than or equal to `lhs`.
|
||||
///
|
||||
/// Taken from:
|
||||
/// https://github.com/rust-lang/rust/blob/eff958c59e8c07ba0515e164b825c9001b242294/library/core/src/num/int_macros.rs
|
||||
const fn next_multiple_of(lhs: i128, rhs: i128) -> i128 {
|
||||
// This would otherwise fail when calculating `r` when self == T::MIN.
|
||||
if rhs == -1 {
|
||||
return lhs;
|
||||
}
|
||||
|
||||
let r = lhs % rhs;
|
||||
let m = if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) { r + rhs } else { r };
|
||||
if m == 0 {
|
||||
lhs
|
||||
} else {
|
||||
lhs + (rhs - m)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn divisible() {
|
||||
// We requires that our span of seconds is divisible by an even number
|
||||
// of days. When it's not divisible, some of the boundary conditions
|
||||
// get a little trickier, but I do not believe it's necessary for
|
||||
// correctness. Without this assertion, some of the minimum values for
|
||||
// our range types above need to be one less. (I believe.)
|
||||
assert_eq!(0, SpanSeconds::MAX_REPR % 86_400);
|
||||
}
|
||||
}
|
||||
574
src/zoned.rs
Normal file
574
src/zoned.rs
Normal file
|
|
@ -0,0 +1,574 @@
|
|||
use crate::{
|
||||
civil::{DateTime, Time},
|
||||
error::{err, Error, ErrorContext},
|
||||
instant::{Instant, TimeScale, Unix},
|
||||
round::{Round, Unit},
|
||||
span::Span,
|
||||
tz::{Offset, TimeZone},
|
||||
util::{
|
||||
rangeint::{RFrom, RInto, TryRFrom},
|
||||
t::{self, NoUnits, NoUnits128, ZonedDayNanoseconds, C},
|
||||
},
|
||||
};
|
||||
|
||||
// BREADCRUMBS: Filling out the rest of the methods on Zoned doesn't look like
|
||||
// it's too tricky. The only interesting one beyond what we've already built
|
||||
// is `Zoned::round`. And in particular, we need `Instant::round` too. I wonder
|
||||
// if that's just going to be the same as `DateTime::round`?
|
||||
//
|
||||
// The real trickiness comes with rounding `Span` values relative to a `Zoned`
|
||||
// instant.
|
||||
//
|
||||
// Do Instant::round next.
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Zoned<S: TimeScale = Unix> {
|
||||
instant: Instant<S>,
|
||||
tz: TimeZone,
|
||||
}
|
||||
|
||||
impl Zoned {
|
||||
pub const UNIX_EPOCH: Zoned =
|
||||
Zoned::new(Instant::UNIX_EPOCH, TimeZone::UTC);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[inline]
|
||||
pub fn now() -> Zoned {
|
||||
Zoned::now_with_scale().expect("system time reports valid value")
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: TimeScale> Zoned<S> {
|
||||
#[inline]
|
||||
pub const fn new(instant: Instant<S>, tz: TimeZone) -> Zoned<S> {
|
||||
Zoned { instant, tz }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn time_zone(&self) -> &TimeZone {
|
||||
&self.tz
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_instant(&self) -> Instant<S> {
|
||||
self.instant
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_datetime(&self) -> DateTime {
|
||||
self.time_zone().to_datetime(self.to_instant())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_instant(&self, instant: Instant<S>) -> Zoned<S> {
|
||||
Zoned::new(instant, self.time_zone().clone())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_time_zone(&self, time_zone: TimeZone) -> Zoned<S> {
|
||||
Zoned::new(self.to_instant(), time_zone)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn since(&self, other: &Zoned<S>) -> Span {
|
||||
self.until(other).negate()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn since_with_largest_unit(
|
||||
&self,
|
||||
largest: Unit,
|
||||
mut other: &Zoned<S>,
|
||||
) -> Result<Span, Error> {
|
||||
Ok(-self.until_with_largest_unit(largest, other)?)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn until(&self, other: &Zoned<S>) -> Span {
|
||||
self.until_with_largest_unit(Unit::Hour, other).expect("always okay")
|
||||
// self.to_instant().until(other.to_instant())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn until_with_largest_unit(
|
||||
&self,
|
||||
largest: Unit,
|
||||
mut other: &Zoned<S>,
|
||||
) -> Result<Span, Error> {
|
||||
use crate::instant::private::Nanoseconds;
|
||||
|
||||
let (zdt1, zdt2) = (self, other);
|
||||
|
||||
// FIXME: Turn this into an error. And iron out time zone equality
|
||||
// story.
|
||||
assert_eq!(zdt1.time_zone(), zdt2.time_zone());
|
||||
|
||||
let sign = t::sign(zdt2, zdt1);
|
||||
if sign == 0 {
|
||||
return Ok(Span::new());
|
||||
}
|
||||
if largest < Unit::Day {
|
||||
return zdt1
|
||||
.to_instant()
|
||||
.until_with_largest_unit(largest, zdt2.to_instant());
|
||||
}
|
||||
|
||||
let (dt1, mut dt2) = (zdt1.to_datetime(), zdt2.to_datetime());
|
||||
|
||||
let mut day_correct: t::SpanDays = C(0).rinto();
|
||||
if -sign == dt1.time().until_nanoseconds(dt2.time()).signum() {
|
||||
day_correct += C(1);
|
||||
}
|
||||
|
||||
let mut mid = dt2
|
||||
.date()
|
||||
.checked_add(Span::new().days_ranged(day_correct * -sign))
|
||||
.with_context(|| {
|
||||
err!(
|
||||
"failed to add {days} days to date in {dt2}",
|
||||
days = day_correct * -sign,
|
||||
)
|
||||
})?
|
||||
.to_datetime(dt1.time());
|
||||
let mut zmid: Zoned<S> = mid
|
||||
.to_zoned_with(self.time_zone().clone())
|
||||
.with_context(|| {
|
||||
err!(
|
||||
"failed to convert intermediate datetime {mid} \
|
||||
to zoned instant in time zone {tz}",
|
||||
tz = self.time_zone().name(),
|
||||
)
|
||||
})?;
|
||||
if t::sign(zdt2, &zmid) == -sign {
|
||||
if sign == -1 {
|
||||
panic!("this should be an error");
|
||||
}
|
||||
day_correct += C(1);
|
||||
mid = dt2
|
||||
.date()
|
||||
.checked_add(Span::new().days_ranged(day_correct * -sign))
|
||||
.with_context(|| {
|
||||
err!(
|
||||
"failed to add {days} days to date in {dt2}",
|
||||
days = day_correct * -sign,
|
||||
)
|
||||
})?
|
||||
.to_datetime(dt1.time());
|
||||
zmid = mid.to_zoned_with(self.time_zone().clone()).with_context(
|
||||
|| {
|
||||
err!(
|
||||
"failed to convert intermediate datetime {mid} \
|
||||
to zoned instant in time zone {tz}",
|
||||
tz = self.time_zone().name(),
|
||||
)
|
||||
},
|
||||
)?;
|
||||
if t::sign(zdt2, &zmid) == -sign {
|
||||
panic!("this should be an error too");
|
||||
}
|
||||
}
|
||||
let remainder_nano =
|
||||
zdt2.to_instant().as_nanosecond_ranged().to_no_units()
|
||||
- zmid.to_instant().as_nanosecond_ranged().to_no_units();
|
||||
dt2 = mid;
|
||||
|
||||
let date_span =
|
||||
dt1.date().until_with_largest_unit(largest, dt2.date());
|
||||
Ok(Span::from_invariant_nanoseconds(Unit::Hour, remainder_nano)
|
||||
.expect("difference between time always fits in span")
|
||||
.years_ranged(date_span.get_years_ranged())
|
||||
.months_ranged(date_span.get_months_ranged())
|
||||
.weeks_ranged(date_span.get_weeks_ranged())
|
||||
.days_ranged(date_span.get_days_ranged()))
|
||||
}
|
||||
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{civil::DateTime, ToSpan, Zoned};
|
||||
///
|
||||
/// let dt = DateTime::constant(2024, 3, 10, 0, 0, 0, 0);
|
||||
/// let inst: Zoned = dt.to_zoned("America/New_York")?;
|
||||
///
|
||||
/// let later_day = inst.checked_add(1.day())?;
|
||||
/// assert_eq!(
|
||||
/// later_day.to_datetime(),
|
||||
/// DateTime::constant(2024, 3, 11, 0, 0, 0, 0),
|
||||
/// );
|
||||
///
|
||||
/// let later_hours = inst.checked_add(24.hours())?;
|
||||
/// assert_eq!(
|
||||
/// later_hours.to_datetime(),
|
||||
/// DateTime::constant(2024, 3, 11, 1, 0, 0, 0),
|
||||
/// );
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn checked_add(&self, span: Span) -> Result<Zoned<S>, Error> {
|
||||
let span_calendar = span.without_lower(Unit::Day);
|
||||
// If our duration only consists of "time" (hours, minutes, etc), then
|
||||
// we can short-circuit and do timestamp math. This also avoids dealing
|
||||
// with ambiguity and time zone bullshit.
|
||||
if span_calendar.is_zero() {
|
||||
return Ok(self.with_instant(
|
||||
self.to_instant().checked_add(span).with_context(|| {
|
||||
err!(
|
||||
"failed to add span {span} to instant {instant} \
|
||||
from zoned instant {zoned}",
|
||||
instant = self.to_instant(),
|
||||
zoned = self,
|
||||
)
|
||||
})?,
|
||||
));
|
||||
}
|
||||
let span_time = span.only_lower(Unit::Day);
|
||||
let dt = self.to_datetime().checked_add(span_calendar).with_context(
|
||||
|| {
|
||||
err!(
|
||||
"failed to add span {span_calendar} to datetime {dt} \
|
||||
from zoned instant {zoned}",
|
||||
dt = self.to_datetime(),
|
||||
zoned = self,
|
||||
)
|
||||
},
|
||||
)?;
|
||||
let instant =
|
||||
self.time_zone().to_instant_with_scale(dt).with_context(|| {
|
||||
err!(
|
||||
"failed to convert civil datetime {dt} to instant \
|
||||
with time zone {tz}",
|
||||
tz = self.time_zone().name(),
|
||||
)
|
||||
})?;
|
||||
let instant = instant.checked_add(span_time).with_context(|| {
|
||||
err!("failed to add span {span_time} to instant {instant}")
|
||||
})?;
|
||||
Ok(self.with_instant(instant))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn checked_sub(&self, span: Span) -> Result<Zoned<S>, Error> {
|
||||
self.checked_add(span.negate())
|
||||
}
|
||||
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{civil::DateTime, Zoned};
|
||||
///
|
||||
/// let dt = DateTime::constant(2015, 10, 18, 12, 0, 0, 0);
|
||||
/// let inst: Zoned = dt.to_zoned("America/Sao_Paulo")?;
|
||||
/// assert_eq!(
|
||||
/// inst.start_of_day()?.to_datetime(),
|
||||
/// DateTime::constant(2015, 10, 18, 1, 0, 0, 0),
|
||||
/// );
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{civil::DateTime, tz::{TimeZone, Offset}, Zoned};
|
||||
///
|
||||
/// // While -9999-01-03T04:00:00+25:59:59 is representable as a Zoned
|
||||
/// // value, the start of the corresponding day is not!
|
||||
/// let dt = DateTime::constant(-9999, 1, 3, 4, 0, 0, 0);
|
||||
/// let inst: Zoned = dt.to_zoned_with(TimeZone::fixed(Offset::MAX))?;
|
||||
/// assert!(inst.start_of_day().is_err());
|
||||
/// // The next day works fine since -9999-01-04T00:00:00+25:59:59 is
|
||||
/// // representable.
|
||||
/// let dt = DateTime::constant(-9999, 1, 4, 15, 0, 0, 0);
|
||||
/// let inst: Zoned = dt.to_zoned_with(TimeZone::fixed(Offset::MAX))?;
|
||||
/// assert_eq!(
|
||||
/// inst.start_of_day()?.to_datetime(),
|
||||
/// DateTime::constant(-9999, 1, 4, 0, 0, 0, 0),
|
||||
/// );
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn start_of_day(&self) -> Result<Zoned<S>, Error> {
|
||||
let civil_start = self.to_datetime().map_time(|_| Time::midnight());
|
||||
let instant = self.time_zone().to_instant_with_scale(civil_start)?;
|
||||
Ok(self.with_instant(instant))
|
||||
}
|
||||
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use jiff::{civil::DateTime, round::{RoundMode, Unit}, Zoned};
|
||||
///
|
||||
/// let dt = DateTime::constant(1995, 12, 7, 3, 24, 30, 3500);
|
||||
/// let inst: Zoned = dt.to_zoned("America/Los_Angeles")?;
|
||||
///
|
||||
/// let rounded = inst.round(Unit::Hour);
|
||||
/// assert_eq!(
|
||||
/// rounded.to_datetime(),
|
||||
/// DateTime::constant(1995, 12, 7, 3, 0, 0, 0),
|
||||
/// );
|
||||
///
|
||||
/// let rounded = inst.round(Unit::Minute.increment(30));
|
||||
/// assert_eq!(
|
||||
/// rounded.to_datetime(),
|
||||
/// DateTime::constant(1995, 12, 7, 3, 30, 0, 0),
|
||||
/// );
|
||||
///
|
||||
/// let rounded = inst.round(
|
||||
/// Unit::Minute.increment(30).mode(RoundMode::Floor),
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// rounded.to_datetime(),
|
||||
/// DateTime::constant(1995, 12, 7, 3, 0, 0, 0),
|
||||
/// );
|
||||
///
|
||||
/// # Ok::<(), Box<dyn std::error::Error>>(())
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn round(&self, options: impl Into<Round>) -> Zoned<S> {
|
||||
self.try_round(options).expect("invalid round options")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_round(
|
||||
&self,
|
||||
options: impl Into<Round>,
|
||||
) -> Result<Zoned<S>, Error> {
|
||||
let options = options.into();
|
||||
let day_length = self.day_length_ranged()?;
|
||||
let start = self.to_datetime();
|
||||
let end = options.round_datetime(Some(day_length), start)?;
|
||||
end.to_zoned_with(self.time_zone().clone())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn day_length_ranged(
|
||||
&self,
|
||||
) -> Result<ZonedDayNanoseconds, Error> {
|
||||
let start = self.start_of_day()?;
|
||||
let end = start.checked_add(Span::new().days_ranged(C(1)))?;
|
||||
let len = start.to_instant().until(end.to_instant());
|
||||
let seconds = t::ZonedDaySeconds::try_rfrom(
|
||||
"seconds-per-zoned-day",
|
||||
len.get_seconds_ranged(),
|
||||
)
|
||||
.with_context(|| {
|
||||
err!(
|
||||
"failed to convert span between {start} until {end} \
|
||||
to seconds",
|
||||
)
|
||||
})?;
|
||||
let nanos = seconds * t::NANOS_PER_SECOND;
|
||||
ZonedDayNanoseconds::try_rfrom("nanoseconds-per-zoned-day", nanos)
|
||||
.with_context(|| {
|
||||
err!(
|
||||
"failed to convert span between {start} until {end} \
|
||||
to nanoseconds",
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_unix_scale(&self) -> Zoned {
|
||||
let instant = self.to_instant().to_unix_scale();
|
||||
Zoned::new(instant, self.time_zone().clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: TimeScale> Zoned<S> {
|
||||
#[cfg(feature = "std")]
|
||||
#[inline]
|
||||
pub fn now_with_scale() -> Result<Zoned<S>, Error> {
|
||||
// TODO: We should use the local time zone.
|
||||
Ok(Zoned::new(Instant::now_with_scale()?, TimeZone::UTC))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from_offset_timezone(
|
||||
dt: DateTime,
|
||||
offset: Option<Offset>,
|
||||
time_zone: Option<TimeZone>,
|
||||
) -> Result<Zoned<S>, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: TimeScale> Default for Zoned<S> {
|
||||
#[inline]
|
||||
fn default() -> Zoned<S> {
|
||||
Zoned::new(Instant::default(), TimeZone::UTC)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> core::fmt::Debug for Zoned<S>
|
||||
where
|
||||
S: TimeScale + core::fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
f.debug_struct("Zoned")
|
||||
.field("instant", &self.to_instant())
|
||||
.field("time_zone", &self.time_zone().name())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: TimeScale> core::fmt::Display for Zoned<S> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
use crate::format::{temporal::DateTimePrinter, FmtWrite};
|
||||
|
||||
static P: DateTimePrinter = DateTimePrinter::new();
|
||||
// Printing to `f` should never fail.
|
||||
Ok(P.print_zoned(self, FmtWrite(f)).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: TimeScale> Eq for Zoned<S> {}
|
||||
|
||||
impl<S: TimeScale> PartialEq for Zoned<S> {
|
||||
#[inline]
|
||||
fn eq(&self, rhs: &Zoned<S>) -> bool {
|
||||
self.to_instant().eq(&rhs.to_instant())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: TimeScale> Ord for Zoned<S> {
|
||||
#[inline]
|
||||
fn cmp(&self, rhs: &Zoned<S>) -> core::cmp::Ordering {
|
||||
self.to_instant().cmp(&rhs.to_instant())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: TimeScale> PartialOrd for Zoned<S> {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, rhs: &Zoned<S>) -> Option<core::cmp::Ordering> {
|
||||
Some(self.cmp(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<S: TimeScale> TryFrom<std::time::SystemTime> for Zoned<S> {
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn try_from(
|
||||
system_time: std::time::SystemTime,
|
||||
) -> Result<Zoned<S>, Error> {
|
||||
let instant = Instant::try_from(system_time)?;
|
||||
Ok(Zoned::new(instant, TimeZone::UTC))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<S: TimeScale> From<Zoned<S>> for std::time::SystemTime {
|
||||
#[inline]
|
||||
fn from(time: Zoned<S>) -> std::time::SystemTime {
|
||||
time.to_instant().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<S: TimeScale + 'static> quickcheck::Arbitrary for Zoned<S> {
|
||||
fn arbitrary(g: &mut quickcheck::Gen) -> Zoned<S> {
|
||||
use quickcheck::Arbitrary;
|
||||
|
||||
let instant = Instant::arbitrary(g);
|
||||
let tz = TimeZone::UTC; // TODO: do something better here?
|
||||
Zoned::new(instant, tz)
|
||||
}
|
||||
|
||||
fn shrink(&self) -> alloc::boxed::Box<dyn Iterator<Item = Self>> {
|
||||
let instant = self.to_instant();
|
||||
alloc::boxed::Box::new(
|
||||
instant.shrink().map(|instant| Zoned::new(instant, TimeZone::UTC)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::ToSpan;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn until_with_largest_unit() {
|
||||
let zdt1: Zoned = DateTime::constant(1995, 12, 7, 3, 24, 30, 3500)
|
||||
.to_zoned("Asia/Kolkata")
|
||||
.unwrap();
|
||||
let zdt2: Zoned = DateTime::constant(2019, 1, 31, 15, 30, 0, 0)
|
||||
.to_zoned("Asia/Kolkata")
|
||||
.unwrap();
|
||||
let span = zdt1.until(&zdt2);
|
||||
assert_eq!(
|
||||
span,
|
||||
202956
|
||||
.hours()
|
||||
.minutes(5)
|
||||
.seconds(29)
|
||||
.milliseconds(999)
|
||||
.microseconds(996)
|
||||
.nanoseconds(500)
|
||||
);
|
||||
let span = zdt1.until_with_largest_unit(Unit::Year, &zdt2).unwrap();
|
||||
assert_eq!(
|
||||
span,
|
||||
23.years()
|
||||
.months(1)
|
||||
.days(24)
|
||||
.hours(12)
|
||||
.minutes(5)
|
||||
.seconds(29)
|
||||
.milliseconds(999)
|
||||
.microseconds(996)
|
||||
.nanoseconds(500)
|
||||
);
|
||||
|
||||
let span = zdt2.until_with_largest_unit(Unit::Year, &zdt1).unwrap();
|
||||
assert_eq!(
|
||||
span,
|
||||
-23.years()
|
||||
.months(1)
|
||||
.days(24)
|
||||
.hours(12)
|
||||
.minutes(5)
|
||||
.seconds(29)
|
||||
.milliseconds(999)
|
||||
.microseconds(996)
|
||||
.nanoseconds(500)
|
||||
);
|
||||
let span =
|
||||
zdt1.until_with_largest_unit(Unit::Nanosecond, &zdt2).unwrap();
|
||||
assert_eq!(span, 730641929999996500i64.nanoseconds(),);
|
||||
|
||||
let zdt1: Zoned = DateTime::constant(2020, 1, 1, 0, 0, 0, 0)
|
||||
.to_zoned("America/New_York")
|
||||
.unwrap();
|
||||
let zdt2: Zoned = DateTime::constant(2020, 4, 24, 21, 0, 0, 0)
|
||||
.to_zoned("America/New_York")
|
||||
.unwrap();
|
||||
let span = zdt1.until(&zdt2);
|
||||
assert_eq!(span, 2756.hours());
|
||||
let span = zdt1.until_with_largest_unit(Unit::Year, &zdt2).unwrap();
|
||||
assert_eq!(span, 3.months().days(23).hours(21));
|
||||
|
||||
let zdt1: Zoned = DateTime::constant(2000, 10, 29, 0, 0, 0, 0)
|
||||
.to_zoned("America/Vancouver")
|
||||
.unwrap();
|
||||
let zdt2: Zoned = DateTime::constant(2000, 10, 29, 23, 0, 0, 5)
|
||||
.to_zoned("America/Vancouver")
|
||||
.unwrap();
|
||||
let span = zdt1.until_with_largest_unit(Unit::Day, &zdt2).unwrap();
|
||||
assert_eq!(span, 24.hours().nanoseconds(5));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zoned_size() {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
assert_eq!(48, core::mem::size_of::<Zoned>());
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
assert_eq!(24, core::mem::size_of::<Zoned>());
|
||||
}
|
||||
}
|
||||
}
|
||||
38
tests/lib.rs
Normal file
38
tests/lib.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#![allow(warnings)]
|
||||
|
||||
use jiff::{
|
||||
civil::{Date, DateTime, Time as CivilTime},
|
||||
Instant, Span,
|
||||
};
|
||||
|
||||
mod tc39_262;
|
||||
|
||||
#[test]
|
||||
fn scratch() {
|
||||
// let t = Time::now();
|
||||
// dbg!(t);
|
||||
// let dt = t.to_datetime();
|
||||
// dbg!(dt);
|
||||
//
|
||||
// let t = Time::from_unix(-1, 0).unwrap();
|
||||
// let dt = t.to_datetime();
|
||||
// dbg!(dt);
|
||||
//
|
||||
// let t = Time::from_unix(0, -1).unwrap();
|
||||
// let dt = t.to_datetime();
|
||||
// dbg!(dt);
|
||||
|
||||
// let t = Instant::from_unix(-377705116799, -999_999_999).unwrap();
|
||||
// let dt = t.to_datetime();
|
||||
// dbg!(dt);
|
||||
|
||||
// let start = Date::new(2024, 2, 28).unwrap();
|
||||
// let span = Span::new().years(1).months(1);
|
||||
// let span = Span::new()
|
||||
// .hours(23)
|
||||
// .minutes(59)
|
||||
// .seconds(59)
|
||||
// .nanoseconds(1_000_000_000);
|
||||
// let end = start.add(span);
|
||||
// eprintln!("{end:?}");
|
||||
}
|
||||
20
tests/tc39_262/README.md
Normal file
20
tests/tc39_262/README.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
These tests come from [TC39's Test262] for the [Temporal proposal]. The tests
|
||||
here try to mimic what's in Test262 as much as possible, but there are many
|
||||
tests that are omitted because they are caught by Rust's type system. On
|
||||
occasion, we diverge in behavior from Temporal. These differences are, to the
|
||||
best of my ability, marked with `DIFFERENCE`.
|
||||
|
||||
These tests were ported by hand. There is, at time of writing, no mechanism for
|
||||
ensuring they remain in sync with Test262.
|
||||
|
||||
[TC39's Test262]: https://github.com/tc39/test262/tree/9e03c403e73341658d8d485a673798ae61f6f94a/test/built-ins/Temporal
|
||||
[Temporal proposal]: https://github.com/tc39/proposal-temporal
|
||||
|
||||
# TODO
|
||||
|
||||
These are some test files that I came across while porting things that I
|
||||
couldn't quite write yet. For example, tests that require parsing ISO 8601
|
||||
duration strings, since the parsing code doesn't exist yet (at time of writing,
|
||||
2024-03-06).
|
||||
|
||||
I tried to list what I could as `TODO` comments in the test files.
|
||||
2
tests/tc39_262/civil/datetime/mod.rs
Normal file
2
tests/tc39_262/civil/datetime/mod.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
mod round;
|
||||
mod since;
|
||||
43
tests/tc39_262/civil/datetime/round.rs
Normal file
43
tests/tc39_262/civil/datetime/round.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
use jiff::{
|
||||
civil::DateTime,
|
||||
round::{RoundMode, Unit},
|
||||
};
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainDateTime/prototype/round/balance.js
|
||||
#[test]
|
||||
fn balance() {
|
||||
let dt = DateTime::constant(1976, 11, 18, 23, 59, 59, 999_999_999);
|
||||
let expected = DateTime::constant(1976, 11, 19, 0, 0, 0, 0);
|
||||
|
||||
assert_eq!(dt.round(Unit::Day), expected);
|
||||
assert_eq!(dt.round(Unit::Hour), expected);
|
||||
assert_eq!(dt.round(Unit::Minute), expected);
|
||||
assert_eq!(dt.round(Unit::Second), expected);
|
||||
assert_eq!(dt.round(Unit::Millisecond), expected);
|
||||
assert_eq!(dt.round(Unit::Microsecond), expected);
|
||||
assert_eq!(dt.round(Unit::Nanosecond), dt);
|
||||
}
|
||||
|
||||
/// DIFFERENCE: Temporal and Jiff have different maximums, so we use our own
|
||||
/// values here.
|
||||
///
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainDateTime/prototype/round/limits.js
|
||||
#[test]
|
||||
fn limits() {
|
||||
let dt = DateTime::constant(9999, 12, 31, 23, 59, 59, 999_999_999);
|
||||
assert!(dt.try_round(Unit::Day).is_err());
|
||||
assert!(dt.try_round(Unit::Microsecond).is_err());
|
||||
|
||||
let dt = DateTime::constant(9999, 12, 31, 23, 59, 59, 999_999_499);
|
||||
assert!(dt.try_round(Unit::Day).is_err());
|
||||
assert_eq!(
|
||||
dt.round(Unit::Microsecond),
|
||||
DateTime::constant(9999, 12, 31, 23, 59, 59, 999_999_000)
|
||||
);
|
||||
|
||||
let dt = DateTime::constant(-9999, 1, 1, 0, 0, 0, 000_000_001);
|
||||
assert_eq!(
|
||||
dt.round(Unit::Microsecond.mode(RoundMode::Floor)),
|
||||
DateTime::constant(-9999, 1, 1, 0, 0, 0, 0)
|
||||
);
|
||||
}
|
||||
1
tests/tc39_262/civil/datetime/since/mod.rs
Normal file
1
tests/tc39_262/civil/datetime/since/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
mod wrapping_at_end_of_month;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
use jiff::{civil::DateTime, round::Unit, ToSpan};
|
||||
|
||||
/// Test that 1-day backoff to maintain date/time sign compatibility backs-off
|
||||
/// from correct end while moving *forwards* in time and does not interfere
|
||||
/// with month boundaries.
|
||||
///
|
||||
/// Ref: https://github.com/tc39/proposal-temporal/issues/2820
|
||||
#[test]
|
||||
fn one_day_backoff1() {
|
||||
let dt1 = DateTime::constant(2023, 2, 28, 3, 0, 0, 0);
|
||||
let dt2 = DateTime::constant(2023, 4, 1, 2, 0, 0, 0);
|
||||
let span = dt1.since_with_largest_unit(Unit::Year, dt2).unwrap();
|
||||
assert_eq!(span, -1.month().days(3).hours(23));
|
||||
}
|
||||
|
||||
/// Test that 1-day backoff to maintain date/time sign compatibility backs-off
|
||||
/// from correct end while moving *forwards* in time and does not interfere
|
||||
/// with month boundaries.
|
||||
///
|
||||
/// Ref: https://github.com/tc39/proposal-temporal/issues/2820
|
||||
#[test]
|
||||
fn one_day_backoff2() {
|
||||
let dt1 = DateTime::constant(2023, 3, 1, 2, 0, 0, 0);
|
||||
let dt2 = DateTime::constant(2023, 1, 1, 3, 0, 0, 0);
|
||||
let span = dt1.since_with_largest_unit(Unit::Year, dt2).unwrap();
|
||||
assert_eq!(span, 1.month().days(30).hours(23));
|
||||
}
|
||||
2
tests/tc39_262/civil/mod.rs
Normal file
2
tests/tc39_262/civil/mod.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
mod datetime;
|
||||
mod time;
|
||||
327
tests/tc39_262/civil/time/add.rs
Normal file
327
tests/tc39_262/civil/time/add.rs
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
use jiff::{civil::Time, span::Span};
|
||||
|
||||
/// TODO
|
||||
///
|
||||
/// All of these require parsing of some kind. Durations I believe.
|
||||
///
|
||||
/// * https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/add/argument-duration-out-of-range.js
|
||||
/// * https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/add/argument-string-fractional-units-rounding-mode.js
|
||||
/// * https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/add/argument-string-negative-fractional-units.js
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/add/argument-duration.js
|
||||
#[test]
|
||||
fn argument_duration() {
|
||||
let t1 = Time::constant(15, 23, 30, 123_456_789);
|
||||
let span = Span::new().hours(16);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, Time::constant(7, 23, 30, 123_456_789));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/add/argument-duration-max.js
|
||||
#[test]
|
||||
fn argument_duration_max() {
|
||||
let t1 = Time::constant(0, 0, 0, 0);
|
||||
let expected = Time::constant(7, 36, 31, 999_999_999);
|
||||
|
||||
let span = Span::new()
|
||||
.years(19_998)
|
||||
.days(7_304_482)
|
||||
.nanoseconds(27391999999999i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new()
|
||||
.months(239_976)
|
||||
.days(7_304_482)
|
||||
.nanoseconds(27391999999999i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new()
|
||||
.weeks(51_131_374)
|
||||
.days(7_304_482)
|
||||
.nanoseconds(27391999999999i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new().days(7_304_482).nanoseconds(27391999999999i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new().hours(175_307_591).nanoseconds(65498124754943i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span =
|
||||
Span::new().minutes(10_518_455_460i64).nanoseconds(65498124754943i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span =
|
||||
Span::new().seconds(631_107_327_600i64).nanoseconds(65498124754943i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/add/argument-duration-max.js
|
||||
#[test]
|
||||
fn argument_duration_min() {
|
||||
let t1 = Time::constant(0, 0, 0, 0);
|
||||
let expected = Time::constant(16, 23, 28, 000_000_001);
|
||||
|
||||
let span = Span::new()
|
||||
.years(-19_998)
|
||||
.days(-7_304_482)
|
||||
.nanoseconds(-27391999999999i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new()
|
||||
.months(-239_976)
|
||||
.days(-7_304_482)
|
||||
.nanoseconds(-27391999999999i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new()
|
||||
.weeks(-51_131_374)
|
||||
.days(-7_304_482)
|
||||
.nanoseconds(-27391999999999i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new().days(-7_304_482).nanoseconds(-27391999999999i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new().hours(-175_307_591).nanoseconds(-65498124754943i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new()
|
||||
.minutes(-10_518_455_460i64)
|
||||
.nanoseconds(-65498124754943i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new()
|
||||
.seconds(-631_107_327_600i64)
|
||||
.nanoseconds(-65498124754943i64);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, expected);
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/add/argument-higher-units.js
|
||||
#[test]
|
||||
fn argument_higher_units() {
|
||||
let t1 = Time::constant(15, 23, 30, 123_456_789);
|
||||
|
||||
let span = Span::new().days(1);
|
||||
assert_eq!(t1, t1.wrapping_add(span));
|
||||
|
||||
let span = Span::new().weeks(1);
|
||||
assert_eq!(t1, t1.wrapping_add(span));
|
||||
|
||||
let span = Span::new().months(1);
|
||||
assert_eq!(t1, t1.wrapping_add(span));
|
||||
|
||||
let span = Span::new().years(1);
|
||||
assert_eq!(t1, t1.wrapping_add(span));
|
||||
}
|
||||
|
||||
/// DIFFERENCE: We "allow" mixed signs in spans, but they normalize. That is,
|
||||
/// if *any* component of a span is negative, then the whole span is negative.
|
||||
///
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/add/argument-mixed-sign.js
|
||||
#[test]
|
||||
fn argument_mixed_sign() {
|
||||
let t1 = Time::constant(15, 30, 45, 987_654_321);
|
||||
let span = Span::new().hours(1).minutes(-30);
|
||||
let t2 = t1.wrapping_add(span);
|
||||
assert_eq!(t2, Time::constant(14, 0, 45, 987_654_321));
|
||||
}
|
||||
|
||||
/// In Test262, this is seemingly just testing that "plain" objects can
|
||||
/// be passed to the `PlainTime.add` API, as opposed to proper `Duration`
|
||||
/// objects. That doesn't really apply to jiff, because Rust, but we still
|
||||
/// capture the tests here.
|
||||
///
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/add/argument-object.js
|
||||
#[test]
|
||||
fn argument_object() {
|
||||
let t1 = Time::constant(15, 23, 30, 123_456_789);
|
||||
|
||||
let span = Span::new().hours(16);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(7, 23, 30, 123_456_789));
|
||||
|
||||
let span = Span::new().minutes(45);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(16, 8, 30, 123_456_789));
|
||||
|
||||
let span = Span::new().seconds(800);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(15, 36, 50, 123_456_789));
|
||||
|
||||
let span = Span::new().milliseconds(800);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(15, 23, 30, 923_456_789));
|
||||
|
||||
let span = Span::new().microseconds(800);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(15, 23, 30, 124_256_789));
|
||||
|
||||
let span = Span::new().nanoseconds(300);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(15, 23, 30, 123_457_089));
|
||||
|
||||
let t1 = Time::constant(7, 23, 30, 123_456_789);
|
||||
let span = Span::new().hours(-16);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(15, 23, 30, 123_456_789));
|
||||
|
||||
let t1 = Time::constant(16, 8, 30, 123_456_789);
|
||||
let span = Span::new().minutes(-45);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(15, 23, 30, 123_456_789));
|
||||
|
||||
let t1 = Time::constant(15, 36, 50, 123_456_789);
|
||||
let span = Span::new().seconds(-800);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(15, 23, 30, 123_456_789));
|
||||
|
||||
let t1 = Time::constant(15, 23, 30, 923_456_789);
|
||||
let span = Span::new().milliseconds(-800);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(15, 23, 30, 123_456_789));
|
||||
|
||||
let t1 = Time::constant(15, 23, 30, 124_256_789);
|
||||
let span = Span::new().microseconds(-800);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(15, 23, 30, 123_456_789));
|
||||
|
||||
let t1 = Time::constant(15, 23, 30, 123_457_089);
|
||||
let span = Span::new().nanoseconds(-300);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(15, 23, 30, 123_456_789));
|
||||
}
|
||||
|
||||
/// Temporal doesn't have checked arithmetic, so this test just copied
|
||||
/// `argument_object`, but with checked arithmetic.
|
||||
///
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/add/argument-object.js
|
||||
#[test]
|
||||
fn argument_object_checked() {
|
||||
let t1 = Time::constant(15, 23, 30, 123_456_789);
|
||||
|
||||
let span = Span::new().hours(16);
|
||||
assert_eq!(t1.checked_add(span).ok(), None);
|
||||
|
||||
// Added our own test to avoid wrapping.
|
||||
let span = Span::new().hours(2);
|
||||
assert_eq!(
|
||||
t1.checked_add(span).unwrap(),
|
||||
Time::constant(17, 23, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let span = Span::new().minutes(45);
|
||||
assert_eq!(
|
||||
t1.checked_add(span).unwrap(),
|
||||
Time::constant(16, 8, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let span = Span::new().seconds(800);
|
||||
assert_eq!(
|
||||
t1.checked_add(span).unwrap(),
|
||||
Time::constant(15, 36, 50, 123_456_789)
|
||||
);
|
||||
|
||||
let span = Span::new().milliseconds(800);
|
||||
assert_eq!(
|
||||
t1.checked_add(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 923_456_789)
|
||||
);
|
||||
|
||||
let span = Span::new().microseconds(800);
|
||||
assert_eq!(
|
||||
t1.checked_add(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 124_256_789)
|
||||
);
|
||||
|
||||
let span = Span::new().nanoseconds(300);
|
||||
assert_eq!(
|
||||
t1.checked_add(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 123_457_089)
|
||||
);
|
||||
|
||||
let t1 = Time::constant(7, 23, 30, 123_456_789);
|
||||
let span = Span::new().hours(-16);
|
||||
assert_eq!(t1.checked_add(span).ok(), None);
|
||||
|
||||
// Added our own test to avoid wrapping.
|
||||
let t1 = Time::constant(7, 23, 30, 123_456_789);
|
||||
let span = Span::new().hours(-2);
|
||||
assert_eq!(
|
||||
t1.checked_add(span).unwrap(),
|
||||
Time::constant(5, 23, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let t1 = Time::constant(16, 8, 30, 123_456_789);
|
||||
let span = Span::new().minutes(-45);
|
||||
assert_eq!(
|
||||
t1.checked_add(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let t1 = Time::constant(15, 36, 50, 123_456_789);
|
||||
let span = Span::new().seconds(-800);
|
||||
assert_eq!(
|
||||
t1.checked_add(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let t1 = Time::constant(15, 23, 30, 923_456_789);
|
||||
let span = Span::new().milliseconds(-800);
|
||||
assert_eq!(
|
||||
t1.checked_add(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let t1 = Time::constant(15, 23, 30, 124_256_789);
|
||||
let span = Span::new().microseconds(-800);
|
||||
assert_eq!(
|
||||
t1.checked_add(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let t1 = Time::constant(15, 23, 30, 123_457_089);
|
||||
let span = Span::new().nanoseconds(-300);
|
||||
assert_eq!(
|
||||
t1.checked_add(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 123_456_789)
|
||||
);
|
||||
}
|
||||
|
||||
/// DIFFERENCE: Wrapping arithmetic on `Time` always wraps, even when the span
|
||||
/// represents an interval of time bigger than what is supported.
|
||||
///
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/add/argument-string-duration-too-large.js
|
||||
#[test]
|
||||
fn argument_string_duration_too_large() {
|
||||
let t1 = Time::constant(0, 0, 0, 0);
|
||||
let span = Span::new().years(19_998).months(239_976);
|
||||
assert_eq!(t1.wrapping_add(span), t1);
|
||||
assert_eq!(t1.checked_add(span).ok(), None);
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/add/balance-negative-time-units.js
|
||||
#[test]
|
||||
fn balance_negative_time_units() {
|
||||
let t1 = Time::constant(1, 1, 1, 001_001_001);
|
||||
|
||||
let span = Span::new().nanoseconds(-2);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(1, 1, 1, 001_000_999));
|
||||
|
||||
let span = Span::new().microseconds(-2);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(1, 1, 1, 000_999_001));
|
||||
|
||||
let span = Span::new().milliseconds(-2);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(1, 1, 0, 999_001_001));
|
||||
|
||||
let span = Span::new().seconds(-2);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(1, 0, 59, 001_001_001));
|
||||
|
||||
let span = Span::new().minutes(-2);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(0, 59, 1, 001_001_001));
|
||||
|
||||
let span = Span::new().hours(-2);
|
||||
assert_eq!(t1.wrapping_add(span), Time::constant(23, 1, 1, 001_001_001));
|
||||
}
|
||||
16
tests/tc39_262/civil/time/equals.rs
Normal file
16
tests/tc39_262/civil/time/equals.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
use jiff::{civil::Time, Instant};
|
||||
|
||||
/// TODO: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/equals
|
||||
///
|
||||
/// Most tests seem to require parsing. Some also deal with timezones. Many
|
||||
/// are irrelevant because of types.
|
||||
|
||||
/// TODO: Switch to a zoned time, or at least add it.
|
||||
///
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/equals/argument-zoneddatetime-negative-epochnanoseconds.js
|
||||
#[test]
|
||||
fn argument_zoneddatetime_negative_epochnanoseconds() {
|
||||
let instant = Instant::from_unix(-13849764, -999_999_999).unwrap();
|
||||
let time = instant.to_datetime().time();
|
||||
assert_eq!(time, Time::constant(16, 50, 35, 000_000_001));
|
||||
}
|
||||
5
tests/tc39_262/civil/time/mod.rs
Normal file
5
tests/tc39_262/civil/time/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
mod add;
|
||||
mod equals;
|
||||
mod round;
|
||||
mod sub;
|
||||
mod until;
|
||||
551
tests/tc39_262/civil/time/round.rs
Normal file
551
tests/tc39_262/civil/time/round.rs
Normal file
|
|
@ -0,0 +1,551 @@
|
|||
use jiff::{
|
||||
civil::Time,
|
||||
round::{Round, RoundMode, Unit},
|
||||
};
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/rounding-cross-midnight.js
|
||||
#[test]
|
||||
fn rounding_cross_midnight() {
|
||||
let t1 = Time::constant(23, 59, 59, 999_999_999);
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond);
|
||||
assert_eq!(t2, t1);
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond);
|
||||
assert_eq!(t2, Time::constant(0, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond);
|
||||
assert_eq!(t2, Time::constant(0, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond);
|
||||
assert_eq!(t2, Time::constant(0, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second);
|
||||
assert_eq!(t2, Time::constant(0, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute);
|
||||
assert_eq!(t2, Time::constant(0, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Hour);
|
||||
assert_eq!(t2, Time::constant(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingincrement-hours.js
|
||||
#[test]
|
||||
fn rounding_increment_hours() {
|
||||
let t1 = Time::constant(3, 34, 56, 987_654_321);
|
||||
|
||||
let t2 = t1.round(Unit::Hour.increment(1));
|
||||
assert_eq!(t2, Time::constant(4, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Hour.increment(2));
|
||||
assert_eq!(t2, Time::constant(4, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Hour.increment(3));
|
||||
assert_eq!(t2, Time::constant(3, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Hour.increment(4));
|
||||
assert_eq!(t2, Time::constant(4, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Hour.increment(6));
|
||||
assert_eq!(t2, Time::constant(6, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Hour.increment(8));
|
||||
assert_eq!(t2, Time::constant(0, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Hour.increment(12));
|
||||
assert_eq!(t2, Time::constant(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingincrement-minutes.js
|
||||
#[test]
|
||||
fn rounding_increment_minutes() {
|
||||
let t1 = Time::constant(3, 34, 56, 987_654_321);
|
||||
|
||||
let t2 = t1.round(Unit::Minute.increment(1));
|
||||
assert_eq!(t2, Time::constant(3, 35, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.increment(2));
|
||||
assert_eq!(t2, Time::constant(3, 34, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.increment(3));
|
||||
assert_eq!(t2, Time::constant(3, 36, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.increment(4));
|
||||
assert_eq!(t2, Time::constant(3, 36, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.increment(5));
|
||||
assert_eq!(t2, Time::constant(3, 35, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.increment(6));
|
||||
assert_eq!(t2, Time::constant(3, 36, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.increment(10));
|
||||
assert_eq!(t2, Time::constant(3, 30, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.increment(12));
|
||||
assert_eq!(t2, Time::constant(3, 36, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.increment(15));
|
||||
assert_eq!(t2, Time::constant(3, 30, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.increment(20));
|
||||
assert_eq!(t2, Time::constant(3, 40, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.increment(30));
|
||||
assert_eq!(t2, Time::constant(3, 30, 0, 0));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingincrement-seconds.js
|
||||
#[test]
|
||||
fn rounding_increment_seconds() {
|
||||
let t1 = Time::constant(3, 34, 56, 987_654_321);
|
||||
|
||||
let t2 = t1.round(Unit::Second.increment(1));
|
||||
assert_eq!(t2, Time::constant(3, 34, 57, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.increment(2));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.increment(3));
|
||||
assert_eq!(t2, Time::constant(3, 34, 57, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.increment(4));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.increment(5));
|
||||
assert_eq!(t2, Time::constant(3, 34, 55, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.increment(6));
|
||||
assert_eq!(t2, Time::constant(3, 34, 54, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.increment(10));
|
||||
assert_eq!(t2, Time::constant(3, 35, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.increment(12));
|
||||
assert_eq!(t2, Time::constant(3, 35, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.increment(15));
|
||||
assert_eq!(t2, Time::constant(3, 35, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.increment(20));
|
||||
assert_eq!(t2, Time::constant(3, 35, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.increment(30));
|
||||
assert_eq!(t2, Time::constant(3, 35, 0, 0));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingincrement-milliseconds.js
|
||||
#[test]
|
||||
fn rounding_increment_milliseconds() {
|
||||
let t1 = Time::constant(3, 34, 56, 987_654_321);
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(1));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 988_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(2));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 988_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(4));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 988_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(5));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 990_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(8));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 984_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(10));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 990_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(20));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 980_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(25));
|
||||
assert_eq!(t2, Time::constant(3, 34, 57, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(40));
|
||||
assert_eq!(t2, Time::constant(3, 34, 57, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(50));
|
||||
assert_eq!(t2, Time::constant(3, 34, 57, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(100));
|
||||
assert_eq!(t2, Time::constant(3, 34, 57, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(125));
|
||||
assert_eq!(t2, Time::constant(3, 34, 57, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(200));
|
||||
assert_eq!(t2, Time::constant(3, 34, 57, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(250));
|
||||
assert_eq!(t2, Time::constant(3, 34, 57, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.increment(500));
|
||||
assert_eq!(t2, Time::constant(3, 34, 57, 0));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingincrement-microseconds.js
|
||||
#[test]
|
||||
fn rounding_increment_microseconds() {
|
||||
let t1 = Time::constant(3, 34, 56, 987_654_321);
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(1));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(2));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(4));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_656_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(5));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_655_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(8));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_656_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(10));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_650_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(20));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_660_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(25));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_650_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(40));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_640_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(50));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_650_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(100));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_700_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(125));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_625_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(200));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_600_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(250));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_750_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.increment(500));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_500_000));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingincrement-nanoseconds.js
|
||||
#[test]
|
||||
fn rounding_increment_nanoseconds() {
|
||||
let t1 = Time::constant(3, 34, 56, 987_654_321);
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(1));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_321));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(2));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_322));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(4));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_320));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(5));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_320));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(8));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_320));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(10));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_320));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(20));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_320));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(25));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_325));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(40));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_320));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(50));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_300));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(100));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_300));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(125));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_375));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(200));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_400));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(250));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_250));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.increment(500));
|
||||
assert_eq!(t2, Time::constant(3, 34, 56, 987_654_500));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingincrement-invalid.js
|
||||
#[test]
|
||||
fn rounding_increment_invalid() {
|
||||
let t1 = Time::constant(8, 22, 36, 123456789);
|
||||
|
||||
assert!(t1.try_round(Unit::Hour.increment(11)).is_err());
|
||||
assert!(t1.try_round(Unit::Minute.increment(29)).is_err());
|
||||
assert!(t1.try_round(Unit::Second.increment(29)).is_err());
|
||||
assert!(t1.try_round(Unit::Millisecond.increment(29)).is_err());
|
||||
assert!(t1.try_round(Unit::Microsecond.increment(29)).is_err());
|
||||
assert!(t1.try_round(Unit::Nanosecond.increment(29)).is_err());
|
||||
|
||||
assert!(t1.try_round(Unit::Hour.increment(24)).is_err());
|
||||
assert!(t1.try_round(Unit::Minute.increment(60)).is_err());
|
||||
assert!(t1.try_round(Unit::Second.increment(60)).is_err());
|
||||
assert!(t1.try_round(Unit::Millisecond.increment(1_000)).is_err());
|
||||
assert!(t1.try_round(Unit::Microsecond.increment(1_000)).is_err());
|
||||
assert!(t1.try_round(Unit::Nanosecond.increment(1_000)).is_err());
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingincrement-out-of-range.js
|
||||
#[test]
|
||||
fn rounding_increment_out_of_range() {
|
||||
let t1 = Time::constant(12, 34, 56, 000_000_005);
|
||||
|
||||
assert!(t1.try_round(Unit::Nanosecond.increment(-1)).is_err());
|
||||
assert!(t1.try_round(Unit::Nanosecond.increment(0)).is_err());
|
||||
assert!(t1.try_round(Unit::Nanosecond.increment(1_000)).is_err());
|
||||
assert!(t1.try_round(Unit::Nanosecond.increment(1_000_000_001)).is_err());
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingmode-ceil.js
|
||||
#[test]
|
||||
fn rounding_mode_ceil() {
|
||||
let t1 = Time::constant(13, 46, 23, 123_987_500);
|
||||
|
||||
let t2 = t1.round(Unit::Hour.mode(RoundMode::Ceil));
|
||||
assert_eq!(t2, Time::constant(14, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.mode(RoundMode::Ceil));
|
||||
assert_eq!(t2, Time::constant(13, 47, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.mode(RoundMode::Ceil));
|
||||
assert_eq!(t2, Time::constant(13, 46, 24, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.mode(RoundMode::Ceil));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 124_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.mode(RoundMode::Ceil));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_988_000));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.mode(RoundMode::Ceil));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_500));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingmode-expand.js
|
||||
#[test]
|
||||
fn rounding_mode_expand() {
|
||||
let t1 = Time::constant(13, 46, 23, 123_987_500);
|
||||
|
||||
let t2 = t1.round(Unit::Hour.mode(RoundMode::Expand));
|
||||
assert_eq!(t2, Time::constant(14, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.mode(RoundMode::Expand));
|
||||
assert_eq!(t2, Time::constant(13, 47, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.mode(RoundMode::Expand));
|
||||
assert_eq!(t2, Time::constant(13, 46, 24, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.mode(RoundMode::Expand));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 124_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.mode(RoundMode::Expand));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_988_000));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.mode(RoundMode::Expand));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_500));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingmode-floor.js
|
||||
#[test]
|
||||
fn rounding_mode_floor() {
|
||||
let t1 = Time::constant(13, 46, 23, 123_987_500);
|
||||
|
||||
let t2 = t1.round(Unit::Hour.mode(RoundMode::Floor));
|
||||
assert_eq!(t2, Time::constant(13, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.mode(RoundMode::Floor));
|
||||
assert_eq!(t2, Time::constant(13, 46, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.mode(RoundMode::Floor));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.mode(RoundMode::Floor));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.mode(RoundMode::Floor));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_000));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.mode(RoundMode::Floor));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_500));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingmode-halfCeil.js
|
||||
#[test]
|
||||
fn rounding_mode_half_ceil() {
|
||||
let t1 = Time::constant(13, 46, 23, 123_987_500);
|
||||
|
||||
let t2 = t1.round(Unit::Hour.mode(RoundMode::HalfCeil));
|
||||
assert_eq!(t2, Time::constant(14, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.mode(RoundMode::HalfCeil));
|
||||
assert_eq!(t2, Time::constant(13, 46, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.mode(RoundMode::HalfCeil));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.mode(RoundMode::HalfCeil));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 124_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.mode(RoundMode::HalfCeil));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_988_000));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.mode(RoundMode::HalfCeil));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_500));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingmode-halfEven.js
|
||||
#[test]
|
||||
fn rounding_mode_half_even() {
|
||||
let t1 = Time::constant(13, 46, 23, 123_987_500);
|
||||
|
||||
let t2 = t1.round(Unit::Hour.mode(RoundMode::HalfEven));
|
||||
assert_eq!(t2, Time::constant(14, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.mode(RoundMode::HalfEven));
|
||||
assert_eq!(t2, Time::constant(13, 46, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.mode(RoundMode::HalfEven));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.mode(RoundMode::HalfEven));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 124_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.mode(RoundMode::HalfEven));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_988_000));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.mode(RoundMode::HalfEven));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_500));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingmode-halfExpand.js
|
||||
#[test]
|
||||
fn rounding_mode_half_expand() {
|
||||
let t1 = Time::constant(13, 46, 23, 123_987_500);
|
||||
|
||||
let t2 = t1.round(Unit::Hour.mode(RoundMode::HalfExpand));
|
||||
assert_eq!(t2, Time::constant(14, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.mode(RoundMode::HalfExpand));
|
||||
assert_eq!(t2, Time::constant(13, 46, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.mode(RoundMode::HalfExpand));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.mode(RoundMode::HalfExpand));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 124_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.mode(RoundMode::HalfExpand));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_988_000));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.mode(RoundMode::HalfExpand));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_500));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingmode-halfFloor.js
|
||||
#[test]
|
||||
fn rounding_mode_half_floor() {
|
||||
let t1 = Time::constant(13, 46, 23, 123_987_500);
|
||||
|
||||
let t2 = t1.round(Unit::Hour.mode(RoundMode::HalfFloor));
|
||||
assert_eq!(t2, Time::constant(14, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.mode(RoundMode::HalfFloor));
|
||||
assert_eq!(t2, Time::constant(13, 46, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.mode(RoundMode::HalfFloor));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.mode(RoundMode::HalfFloor));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 124_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.mode(RoundMode::HalfFloor));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_000));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.mode(RoundMode::HalfFloor));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_500));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingmode-halfTrunc.js
|
||||
#[test]
|
||||
fn rounding_mode_half_trunc() {
|
||||
let t1 = Time::constant(13, 46, 23, 123_987_500);
|
||||
|
||||
let t2 = t1.round(Unit::Hour.mode(RoundMode::HalfTrunc));
|
||||
assert_eq!(t2, Time::constant(14, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.mode(RoundMode::HalfTrunc));
|
||||
assert_eq!(t2, Time::constant(13, 46, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.mode(RoundMode::HalfTrunc));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.mode(RoundMode::HalfTrunc));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 124_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.mode(RoundMode::HalfTrunc));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_000));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.mode(RoundMode::HalfTrunc));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_500));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/roundingmode-trunc.js
|
||||
#[test]
|
||||
fn rounding_mode_trunc() {
|
||||
let t1 = Time::constant(13, 46, 23, 123_987_500);
|
||||
|
||||
let t2 = t1.round(Unit::Hour.mode(RoundMode::Trunc));
|
||||
assert_eq!(t2, Time::constant(13, 0, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Minute.mode(RoundMode::Trunc));
|
||||
assert_eq!(t2, Time::constant(13, 46, 0, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Second.mode(RoundMode::Trunc));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 0));
|
||||
|
||||
let t2 = t1.round(Unit::Millisecond.mode(RoundMode::Trunc));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_000_000));
|
||||
|
||||
let t2 = t1.round(Unit::Microsecond.mode(RoundMode::Trunc));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_000));
|
||||
|
||||
let t2 = t1.round(Unit::Nanosecond.mode(RoundMode::Trunc));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_500));
|
||||
}
|
||||
|
||||
/// DIFFERENCE: Unlike Temporal, we permit the smallest unit to be missing. It
|
||||
/// defaults to `Nanosecond`.
|
||||
///
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/round/smallestunit-missing.js
|
||||
#[test]
|
||||
fn smallest_unit_missing() {
|
||||
let t1 = Time::constant(13, 46, 23, 123_987_499);
|
||||
|
||||
let t2 = t1.round(Round::new());
|
||||
assert_eq!(t2, t1);
|
||||
|
||||
let t2 = t1.round(Round::new().increment(500));
|
||||
assert_eq!(t2, Time::constant(13, 46, 23, 123_987_500));
|
||||
}
|
||||
327
tests/tc39_262/civil/time/sub.rs
Normal file
327
tests/tc39_262/civil/time/sub.rs
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
use jiff::{civil::Time, span::Span};
|
||||
|
||||
/// TODO
|
||||
///
|
||||
/// All of these require parsing of some kind. Durations I believe.
|
||||
///
|
||||
/// * https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/subtract/argument-duration-out-of-range.js
|
||||
/// * https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/subtract/argument-string-fractional-units-rounding-mode.js
|
||||
/// * https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/subtract/argument-string-negative-fractional-units.js
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/subtract/argument-duration.js
|
||||
#[test]
|
||||
fn argument_duration() {
|
||||
let t1 = Time::constant(15, 23, 30, 123_456_789);
|
||||
let span = Span::new().hours(16);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, Time::constant(23, 23, 30, 123_456_789));
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/subtract/argument-duration-max.js
|
||||
#[test]
|
||||
fn argument_duration_max() {
|
||||
let t1 = Time::midnight();
|
||||
let expected = Time::constant(16, 23, 28, 000_000_001);
|
||||
|
||||
let span = Span::new()
|
||||
.years(19_998)
|
||||
.days(7_304_482)
|
||||
.nanoseconds(27391999999999i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new()
|
||||
.months(239_976)
|
||||
.days(7_304_482)
|
||||
.nanoseconds(27391999999999i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new()
|
||||
.weeks(51_131_374)
|
||||
.days(7_304_482)
|
||||
.nanoseconds(27391999999999i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new().days(7_304_482).nanoseconds(27391999999999i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new().hours(175_307_591).nanoseconds(65498124754943i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span =
|
||||
Span::new().minutes(10_518_455_460i64).nanoseconds(65498124754943i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span =
|
||||
Span::new().seconds(631_107_327_600i64).nanoseconds(65498124754943i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/subtract/argument-duration-max.js
|
||||
#[test]
|
||||
fn argument_duration_min() {
|
||||
let t1 = Time::constant(0, 0, 0, 0);
|
||||
let expected = Time::constant(7, 36, 31, 999_999_999);
|
||||
|
||||
let span = Span::new()
|
||||
.years(-19_998)
|
||||
.days(-7_304_482)
|
||||
.nanoseconds(-27391999999999i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new()
|
||||
.months(-239_976)
|
||||
.days(-7_304_482)
|
||||
.nanoseconds(-27391999999999i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new()
|
||||
.weeks(-51_131_374)
|
||||
.days(-7_304_482)
|
||||
.nanoseconds(-27391999999999i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new().days(-7_304_482).nanoseconds(-27391999999999i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new().hours(-175_307_591).nanoseconds(-65498124754943i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new()
|
||||
.minutes(-10_518_455_460i64)
|
||||
.nanoseconds(-65498124754943i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
|
||||
let span = Span::new()
|
||||
.seconds(-631_107_327_600i64)
|
||||
.nanoseconds(-65498124754943i64);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, expected);
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/subtract/argument-higher-units.js
|
||||
#[test]
|
||||
fn argument_higher_units() {
|
||||
let t1 = Time::constant(15, 23, 30, 123_456_789);
|
||||
|
||||
let span = Span::new().days(1);
|
||||
assert_eq!(t1, t1.wrapping_sub(span));
|
||||
|
||||
let span = Span::new().weeks(1);
|
||||
assert_eq!(t1, t1.wrapping_sub(span));
|
||||
|
||||
let span = Span::new().months(1);
|
||||
assert_eq!(t1, t1.wrapping_sub(span));
|
||||
|
||||
let span = Span::new().years(1);
|
||||
assert_eq!(t1, t1.wrapping_sub(span));
|
||||
}
|
||||
|
||||
/// DIFFERENCE: We "allow" mixed signs in spans, but they normalize. That is,
|
||||
/// if *any* component of a span is negative, then the whole span is negative.
|
||||
///
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/subtract/argument-mixed-sign.js
|
||||
#[test]
|
||||
fn argument_mixed_sign() {
|
||||
let t1 = Time::constant(15, 30, 45, 987_654_321);
|
||||
let span = Span::new().hours(1).minutes(-30);
|
||||
let t2 = t1.wrapping_sub(span);
|
||||
assert_eq!(t2, Time::constant(17, 0, 45, 987_654_321));
|
||||
}
|
||||
|
||||
/// In Test262, this is seemingly just testing that "plain" objects can
|
||||
/// be passed to the `PlainTime.add` API, as opposed to proper `Duration`
|
||||
/// objects. That doesn't really apply to jiff, because Rust, but we still
|
||||
/// capture the tests here.
|
||||
///
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/subtract/argument-object.js
|
||||
#[test]
|
||||
fn argument_object() {
|
||||
let t1 = Time::constant(15, 23, 30, 123_456_789);
|
||||
|
||||
let span = Span::new().hours(16);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(23, 23, 30, 123_456_789));
|
||||
|
||||
let span = Span::new().minutes(45);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(14, 38, 30, 123_456_789));
|
||||
|
||||
let span = Span::new().seconds(45);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(15, 22, 45, 123_456_789));
|
||||
|
||||
let span = Span::new().milliseconds(800);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(15, 23, 29, 323_456_789));
|
||||
|
||||
let span = Span::new().microseconds(800);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(15, 23, 30, 122_656_789));
|
||||
|
||||
let span = Span::new().nanoseconds(800);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(15, 23, 30, 123_455_989));
|
||||
|
||||
let t1 = Time::constant(23, 23, 30, 123_456_789);
|
||||
let span = Span::new().hours(-16);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(15, 23, 30, 123_456_789));
|
||||
|
||||
let t1 = Time::constant(14, 38, 30, 123_456_789);
|
||||
let span = Span::new().minutes(-45);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(15, 23, 30, 123_456_789));
|
||||
|
||||
let t1 = Time::constant(15, 22, 45, 123_456_789);
|
||||
let span = Span::new().seconds(-45);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(15, 23, 30, 123_456_789));
|
||||
|
||||
let t1 = Time::constant(15, 23, 29, 323_456_789);
|
||||
let span = Span::new().milliseconds(-800);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(15, 23, 30, 123_456_789));
|
||||
|
||||
let t1 = Time::constant(15, 23, 30, 122_656_789);
|
||||
let span = Span::new().microseconds(-800);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(15, 23, 30, 123_456_789));
|
||||
|
||||
let t1 = Time::constant(15, 23, 30, 123_455_989);
|
||||
let span = Span::new().nanoseconds(-800);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(15, 23, 30, 123_456_789));
|
||||
}
|
||||
|
||||
/// Temporal doesn't have checked arithmetic, so this test just copied
|
||||
/// `argument_object`, but with checked arithmetic.
|
||||
///
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/subtract/argument-object.js
|
||||
#[test]
|
||||
fn argument_object_checked() {
|
||||
let t1 = Time::constant(15, 23, 30, 123_456_789);
|
||||
|
||||
let span = Span::new().hours(16);
|
||||
assert_eq!(t1.checked_sub(span).ok(), None);
|
||||
|
||||
// Added our own test to avoid wrapping.
|
||||
let span = Span::new().hours(2);
|
||||
assert_eq!(
|
||||
t1.checked_sub(span).unwrap(),
|
||||
Time::constant(13, 23, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let span = Span::new().minutes(45);
|
||||
assert_eq!(
|
||||
t1.checked_sub(span).unwrap(),
|
||||
Time::constant(14, 38, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let span = Span::new().seconds(45);
|
||||
assert_eq!(
|
||||
t1.checked_sub(span).unwrap(),
|
||||
Time::constant(15, 22, 45, 123_456_789)
|
||||
);
|
||||
|
||||
let span = Span::new().milliseconds(800);
|
||||
assert_eq!(
|
||||
t1.checked_sub(span).unwrap(),
|
||||
Time::constant(15, 23, 29, 323_456_789)
|
||||
);
|
||||
|
||||
let span = Span::new().microseconds(800);
|
||||
assert_eq!(
|
||||
t1.checked_sub(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 122_656_789)
|
||||
);
|
||||
|
||||
let span = Span::new().nanoseconds(800);
|
||||
assert_eq!(
|
||||
t1.checked_sub(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 123_455_989)
|
||||
);
|
||||
|
||||
let t1 = Time::constant(23, 23, 30, 123_456_789);
|
||||
let span = Span::new().hours(-16);
|
||||
assert_eq!(t1.checked_sub(span).ok(), None);
|
||||
|
||||
// Added our own test to avoid wrapping.
|
||||
let t1 = Time::constant(23, 23, 30, 123_456_789);
|
||||
let span = Span::new().hours(2);
|
||||
assert_eq!(
|
||||
t1.checked_sub(span).unwrap(),
|
||||
Time::constant(21, 23, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let t1 = Time::constant(14, 38, 30, 123_456_789);
|
||||
let span = Span::new().minutes(-45);
|
||||
assert_eq!(
|
||||
t1.checked_sub(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let t1 = Time::constant(15, 22, 45, 123_456_789);
|
||||
let span = Span::new().seconds(-45);
|
||||
assert_eq!(
|
||||
t1.checked_sub(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let t1 = Time::constant(15, 23, 29, 323_456_789);
|
||||
let span = Span::new().milliseconds(-800);
|
||||
assert_eq!(
|
||||
t1.checked_sub(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let t1 = Time::constant(15, 23, 30, 122_656_789);
|
||||
let span = Span::new().microseconds(-800);
|
||||
assert_eq!(
|
||||
t1.checked_sub(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 123_456_789)
|
||||
);
|
||||
|
||||
let t1 = Time::constant(15, 23, 30, 123_455_989);
|
||||
let span = Span::new().nanoseconds(-800);
|
||||
assert_eq!(
|
||||
t1.checked_sub(span).unwrap(),
|
||||
Time::constant(15, 23, 30, 123_456_789)
|
||||
);
|
||||
}
|
||||
|
||||
/// DIFFERENCE: Wrapping arithmetic on `Time` always wraps, even when the span
|
||||
/// represents an interval of time bigger than what is supported.
|
||||
///
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/subtract/argument-string-duration-too-large.js
|
||||
#[test]
|
||||
fn argument_string_duration_too_large() {
|
||||
let t1 = Time::constant(0, 0, 0, 0);
|
||||
let span = Span::new().years(19_998).months(239_976);
|
||||
assert_eq!(t1.wrapping_sub(span), t1);
|
||||
assert_eq!(t1.checked_sub(span).ok(), None);
|
||||
}
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/subtract/balance-negative-time-units.js
|
||||
#[test]
|
||||
fn balance_negative_time_units() {
|
||||
let t1 = Time::constant(1, 1, 1, 001_001_001);
|
||||
|
||||
let span = Span::new().nanoseconds(2);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(1, 1, 1, 001_000_999));
|
||||
|
||||
let span = Span::new().microseconds(2);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(1, 1, 1, 000_999_001));
|
||||
|
||||
let span = Span::new().milliseconds(2);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(1, 1, 0, 999_001_001));
|
||||
|
||||
let span = Span::new().seconds(2);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(1, 0, 59, 001_001_001));
|
||||
|
||||
let span = Span::new().minutes(2);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(0, 59, 1, 001_001_001));
|
||||
|
||||
let span = Span::new().hours(2);
|
||||
assert_eq!(t1.wrapping_sub(span), Time::constant(23, 1, 1, 001_001_001));
|
||||
}
|
||||
16
tests/tc39_262/civil/time/until.rs
Normal file
16
tests/tc39_262/civil/time/until.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
use jiff::{civil::Time, ToSpan};
|
||||
|
||||
/// Source: https://github.com/tc39/test262/blob/62626e083bd506124aac6c799464d76c2c42851b/test/built-ins/Temporal/PlainTime/prototype/until/argument-cast.js
|
||||
#[test]
|
||||
fn argument_cast() {
|
||||
let t1 = Time::constant(15, 23, 30, 123_456_789);
|
||||
let t2 = Time::constant(16, 34, 0, 0);
|
||||
let span = 1
|
||||
.hours()
|
||||
.minutes(10)
|
||||
.seconds(29)
|
||||
.milliseconds(876)
|
||||
.microseconds(543)
|
||||
.nanoseconds(211);
|
||||
assert_eq!(t1.until(t2), span);
|
||||
}
|
||||
1
tests/tc39_262/mod.rs
Normal file
1
tests/tc39_262/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
mod civil;
|
||||
Loading…
Add table
Add a link
Reference in a new issue