1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//! # tzcraft
//!
//! A date and time library that refuses the usual design axioms.
//!
//! ## The four axioms
//!
//! **1. One timeline.** [`Ticks`] is the only type that does instant
//! arithmetic: a signed 128-bit nanosecond counter since the Unix epoch.
//! That single width buys full nanosecond precision *and* a range of roughly
//! ±292 billion years, so there is no "small instant / large instant" split
//! and no overflow-collapse strategy to learn. [`Duration`] is a distinct
//! signed span type — you cannot add two instants, the type system says so.
//!
//! **2. Civil types are projections, not owners.** [`Date`],
//! [`TimeOfDay`] and [`CivilDateTime`] hold no arithmetic of their own; they
//! are pure projections of the timeline onto the proleptic Gregorian
//! calendar. Calendar-aware operations (months, years) exist once, as
//! project → adjust → re-project. There is no matrix of `Add` impls to
//! implement or misuse.
//!
//! **3. The compiler is the calendar.** Every civil computation — leap
//! rules, the day-count inversion, weekdays, ISO weeks — is a `const fn`,
//! so the compiler folds calendar math at compile time. Timezones are
//! `const` data too: a [`Zone`] is either UTC or a fixed offset, carried
//! inline with the instant in [`Zoned`]. There is no global registry, no
//! mutable "current zone", no IANA download, no hidden context.
//!
//! **4. The codec picks the wire shape.** Every type implements `nextjson`'s
//! format-neutral contracts exactly once. Human-readable codecs (JSON via
//! `nextjson`) see ISO 8601 / RFC 3339 text; binary codecs (`rustbinary`)
//! see compact integers. The same implementation, two shapes, zero feature
//! toggles. JSON stays readable; the binary profile stays small.
//!
//! ## Scope, stated plainly
//!
//! `tzcraft` is `no_std` + `alloc`, `#![deny(unsafe_code)]`, with no
//! dependencies beyond `nextjson` (text/`serde`) and `rustbinary` (binary).
//! It does **not** ship an IANA timezone database and does **not** pretend
//! that fixed offsets are daylight-saving rules. If a wall clock must follow
//! real transitions, resolve the offset with your own policy and hand the
//! resulting `Zone::Fixed` to the library. The seam is explicit on purpose.
//!
//! ## `chrono` replacement surface
//!
//! The everyday `chrono` API is covered: strftime-style `format` /
//! `parse_from_str` on every type, `Days` / `Months` / `IsoWeek` units,
//! `from_timestamp` / `timestamp(_millis/_micros/_nanos)`, `Duration`
//! constructors and `num_*` counts, `signed_duration_since`,
//! `checked_add_signed`, `with_year`/`with_month`/..., RFC 2822, and the
//! serde story via `nextjson` / `rustbinary`. Three deliberate differences:
//! `format()` returns `Result` (unknown directives are errors), timestamps
//! use floor semantics for pre-epoch instants, and `num_*` returns
//! `Result<i64>` instead of silently overflowing. `Local` (system-local
//! offset) is out of scope without platform FFI; supply the offset yourself
//! through `Zone::fixed`. The full mapping table lives in the README.
//!
//! ## Quick start
//!
//! ```
//! use tzcraft::{Date, Duration, Months, Offset, Ticks, Weekday, Zone, Zoned};
//!
//! // One timeline, any reading.
//! let launch = Ticks::from_rfc3339("2024-06-15T08:30:00Z")?;
//! let local = launch.to_zoned(Zone::fixed(Offset::from_hms(8, 0, 0)?));
//! assert_eq!(local.to_rfc3339(tzcraft::FractionDigits::None), "2024-06-15T16:30:00+08:00");
//! assert_eq!(local.date()?.weekday(), Weekday::Saturday);
//!
//! // Const calendar math: the compiler computes this at compile time.
//! const NEW_YEAR_2025: Date = Date::from_days_since_epoch(20_089);
//! const WEEKDAY: Weekday = NEW_YEAR_2025.weekday();
//! assert_eq!(WEEKDAY, Weekday::Wednesday);
//!
//! // Calendar-aware months clamp instead of overflowing.
//! let jan = Date::from_ymd(2023, 1, 31)?;
//! assert_eq!(jan.checked_add_months(Months::new(1))?, Date::from_ymd(2023, 2, 28)?);
//!
//! // Durations are signed and ISO 8601 round-trip cleanly.
//! let span = Duration::from_iso8601("P1DT2H3M4.5S")?;
//! assert_eq!(span.to_iso8601(), "P1DT2H3M4.5S");
//!
//! // Text and binary codecs share one implementation.
//! let json = nextjson::nextencode(&local)?;
//! let back: Zoned = nextjson::nextdecode(&json)?;
//! assert_eq!(back, local);
//! let bin = tzcraft::binary::encode(&local)?;
//! let back: Zoned = tzcraft::binary::decode(&bin)?;
//! assert_eq!(back, local);
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! ## `chrono` migration in one glance
//!
//! ```
//! use tzcraft::{CivilDateTime, Date, Duration, Months, Ticks, Weekday};
//!
//! // `Utc::now().timestamp_millis()`
//! let now_ms = Ticks::now()?.timestamp_millis()?;
//! // `NaiveDate::from_ymd_opt(2024, 2, 29).unwrap()`
//! let d = Date::from_ymd(2024, 2, 29)?;
//! // `d.format("%A %d %B %Y")`
//! assert_eq!(d.format("%A %d %B %Y")?, "Thursday 29 February 2024");
//! // `d.and_hms_opt(12, 0, 0).unwrap()`
//! let dt = d.and_hms(12, 0, 0)?;
//! // `dt.format("%Y-%m-%d %H:%M:%S")`
//! assert_eq!(dt.format("%Y-%m-%d %H:%M:%S")?, "2024-02-29 12:00:00");
//! // `d.checked_add_months(Months::new(1))`, `checked_add_days(Days::new(1))`
//! assert_eq!(d.checked_add_months(Months::new(1))?, Date::from_ymd(2024, 3, 29)?);
//! // `NaiveDateTime::parse_from_str`
//! assert_eq!(
//! CivilDateTime::parse_from_str("2024-02-29 12:00:00", "%Y-%m-%d %H:%M:%S")?,
//! dt
//! );
//! // `dt.signed_duration_since(...)`
//! assert_eq!(dt.signed_duration_since(dt), Duration::ZERO);
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
// `doc_auto_cfg` adds "Available on crate feature ..." badges on docs.rs
// (nightly); on stable it is inert.
extern crate alloc;
extern crate std;
pub use crate;
pub use crateDate;
pub use crateCivilDateTime;
pub use crateDuration;
pub use crate;
pub use crateFractionDigits;
pub use crateOffset;
pub use crateTicks;
pub use crateTimeOfDay;
pub use crate;
pub use crateZone;
pub use crateZoned;