Expand description
Β§Tempotime
A Luxon.js-inspired datetime library for Rust with zero dependencies by default.
Tempotime provides a clean, immutable, and chainable API for working with dates and times in Rust. Inspired by the elegant design of Luxon.js (the modern successor to Moment.js), it brings that same developer-friendly experience to Rust while offering unique advantages like zero-dependency operation for UTC-only use cases.
Β§π Key Features
- π Zero dependencies by default β UTC-only DateTime using only
std::time - π Immutable operations β All methods return new instances, preventing bugs
- βοΈ Chainable API β Fluent interface for complex date operations
- π Optional timezone support β Enable
tzfeature for full IANA timezone database - π Luxon-compatible formatting β Familiar, intuitive token-based formatting
- π¦ Small footprint β ~175KB binary in zero-deps mode vs ~2MB with full features
- π Serde support β Optional JSON serialization with ISO-8601 strings
- β‘ Fast compilation β Minimal dependencies mean quick build times
Β§π Quick Start
use tempotime::{dt, Duration};
// Get current time
let now = dt();
// Chain operations fluently
let future = now
.plus(&Duration::from_object(&[("weeks", 2), ("days", 3)]))
.start_of("day");
// Format output beautifully
println!("{}", future.to_format("MMMM do, yyyy 'at' h:mm a"));
// Output: "November 16th, 2025 at 12:00 am"Β§π¦ Installation
Add to your Cargo.toml:
# Zero-deps mode (UTC only, smallest binary)
[dependencies]
tempotime = "0.1"
# With timezone support (IANA timezone database)
[dependencies]
tempotime = { version = "0.1", features = ["tz"] }
# With JSON serialization
[dependencies]
tempotime = { version = "0.1", features = ["serde"] }
# All features enabled
[dependencies]
tempotime = { version = "0.1", features = ["tz", "serde"] }Β§π― Feature Flags
| Feature | Description | Binary Impact | Use When |
|---|---|---|---|
std (default) | Standard library support | Base | Always enabled |
chrono | Accurate month/year math | +~2MB | Need precise date arithmetic |
tz | IANA timezone database | +~2MB | Need timezone conversions |
serde | JSON serialization | +~100KB | Need to serialize/deserialize |
Β§π Examples
Β§Basic DateTime Operations
use tempotime::{dt, DateTime, Duration};
// Create DateTime instances
let now = DateTime::now();
let iso = DateTime::from_iso("2025-10-30T14:30:00Z").unwrap();
let formatted = DateTime::from_format("Oct 30, 2025", "MMM dd, yyyy").unwrap();
// Add or subtract durations
let tomorrow = now.clone().plus(&Duration::from_object(&[("days", 1)]));
let last_week = now.clone().minus(&Duration::from_object(&[("weeks", 1)]));
// Round to start/end of units
let start_of_day = now.clone().start_of("day"); // 00:00:00
let end_of_month = now.end_of("month"); // Last millisecond of monthΒ§Chainable Operations
use tempotime::{dt, Duration};
// Complex operations in a single chain
let result = dt()
.plus(&Duration::from_object(&[("days", 3), ("hours", 2)]))
.start_of("day")
.to_format("yyyy-MM-dd HH:mm:ss");
println!("3 days from now (start of day): {}", result);Β§Formatting Dates
use tempotime::dt;
let now = dt();
// Custom formatting with tokens
println!("{}", now.to_format("yyyy-MM-dd")); // "2025-10-30"
println!("{}", now.to_format("MMMM do, yyyy")); // "October 30th, 2025"
println!("{}", now.to_format("EEEE 'at' h:mm a")); // "Wednesday at 2:30 pm"
println!("{}", now.to_format("yyyy-MM-dd'T'HH:mm:ss")); // "2025-10-30T14:30:00"
// Locale presets
use tempotime::DateTime;
println!("{}", now.to_locale_string(DateTime::DATE_SHORT)); // "10/30/2025"
println!("{}", now.to_locale_string(DateTime::DATE_FULL)); // "October 30, 2025"
println!("{}", now.to_locale_string(DateTime::TIME_SIMPLE)); // "2:30 pm"
println!("{}", now.to_locale_string(DateTime::DATETIME_MED)); // "Oct 30, 2025, 2:30 pm"Β§Working with Timezones
use tempotime::dt;
// Convert to different timezones
let utc = dt();
let ny = utc.clone().set_zone("America/New_York");
let tokyo = utc.clone().set_zone("Asia/Tokyo");
println!("UTC: {}", utc.to_format("h:mm a"));
println!("New York: {}", ny.to_format("h:mm a"));
println!("Tokyo: {}", tokyo.to_format("h:mm a"));Β§Durations
use tempotime::Duration;
// Create durations with multiple units
let dur = Duration::from_object(&[
("weeks", 2),
("days", 3),
("hours", 4),
]);
// Convert to different units
println!("Total hours: {}", dur.as_unit("hours"));
println!("Total days: {}", dur.as_unit("days"));
// Export as object
let obj = dur.to_object();Β§Intervals
use tempotime::{dt, Duration, Interval};
// Define a time interval
let start = dt();
let end = start.clone().plus(&Duration::from_object(&[("days", 30)]));
let interval = Interval::from_date_times(start, end);
// Check if a datetime falls within the interval
let check = dt().plus(&Duration::from_object(&[("days", 15)]));
assert!(interval.contains(&check));
// Get interval length
println!("Interval length: {} days", interval.length("days").as_unit("days"));Β§Time Differences
use tempotime::DateTime;
let now = DateTime::now();
let past = DateTime::from_iso("2025-01-01T00:00:00Z").unwrap();
// Calculate differences in various units
println!("Days ago: {:.0}", now.diff(&past, "days"));
println!("Hours ago: {:.1}", now.diff(&past, "hours"));
println!("Years ago: {:.2}", now.diff(&past, "years"));Β§π¨ Format Tokens
Tempotime supports Luxon.js-style formatting tokens:
| Token | Output | Description |
|---|---|---|
yyyy | 2025 | 4-digit year |
yy | 25 | 2-digit year |
MMMM | October | Full month name |
MMM | Oct | Short month name |
MM | 10 | 2-digit month |
M | 10 | Month (no padding) |
dd | 30 | 2-digit day |
d | 30 | Day (no padding) |
do | 30th | Day with ordinal suffix |
EEEE | Wednesday | Full weekday name |
EEE | Wed | Short weekday name |
HH | 14 | 24-hour (padded) |
H | 14 | 24-hour (no padding) |
hh | 02 | 12-hour (padded) |
h | 2 | 12-hour (no padding) |
mm | 30 | Minutes (padded) |
ss | 00 | Seconds (padded) |
SSS | 123 | Milliseconds |
a | pm | AM/PM lowercase |
Escape literal text with single quotes: 'at' β βatβ
Β§βοΈ Zero-Deps Mode
By default, tempotime uses only std::time::SystemTime for UTC timestamps,
resulting in zero external dependencies.
Β§Advantages
- β Zero external dependencies
- β Fast compilation (~2-3 seconds vs ~30 seconds with full features)
- β Tiny binary footprint (~175KB vs ~2MB)
- β Perfect for microservices, CLI tools, and embedded systems
- β Full API compatibility (same methods work identically)
Β§Limitations
- β οΈ UTC only (
.set_zone()is a no-op withouttzfeature) - β οΈ Month/year arithmetic uses approximations (30 days/month, 365 days/year)
- β οΈ No DST (Daylight Saving Time) handling
- β οΈ
.local()returns UTC time
Β§When to Use
Use zero-deps mode when:
- You only need UTC timestamps
- Binary size is critical
- Compilation speed matters
- You want minimal dependencies
Enable chrono or tz features when:
- You need accurate month/year arithmetic
- Timezone conversions are required
- DST handling is important
Β§π Comparison with Other Libraries
Β§vs. chrono
// chrono (verbose, mutable)
use chrono::{Utc, Duration};
let dt = Utc::now()
.checked_add_signed(Duration::days(3))
.unwrap()
.format("%Y-%m-%d")
.to_string();
// tempotime (clean, immutable)
use tempotime::{dt, Duration};
let dt = dt()
.plus(&Duration::from_object(&[("days", 3)]))
.to_format("yyyy-MM-dd");Β§vs. time
Tempotime provides:
- Immutable-by-default design
- Luxon-style formatting tokens
- Object-based duration syntax
- More intuitive chainable API
- Optional zero-dependency mode
Β§π€ Contributing
Contributions are welcome! This is a community-driven port of Luxon.js to Rust.
Β§π License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.
Β§π Inspiration
This project is inspired by Luxon.js, the modern successor to Moment.js, bringing its elegant API design to the Rust ecosystem.
StructsΒ§
- Date
Time - A date and time value with optional timezone support.
- Duration
- A length of time with multiple units.
- Interval
- A range of time between two DateTimes.