Loading page…
Rust walkthroughs
Loading page…
chrono::Duration differ from std::time::Duration and when would you use each?chrono::Duration and std::time::Duration serve similar purposes but have fundamentally different sign semantics: std::time::Duration represents only non-negative time spans and panics on overflow, while chrono::Duration can represent negative durations and handles overflow gracefully with checked/wrapping operations. The std::time::Duration type is part of the standard library and works directly with std::time::Instant and thread sleep operations, whereas chrono::Duration integrates with chrono's date/time types and supports calendar-aware operations. Use std::time::Duration for timeouts, delays, and simple timing with Instant; use chrono::Duration for date arithmetic, scheduling, and any context where negative durations make semantic sense.
use std::time::Duration as StdDuration;
use chrono::Duration as ChronoDuration;
fn main() {
// std::time::Duration: unsigned, non-negative only
let std_dur = StdDuration::new(5, 0);
let std_dur2 = StdDuration::from_secs(10);
// Cannot represent negative durations
// let negative_std = StdDuration::from_secs(-5); // Won't compile
// let negative_std = StdDuration::new(-5, 0); // Won't compile
// chrono::Duration: signed, can be negative
let chrono_dur = ChronoDuration::seconds(5);
let chrono_neg = ChronoDuration::seconds(-5);
println!("Positive: {:?}", chrono_dur);
println!("Negative: {:?}", chrono_neg);
// Convert chrono to std (fails if negative)
if chrono_dur.std().is_ok() {
println!("Chrono to std: {:?}", chrono_dur.std().unwrap());
}
if chrono_neg.std().is_err() {
println!("Cannot convert negative chrono::Duration to std");
}
}The sign difference is the most fundamental distinction.
use std::time::{Duration, Instant};
use chrono::{DateTime, Duration as ChronoDuration, Utc};
fn main() {
// std::time::Duration works with Instant
let start = Instant::now();
std::thread::sleep(Duration::from_millis(100));
let elapsed = start.elapsed();
println!("Elapsed: {:?}", elapsed);
// chrono::Duration works with DateTime
let now: DateTime<Utc> = Utc::now();
let future = now + ChronoDuration::days(7);
let past = now - ChronoDuration::days(7);
let difference = future - past;
println!("Now: {}", now);
println!("Future: {}", future);
println!("Past: {}", past);
println!("Difference: {:?}", difference);
}std::time::Duration integrates with Instant; chrono::Duration integrates with DateTime.
use std::time::{Duration, Instant};
use chrono::{DateTime, Duration as ChronoDuration, Utc};
fn main() {
// std::time::Duration: subtraction can panic
let d1 = Duration::from_secs(10);
let d2 = Duration::from_secs(5);
let diff = d1 - d2; // OK: 5 seconds
// let panic = d2 - d1; // PANIC: attempt to subtract with overflow
// Checked subtraction prevents panic
match d2.checked_sub(d1) {
Some(d) => println!("Result: {:?}", d),
None => println!("Would underflow"),
}
// chrono::Duration: subtraction handles negative naturally
let c1 = ChronoDuration::seconds(10);
let c2 = ChronoDuration::seconds(5);
let diff = c1 - c2; // 5 seconds
let neg = c2 - c1; // -5 seconds (no panic)
println!("Positive diff: {:?}", diff);
println!("Negative diff: {:?}", neg);
// DateTime subtraction returns chrono::Duration
let dt1: DateTime<Utc> = Utc::now();
let dt2: DateTime<Utc> = dt1 + ChronoDuration::hours(2);
let delta = dt2 - dt1; // Returns chrono::Duration
println!("DateTime delta: {:?}", delta);
}chrono::Duration subtraction is infallible; std::time::Duration subtraction can panic.
use std::time::Duration as StdDuration;
use chrono::Duration as ChronoDuration;
fn main() {
// std::time::Duration constructors (unsigned)
let std1 = StdDuration::from_secs(60);
let std2 = StdDuration::from_millis(500);
let std3 = StdDuration::from_micros(1000);
let std4 = StdDuration::from_nanos(100);
let std5 = StdDuration::new(5, 500_000_000); // 5.5 seconds
// chrono::Duration constructors (signed)
let chr1 = ChronoDuration::seconds(60);
let chr2 = ChronoDuration::seconds(-60); // Negative OK
let chr3 = ChronoDuration::milliseconds(500);
let chr4 = ChronoDuration::microseconds(1000);
let chr5 = ChronoDuration::nanoseconds(100);
let chr6 = ChronoDuration::nanoseconds(-100); // Negative nanoseconds
// Chrono also has days, weeks
let week = ChronoDuration::weeks(2);
let days = ChronoDuration::days(30);
println!("Week: {:?}", week);
println!("Days: {:?}", days);
// std has weeks/days only as from_secs multiplication
let std_week = StdDuration::from_secs(7 * 24 * 60 * 60);
println!("Std week: {:?}", std_week);
}chrono::Duration has more human-friendly constructors and supports negative values.
use std::time::Duration as StdDuration;
use chrono::Duration as ChronoDuration;
fn main() {
// std::time::Duration: overflow panics
let std1 = StdDuration::from_secs(u64::MAX);
// let std2 = std1 + StdDuration::from_secs(1); // PANIC: overflow
// Checked operations available
match std1.checked_add(StdDuration::from_secs(1)) {
Some(d) => println!("Result: {:?}", d),
None => println!("Overflow occurred"),
}
// chrono::Duration: uses i64 internally, checked by default
let chr1 = ChronoDuration::seconds(i64::MAX / 1_000_000_000);
// Chrono has checked, saturating, and overflowing variants
let result = chr1.checked_add(ChronoDuration::seconds(1));
match result {
Some(d) => println!("Result: {:?}", d),
None => println!("Chrono overflow"),
}
}Both have checked operations, but chrono::Duration handles larger ranges with sign.
use std::time::Duration as StdDuration;
use chrono::Duration as ChronoDuration;
fn main() {
// chrono::Duration -> std::time::Duration (may fail if negative)
let chrono_pos = ChronoDuration::seconds(5);
let std_dur = chrono_pos.to_std().unwrap();
println!("Chrono to std: {:?}", std_dur);
let chrono_neg = ChronoDuration::seconds(-5);
match chrono_neg.to_std() {
Ok(d) => println!("Converted: {:?}", d),
Err(e) => println!("Error: {}", e), // NegHum
}
// std::time::Duration -> chrono::Duration (always succeeds)
let std_dur = StdDuration::from_secs(10);
let chrono_dur = ChronoDuration::from_std(std_dur);
println!("Std to chrono: {:?}", chrono_dur);
// chrono::Duration::std() is same as to_std()
let chrono_dur = ChronoDuration::seconds(30);
let std = chrono_dur.std();
match std {
Ok(d) => println!("std(): {:?}", d),
Err(_) => println!("Cannot convert negative"),
}
}to_std() can fail; from_std() always succeeds since std durations are non-negative.
use std::time::Duration;
use std::thread;
use chrono::Duration as ChronoDuration;
fn main() {
// std::time::Duration is required for thread::sleep
thread::sleep(Duration::from_millis(100));
// chrono::Duration must be converted first
let chrono_dur = ChronoDuration::milliseconds(100);
thread::sleep(chrono_dur.to_std().unwrap());
// For negative chrono durations, take absolute or handle error
let chrono_neg = ChronoDuration::milliseconds(-100);
let sleep_dur = chrono_neg.to_std().unwrap_or(Duration::ZERO);
// Or use absolute value
let abs_dur = chrono_neg.abs().to_std().unwrap();
}std::time::Duration is the only type accepted by thread::sleep.
use std::time::Duration;
use std::sync::mpsc;
fn main() {
let (tx, rx) = mpsc::channel();
// std::time::Duration for timeouts
match rx.recv_timeout(Duration::from_millis(100)) {
Ok(msg) => println!("Received: {}", msg),
Err(e) => println!("Timeout or error: {}", e),
}
// Async runtimes also use std::time::Duration
// tokio::time::sleep(Duration::from_secs(1)).await;
// async_std::task::sleep(Duration::from_secs(1)).await;
}All standard library timeout operations require std::time::Duration.
use chrono::{DateTime, Duration, NaiveDate, Utc};
fn main() {
// chrono::Duration enables date arithmetic
let date = NaiveDate::from_ymd_opt(2024, 3, 15).unwrap();
// Add/subtract durations
let future = date + Duration::days(30);
let past = date - Duration::days(30);
println!("Original: {}", date);
println!("Future: {}", future);
println!("Past: {}", past);
// Calculate difference between dates
let diff = future - past; // Returns chrono::Duration
println!("Difference: {} days", diff.num_days());
// Negative durations for countdown
let deadline = NaiveDate::from_ymd_opt(2024, 12, 31).unwrap();
let today = NaiveDate::from_ymd_opt(2024, 6, 15).unwrap();
let until_deadline = deadline - today;
if until_deadline.num_days() > 0 {
println!("{} days until deadline", until_deadline.num_days());
} else {
println!("Deadline passed {} days ago", -until_deadline.num_days());
}
}Date arithmetic naturally produces chrono::Duration with sign.
use std::time::Duration as StdDuration;
use chrono::Duration as ChronoDuration;
fn main() {
// Both support comparison
let std1 = StdDuration::from_secs(5);
let std2 = StdDuration::from_secs(10);
println!("std1 < std2: {}", std1 < std2);
let chr1 = ChronoDuration::seconds(5);
let chr2 = ChronoDuration::seconds(10);
let chr3 = ChronoDuration::seconds(-5);
println!("chr1 < chr2: {}", chr1 < chr2);
println!("chr3 < chr1: {}", chr3 < chr1); // Negative is less than positive
// Sorting works correctly
let mut durations = vec![
ChronoDuration::seconds(10),
ChronoDuration::seconds(-5),
ChronoDuration::seconds(0),
ChronoDuration::seconds(5),
];
durations.sort();
println!("Sorted: {:?}", durations);
}chrono::Duration comparisons handle sign correctly.
use chrono::Duration;
fn main() {
let negative = Duration::seconds(-100);
let positive = Duration::seconds(100);
// Check sign
println!("Is negative: {}", negative.is_negative());
println!("Is zero: {}", Duration::zero().is_zero());
// Get absolute value
let abs = negative.abs();
println!("Absolute: {:?}", abs);
// Negate
let negated = positive.num_seconds() * -1;
println!("Negated: {}", negated);
// Duration math with signs
let a = Duration::seconds(100);
let b = Duration::seconds(-50);
let result = a + b; // 50 seconds
println!("Sum: {:?}", result);
// Duration from nanos handles sign
let precise = Duration::nanoseconds(-1_500_000_000); // -1.5 seconds
println!("Precise: {:?}", precise);
println!("As seconds: {}", precise.num_seconds());
println!("As millis: {}", precise.num_milliseconds());
}chrono::Duration provides sign-aware operations absent in std::time::Duration.
use std::time::Duration as StdDuration;
use chrono::Duration as ChronoDuration;
fn main() {
// std::time::Duration limits
// - Minimum: Duration::ZERO
// - Maximum: Duration::MAX (~584 billion years)
println!("Std max: {:?}", StdDuration::MAX);
println!("Std zero: {:?}", StdDuration::ZERO);
// chrono::Duration limits (i64-based)
// - Minimum: Duration::min_value() (~-292 billion years)
// - Maximum: Duration::max_value() (~+292 billion years)
println!("Chrono max: {:?}", ChronoDuration::max_value());
println!("Chrono min: {:?}", ChronoDuration::min_value());
// Nanosecond precision for both
let std_nano = StdDuration::from_nanos(1);
let chrono_nano = ChronoDuration::nanoseconds(1);
println!("Std nano: {:?}", std_nano);
println!("Chrono nano: {:?}", chrono_nano);
}Both support nanosecond precision; chrono spans a symmetric range around zero.
use std::time::{Duration, Instant};
use chrono::{DateTime, Duration as ChronoDuration, Utc};
fn main() {
// USE std::time::Duration FOR:
// 1. Thread sleep
std::thread::sleep(Duration::from_millis(100));
// 2. Timeout operations
// rx.recv_timeout(Duration::from_secs(5));
// 3. Instant arithmetic
let start = Instant::now();
let deadline = start + Duration::from_secs(30);
// 4. Async runtimes
// tokio::time::sleep(Duration::from_secs(1)).await;
// USE chrono::Duration FOR:
// 1. DateTime arithmetic
let now: DateTime<Utc> = Utc::now();
let deadline = now + ChronoDuration::days(7);
// 2. Negative durations (countdowns, differences)
let remaining = deadline - now;
if remaining.is_negative() {
println!("Deadline passed!");
}
// 3. Calendar-aware operations
let future = now + ChronoDuration::weeks(2);
// 4. Date scheduling
// let next_run = last_run + ChronoDuration::days(1);
}Choose based on the API you're integrating with.
Core difference: std::time::Duration is unsigned (non-negative only), while chrono::Duration is signed (supports negative values).
When to use std::time::Duration:
thread::sleep)Instant arithmetic for measuring elapsed timeWhen to use chrono::Duration:
Conversion:
chrono::Duration::to_std() → Result<std::time::Duration, ...> (fails if negative)chrono::Duration::from_std(std_dur) → chrono::Duration (always succeeds)Key insight: The choice is usually determined by the API you're working with. Standard library and most async runtimes require std::time::Duration. Chrono's date/time types produce and consume chrono::Duration. The critical distinction is handling negative durations: if your application logic involves "time until deadline" that can be negative (deadline passed), you need chrono::Duration. If you're measuring elapsed time or setting timeouts, std::time::Duration is simpler and more widely supported in the ecosystem.