Table of Contents
- Install
- Quick Start
- Why DTT?
- Features
- Supported Timezone Abbreviations
- API Highlights
- Development
- Troubleshooting
- Documentation
- Contributing
- License
Install
Or add to Cargo.toml:
[]
= "0.0.10"
Prerequisites
DTT requires Rust 1.88.0 or later (pinned by time = 0.3.47, which carries the upstream fix for RUSTSEC stack-exhaustion DoS in time < 0.3.47).
| Platform | Setup |
|---|---|
| macOS | brew install rustup-init && rustup-init -y |
| Linux | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y |
| WSL | Same as Linux, run inside your WSL distribution |
| Windows | Download rustup-init.exe from rustup.rs |
After install, verify with rustc --version (must be ≥ 1.88.0). Upgrade an existing toolchain with rustup update stable.
Quick Start
use *;
Run the full demo:
Why DTT?
Most datetime libraries silently produce wrong answers in surprising places. DTT is designed to fail loudly rather than guess:
- Round-trip safety:
DateTime::parse(&dt.format_rfc3339()?)? == dtalways holds. No silent date-only truncation. - Unambiguous timezones:
ISTcould mean Indian (+05:30), Irish (+01:00), or Israel (+02:00). DTT requires explicit suffixes (IST_INDIA,IST_IRELAND,IST_ISRAEL) so you cannot accidentally use the wrong one. - Mixed-sign offsets rejected:
new_with_custom_offset(5, -30)returns an error instead of silently producing+05:30. - Deterministic
Default:DateTime::default()returns the Unix epoch, not wall-clock time, so tests are reproducible. - UTC-normalised equality: Two
DateTimevalues that represent the same instant compare equal regardless of which offset they were stored in. - Strict validation:
is_valid_yearis bounded to the actualtime::Daterange (-9999..=9999), so the validator and the builder always agree.
Features
| Parsing | RFC 3339 with offset, ISO 8601 date-only, custom format strings |
| Formatting | RFC 3339, custom format descriptors |
| Validation | Components, ranges, leap years, ISO 8601, time strings |
| Arithmetic | add_days, add_months, add_years (overflow-checked) |
| Comparisons | Eq, Ord, Hash — all UTC-normalised |
| Calendar helpers | start_of_week, end_of_month, iso_week, iso_year |
| Timezone support | 22 disambiguated abbreviations + custom offsets |
| Serialization | serde round-trip via canonical RFC 3339 strings |
| Cross-platform | macOS, Linux, WSL, Windows |
Supported Timezone Abbreviations
Common abbreviations are intentionally disambiguated. Bare codes like EST, CST, IST, and WADT are not accepted because they refer to multiple zones in the real world.
| Code | Offset | Region |
|---|---|---|
UTC, GMT |
+00:00 | Coordinated Universal Time |
EST_USA |
−05:00 | US Eastern Standard Time |
EDT |
−04:00 | US Eastern Daylight Time |
CST_USA |
−06:00 | US Central Standard Time |
CDT |
−05:00 | US Central Daylight Time |
MST / MDT |
−07/−06 | US Mountain |
PST / PDT |
−08/−07 | US Pacific |
CET / CEST |
+01/+02 | Central Europe |
EET / EEST |
+02/+03 | Eastern Europe |
IST_IRELAND |
+01:00 | Irish Standard Time |
IST_ISRAEL |
+02:00 | Israel Standard Time |
IST_INDIA |
+05:30 | Indian Standard Time |
JST |
+09:00 | Japan |
HKT |
+08:00 | Hong Kong |
CST_CHINA |
+08:00 | China Standard Time |
EST_AUS / AEST |
+10:00 | Australian Eastern |
AEDT |
+11:00 | Australian Eastern Daylight |
ACWST |
+08:45 | Australian Central Western |
For any other zone, use DateTime::new_with_custom_offset(hours, minutes).
Note: DST is not handled automatically. Pick the appropriate code (e.g.
EDTvsEST_USA) for the date range you care about.
API Highlights
Construction
use *;
use UtcOffset;
let now = new; // current UTC
let utc = new_with_tz?; // explicit
let mumbai = new_with_tz?; // disambiguated
let custom = new_with_custom_offset?; // +05:30
let exact = from_components?;
let epoch = default; // 1970-01-01T00:00:00Z
// Builder pattern
let dt = new
.year.month.day
.hour.minute.second
.offset
.build?;
# Ok::
Parsing & Formatting
# use *;
let dt1 = parse?;
let dt2 = parse?;
let dt3 = parse?; // date-only OK
let custom = parse_custom_format?;
let s: String = dt1.format_rfc3339?;
let pretty = dt1.format?;
# Ok::
Arithmetic & Calendar Math
# use *;
let dt = parse?;
let next_day = dt.next_day?;
let prev_day = dt.previous_day?;
let next_week = dt.add_days?;
let next_feb = dt.add_months?; // → 2024-02-29 (leap year aware)
let next_year = dt.add_years?;
let monday = dt.start_of_week?;
let sunday = dt.end_of_week?;
let last_day = dt.end_of_month?;
# Ok::
Macros
use *;
use ;
let now = dtt_now!;
let dt = dtt_parse!?;
let later = dtt_add_days!?;
let secs: = dtt_diff_seconds!;
assert_eq!;
# Ok::
Development
Clone, build, and verify in under a minute on any platform:
The Makefile is a thin wrapper around the underlying Cargo commands,
so the equivalent direct invocations also work:
All commands work identically on macOS, Linux, and WSL. CI exercises
the same matrix on Linux, macOS, and Windows on every PR via
.github/workflows/cross-platform.yml.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
feature 'edition2024' is required from time-core |
Rust < 1.88.0 | rustup update stable |
Err(InvalidTimezone) for "EST", "CST", "IST" |
Bare ambiguous codes are rejected by design | Use a suffixed form (e.g. EST_USA, IST_INDIA) |
Err(InvalidFormat) parsing "2024-01-01T12:00:00" |
RFC 3339 requires an offset | Append Z or +HH:MM |
Err(InvalidTimezone) from new_with_custom_offset(5, -30) |
Mixed-sign offsets are rejected | Pass same-sign components, e.g. (4, 30) |
Err(InvalidDate) from from_components(10000, ...) |
time::Date only supports -9999..=9999 |
Use a year inside that range |
| Tests fail with environment-variable race | cargo test runs tests in parallel |
Already mitigated via serial_test; use cargo test -- --test-threads=1 if you have a custom env-var test |
Documentation
- API reference: https://docs.rs/dtt
- End-to-end example:
examples/dtt.rs - Benchmarks:
benches/criterion.rs— run withcargo bench - Changelog:
CHANGELOG.md - Security policy:
.github/SECURITY.md - Code of conduct:
.github/CODE-OF-CONDUCT.md
Contributing
Contributions are welcome. Please read CONTRIBUTING.md — in particular, all commits must be cryptographically signed (git commit -S).
Quick checklist before opening a PR:
THE ARCHITECT ᴬ Sebastien Rousseau THE ENGINE ᵞ EUXIS ᴬ Enterprise Unified Execution Intelligence System
License
Dual-licensed under Apache 2.0 or MIT, at your option.