Loading pageā¦
Rust walkthroughs
Loading pageā¦
chrono::DateTime::from_utc and with_timezone for timezone conversions?from_utc constructs a DateTime from a UTC timestamp combined with a timezone, treating the input as UTC time and computing the local representation. with_timezone converts an existing DateTime from one timezone to another, preserving the same instant in time but changing the offset and local representation. The key distinction is intent: from_utc creates a DateTime from UTC components (you have UTC time and want to view it in a timezone), while with_timezone transforms between timezones (you have a moment in time and want to see it in a different timezone). Both produce equivalent results when starting from UTC, but with_timezone is more general since it works between any two timezones, not just from UTC. In chrono, DateTime<Utc> can call with_timezone(&Tz) to get DateTime<Tz>, and internally this uses the same offset calculation as from_utc.
use chrono::{DateTime, TimeZone, Utc, FixedOffset, Local};
fn main() {
// from_utc constructs a DateTime from a UTC timestamp in a timezone
// The input is interpreted as UTC, then converted to the target timezone
// Create a UTC time: 2024-03-15 10:00:00 UTC
let utc_time = Utc.ymd(2024, 3, 15).and_hms(10, 0, 0);
// Convert to Eastern Time (UTC-5)
let eastern = FixedOffset::west(5 * 3600)
.from_utc_datetime(&utc_time.naive_utc());
println!("UTC: {}", utc_time);
println!("Eastern: {}", eastern);
// Eastern shows 05:00 (10:00 UTC - 5 hours)
// Using from_utc with different timezone types
let local: DateTime<Local> = Local.from_utc_datetime(&utc_time.naive_utc());
println!("Local: {}", local);
// The instant in time is the same, only the representation changes
}from_utc takes a naive UTC datetime and produces a datetime in the target timezone.
use chrono::{DateTime, TimeZone, Utc, FixedOffset, Local};
fn main() {
// with_timezone converts a DateTime from one timezone to another
// It preserves the same instant, changing only the representation
// Start with a UTC datetime
let utc_dt: DateTime<Utc> = Utc.ymd(2024, 3, 15).and_hms(10, 0, 0);
println!("UTC: {}", utc_dt);
// Convert to Eastern Time
let eastern = FixedOffset::west(5 * 3600);
let eastern_dt: DateTime<FixedOffset> = utc_dt.with_timezone(&eastern);
println!("Eastern: {}", eastern_dt);
// Convert to Local timezone
let local_dt: DateTime<Local> = utc_dt.with_timezone(&Local);
println!("Local: {}", local_dt);
// All represent the same instant in time
assert_eq!(utc_dt.timestamp(), eastern_dt.timestamp());
assert_eq!(utc_dt.timestamp(), local_dt.timestamp());
}with_timezone is called on an existing DateTime and converts it to a different timezone.
use chrono::{DateTime, TimeZone, Utc, FixedOffset};
fn main() {
let utc_dt: DateTime<Utc> = Utc.ymd(2024, 6, 15).and_hms(14, 30, 0);
// Method 1: from_utc
let eastern = FixedOffset::west(5 * 3600);
let from_utc_result = eastern.from_utc_datetime(&utc_dt.naive_utc());
// Method 2: with_timezone
let with_tz_result = utc_dt.with_timezone(&eastern);
// Both produce the same result
assert_eq!(from_utc_result, with_tz_result);
println!("from_utc: {}", from_utc_result);
println!("with_timezone: {}", with_tz_result);
// They represent the same instant with the same offset
assert_eq!(from_utc_result.timestamp(), with_tz_result.timestamp());
assert_eq!(from_utc_result.offset(), with_tz_result.offset());
}When starting from UTC, from_utc and with_timezone produce identical results.
use chrono::{DateTime, TimeZone, Utc, FixedOffset};
fn main() {
// with_timezone can convert between any two timezones
// from_utc only works when the source is UTC
// Create a datetime in Eastern Time
let eastern = FixedOffset::west(5 * 3600);
let eastern_dt: DateTime<FixedOffset> = eastern.ymd(2024, 3, 15).and_hms(10, 0, 0);
// This represents 10:00 AM Eastern = 15:00 UTC
// Convert to Pacific Time (UTC-8)
let pacific = FixedOffset::west(8 * 3600);
let pacific_dt: DateTime<FixedOffset> = eastern_dt.with_timezone(&pacific);
println!("Eastern: {}", eastern_dt); // 10:00
println!("Pacific: {}", pacific_dt); // 07:00 (same instant)
// Both represent the same instant
assert_eq!(eastern_dt.timestamp(), pacific_dt.timestamp());
// from_utc would require first converting to UTC
let utc_dt = eastern_dt.with_timezone(&Utc);
let pacific_via_utc = pacific.from_utc_datetime(&utc_dt.naive_utc());
assert_eq!(pacific_dt, pacific_via_utc);
// with_timezone is more direct for timezone-to-timezone conversion
}with_timezone works between any timezones; from_utc requires UTC as the source.
use chrono::{NaiveDateTime, TimeZone, Utc, FixedOffset, Local};
fn main() {
// A NaiveDateTime has no timezone - it's just a date and time
let naive: NaiveDateTime = NaiveDateTime::parse_from_str(
"2024-03-15 10:00:00",
"%Y-%m-%d %H:%M:%S"
).unwrap();
// from_utc interprets naive as UTC and converts to target timezone
let eastern = FixedOffset::west(5 * 3600);
let from_utc_result = eastern.from_utc_datetime(&naive);
println!("from_utc (as UTC to Eastern): {}", from_utc_result);
// Interprets 10:00 as UTC, shows as 05:00 Eastern
// from_local interprets naive as local time in the target timezone
let from_local_result = eastern.from_local_datetime(&naive).single().unwrap();
println!("from_local (as Eastern time): {}", from_local_result);
// Interprets 10:00 as Eastern, keeps showing as 10:00 Eastern
// These are different instants!
assert_ne!(from_utc_result.timestamp(), from_local_result.timestamp());
// The difference is 5 hours
let diff = from_local_result.timestamp() - from_utc_result.timestamp();
println!("Difference in seconds: {}", diff); // 18000 = 5 hours
}from_utc interprets naive datetime as UTC; from_local interprets it as local to the timezone.
use chrono::{DateTime, NaiveDateTime, TimeZone, Utc, FixedOffset};
fn main() {
// Naive datetime - no timezone information
let naive = NaiveDateTime::parse_from_str(
"2024-06-15 12:00:00",
"%Y-%m-%d %H:%M:%S"
).unwrap();
// from_utc creates a DateTime from a naive UTC datetime
let utc: DateTime<Utc> = Utc.from_utc_datetime(&naive);
println!("UTC: {}", utc);
// This is the primary way to convert naive to aware (when you know it's UTC)
let tokyo = FixedOffset::east(9 * 3600);
let tokyo_dt: DateTime<FixedOffset> = tokyo.from_utc_datetime(&naive);
println!("Tokyo (from UTC): {}", tokyo_dt);
// with_timezone requires a DateTime (already timezone-aware)
// This won't compile with a NaiveDateTime:
// naive.with_timezone(&Utc) // Error: NaiveDateTime has no with_timezone
// DateTime has with_timezone
let back_to_utc = tokyo_dt.with_timezone(&Utc);
println!("Back to UTC: {}", back_to_utc);
}from_utc converts naive to aware; with_timezone converts between aware types.
use chrono::{DateTime, TimeZone, Utc};
use chrono_tz::{Tz, Europe::London, America::New_York};
fn main() {
// Timezones with DST require special handling
// chrono_tz provides timezone database support
// March 2024: DST transition in New York
// Spring forward: 2:00 AM -> 3:00 AM on March 10
// A time that exists in UTC but might be ambiguous/invalid in local
let utc_dt: DateTime<Utc> = Utc.ymd(2024, 3, 10).and_hms(6, 30, 0);
// with_timezone handles DST correctly
let ny_dt = utc_dt.with_timezone(&New_York);
println!("UTC {}: NY time {}", utc_dt, ny_dt);
// Converting to a timezone during DST gap
let spring_forward_utc: DateTime<Utc> = Utc.ymd(2024, 3, 10).and_hms(7, 0, 0);
let ny_spring = spring_forward_utc.with_timezone(&New_York);
println!("Spring forward UTC {}: NY {}", spring_forward_utc, ny_spring);
// London DST transition
let london_dt = utc_dt.with_timezone(&London);
println!("London: {}", london_dt);
// All represent the same instant
assert_eq!(utc_dt.timestamp(), ny_dt.timestamp());
assert_eq!(utc_dt.timestamp(), london_dt.timestamp());
}with_timezone correctly handles DST transitions; the offset varies based on the date.
use chrono::{DateTime, TimeZone, Utc, Local, FixedOffset};
use std::str::FromStr;
fn main() {
// PATTERN 1: Parse UTC string and convert to local
let utc_str = "2024-06-15T14:30:00Z";
let utc_dt: DateTime<Utc> = utc_str.parse().unwrap();
let local_dt: DateTime<Local> = utc_dt.with_timezone(&Local);
println!("UTC {} -> Local {}", utc_dt, local_dt);
// PATTERN 2: Create from Unix timestamp
let timestamp = 1718464200i64;
let from_timestamp = Utc.timestamp(timestamp, 0);
let eastern = FixedOffset::west(5 * 3600);
let eastern_dt = from_timestamp.with_timezone(&eastern);
println!("Timestamp {} -> {}", timestamp, eastern_dt);
// PATTERN 3: Store UTC, display in user's timezone
struct Event {
name: String,
time: DateTime<Utc>,
}
let event = Event {
name: "Meeting".to_string(),
time: Utc.ymd(2024, 6, 15).and_hms(14, 0, 0),
};
fn display_event(event: &Event, tz: &FixedOffset) -> String {
let local_time = event.time.with_timezone(tz);
format!("{} at {}", event.name, local_time)
}
let user_tz = FixedOffset::west(8 * 3600); // Pacific
println!("{}", display_event(&event, &user_tz));
// PATTERN 4: Accept naive datetime from user, interpret as local
let user_input = "2024-06-15 14:30:00";
let naive = chrono::NaiveDateTime::parse_from_str(user_input, "%Y-%m-%d %H:%M:%S").unwrap();
// User meant this as their local time, not UTC
let user_tz = FixedOffset::west(5 * 3600);
let user_dt = user_tz.from_local_datetime(&naive).single().unwrap();
let for_storage: DateTime<Utc> = user_dt.with_timezone(&Utc);
println!("User input {} -> UTC for storage: {}", user_input, for_storage);
}Common patterns: store as UTC, convert for display; or accept local input, convert to UTC.
use chrono::{DateTime, NaiveDateTime, TimeZone, Utc, FixedOffset};
fn main() {
// DateTime<Tz> has with_timezone
let utc_dt: DateTime<Utc> = Utc.ymd(2024, 6, 15).and_hms(12, 0, 0);
let tz = FixedOffset::west(5 * 3600);
let converted = utc_dt.with_timezone(&tz); // Available on DateTime
// TimeZone trait has from_utc_datetime
let naive = utc_dt.naive_utc();
let via_from_utc = tz.from_utc_datetime(&naive); // Available on TimeZone impl
// NaiveDateTime has neither - it's timezone-unaware
// naive.with_timezone(&tz) // Compile error
// tz.from_utc_datetime requires &NaiveDateTime as input
// Date<Tz> also has with_timezone
let utc_date = Utc.ymd(2024, 6, 15);
let tz_date = utc_date.with_timezone(&tz);
println!("Date in timezone: {}", tz_date);
// Summary:
// - DateTime<Tz>::with_timezone(&other_tz) -> DateTime<OtherTz>
// - Tz::from_utc_datetime(&NaiveDateTime) -> DateTime<Tz>
// - NaiveDateTime has no timezone methods
}with_timezone is on DateTime; from_utc_datetime is on TimeZone implementations.
use chrono::{DateTime, TimeZone, Utc, FixedOffset};
fn main() {
// Both methods ultimately do the same calculation:
// 1. Take the UTC timestamp
// 2. Apply the target timezone's offset
let utc_dt: DateTime<Utc> = Utc.ymd(2024, 6, 15).and_hms(12, 0, 0);
let eastern = FixedOffset::west(5 * 3600);
// with_timezone internally:
// - Gets the UTC timestamp from the source DateTime
// - Applies the target timezone's offset
let via_with_tz = utc_dt.with_timezone(&eastern);
// from_utc_datetime internally:
// - Takes the naive datetime as UTC
// - Applies the target timezone's offset
let via_from_utc = eastern.from_utc_datetime(&utc_dt.naive_utc());
// Both compute: local_time = utc_time - offset
// For UTC-5: local = 12:00 - 5:00 = 07:00
println!("with_timezone: {}", via_with_tz); // 2024-06-15 07:00:00 -05:00
println!("from_utc: {}", via_from_utc); // 2024-06-15 07:00:00 -05:00
// The timestamp (instant) is identical
assert_eq!(via_with_tz.timestamp(), via_from_utc.timestamp());
assert_eq!(via_with_tz.timestamp(), utc_dt.timestamp());
// What's stored in DateTime:
// - A NaiveDateTime (the local representation)
// - The offset from UTC
// The timestamp is derived: local_time + offset = UTC timestamp
}Both methods apply offset calculation; the difference is in API ergonomics and use cases.
Method comparison:
| Aspect | from_utc | with_timezone |
|--------|-----------|-----------------|
| Input | NaiveDateTime (interpreted as UTC) | DateTime<Tz> (any timezone) |
| Output | DateTime<Tz> | DateTime<OtherTz> |
| Source | Must be UTC | Can be any timezone |
| Called on | TimeZone impl | DateTime instance |
| Primary use | Convert naive UTC to timezone-aware | Convert between timezones |
When to use from_utc:
NaiveDateTime (from parsing, database, etc.) that represents UTCDateTime from UTC componentsDateTime from external UTC dataWhen to use with_timezone:
DateTime and need to change its timezoneCommon workflow:
// 1. Parse or receive naive datetime (assumed UTC)
let naive = parse_naive_datetime(input);
// 2. Convert to timezone-aware (from_utc)
let utc_dt: DateTime<Utc> = Utc.from_utc_datetime(&naive);
// 3. Store or process in UTC
// 4. Convert for display in user's timezone (with_timezone)
let user_tz = get_user_timezone();
let display_dt = utc_dt.with_timezone(&user_tz);Key insight: from_utc and with_timezone are two sides of the same coināboth compute how an instant in time appears in a given timezone. from_utc is the entry point when you have raw UTC data without timezone information (a NaiveDateTime), creating a timezone-aware DateTime. with_timezone is the transformation function when you already have a DateTime and want to see it in another timezone. The practical implication is that most applications store times in UTC (using from_utc at ingestion) and use with_timezone for display. The naming reflects their purpose: from_utc answers "I have UTC data, create a DateTime in this timezone"; with_timezone answers "I have a DateTime, show me what time it is in that timezone." Internally, both use the same offset calculationāthe difference is purely in how you express intent and what types you're working with.