Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Time Zones

jiff is a newer date and time crate. Its time zone support is built in rather than an add-on, and Span represents calendar durations. These recipes show what jiff does differently from chrono and time; see Choosing between chrono, time and jiff for how the crates compare.

Examine the current time with a time zone

jiff Date and time

Use jiff when you need named IANA time zones without an extra crate; see Choosing between chrono, time and jiff. Gets the current Zoned datetime in the system time zone, converts it to another zone such as Asia/Tokyo with Zoned::in_tz, and reads its parts. A Zoned carries its time zone, so the UTC offset is always correct for that instant. time only has fixed offsets, so it cannot do this lookup.

use jiff::{Timestamp, Zoned};

fn main() -> Result<(), jiff::Error> {
    let now = Zoned::now();
    println!("Local time: {now}");

    let tokyo = now.in_tz("Asia/Tokyo")?;
    println!("In Tokyo:   {tokyo}");
    println!("UTC offset: {}", tokyo.offset());

    let timestamp: Timestamp = now.timestamp();
    println!("Timestamp:  {timestamp}");

    println!(
        "Year {}, month {}, day {}, weekday {:?}",
        now.year(),
        now.month(),
        now.day(),
        now.weekday()
    );
    println!(
        "Time {:02}:{:02}:{:02}",
        now.hour(),
        now.minute(),
        now.second()
    );
    Ok(())
}

Parse and format a datetime with a time zone

jiff Date and time

Use jiff when the time zone name must survive a round trip through text; see Choosing between chrono, time and jiff. Parses an RFC 9557 string, which includes an IANA time zone name ([America/New_York]) as well as the offset, into a Zoned using FromStr. Output is formatted with Zoned::strftime, which can print the zone abbreviation (EDT), and strtime::parse handles custom patterns. Invalid input returns an Err.

use jiff::Zoned;
use jiff::civil::Date;
use jiff::fmt::strtime;

fn main() -> Result<(), jiff::Error> {
    // RFC 9557 strings carry an IANA time zone name alongside the offset.
    let zoned: Zoned = "2024-07-11T01:14:00-04:00[America/New_York]".parse()?;
    println!("Parsed:    {zoned}");
    println!(
        "Formatted: {}",
        zoned.strftime("%A, %B %-d, %Y at %-I:%M %p %Z")
    );

    // Parsing with a custom strftime-style pattern.
    let date: Date = strtime::parse("%d/%m/%Y", "11/07/2024")?.to_date()?;
    println!("Custom:    {date}");

    // Invalid input is an `Err`, not a panic.
    let bad = "not a date".parse::<Zoned>();
    println!("Invalid:   {}", bad.is_err());
    Ok(())
}

Perform calendar arithmetic with Span

jiff Date and time

Use jiff when calendar arithmetic has to follow daylight saving time; see Choosing between chrono, time and jiff. A Span is a duration made of calendar units such as days and weeks as well as clock units. Zoned::checked_add applies it with the time zone taken into account, so adding one day to 12:00 before a spring-forward change gives 12:00 the next day, while adding 24 hours gives 13:00. A fixed-offset type such as time’s OffsetDateTime cannot tell these apart. checked_add returns an Err rather than panicking on overflow, and Zoned::until computes the difference between two datetimes.

use jiff::{Span, SpanRound, Unit, Zoned, civil};

fn main() -> Result<(), jiff::Error> {
    let start = civil::date(2024, 3, 9)
        .at(12, 0, 0, 0)
        .in_tz("America/New_York")?;

    // Calendar-aware arithmetic: clocks spring forward on March 10, so that day
    // is only 23 hours long. Adding one day still lands on 12:00, while adding
    // 24 hours lands on 13:00.
    let next_day = start.checked_add(Span::new().days(1))?;
    println!("{start} + 1 day   = {next_day}");

    let in_24_hours = start.checked_add(Span::new().hours(24))?;
    println!("{start} + 24 hours = {in_24_hours}");

    // Mixed units, and checked_add returns `Err` on overflow instead of panicking.
    let later = start.checked_add(Span::new().weeks(2).days(1).hours(3))?;
    println!("Two weeks, a day and 3 hours later: {later}");

    let overflow = start.checked_add(Span::new().years(10_000));
    println!("Overflow is an error: {}", overflow.is_err());

    // The difference between two datetimes, balanced up to hours.
    let end: Zoned = "2024-03-12T09:30:00-04:00[America/New_York]".parse()?;
    let diff = start.until((Unit::Hour, &end))?;
    println!("Until {end}: {diff:#}");

    let rounded = start.until(&end)?.round(
        SpanRound::new()
            .largest(Unit::Day)
            .smallest(Unit::Hour)
            .relative(&start),
    )?;
    println!("Rounded: {rounded:#}");
    Ok(())
}