Working with Time Zones in Rust: A Complete Guide for Backend Developers

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why Time is a Headache

\n\n

In any serious Rust project, whether it's a web server on Actix, a log parser, or a monitoring system, sooner or later the question arises: how to properly work with time zones in Rust. It seems simple enough? Take a timestamp, display it on the screen — and you're done. But reality is harsh: one forgotten time zone turns logs into a mess, and the database starts lying.

\n\n

In this article, we'll explore how the Rust ecosystem solves the time problem. You'll learn why chrono has become the de facto standard, how to keep your sanity with UTC and Local, and how to handle exotic time zones like "Asia/Yekaterinburg" without pain. Let's go!

\n\n

Why Doesn't the Rust Standard Library Cut It?

\n\n

std::time has SystemTime, Instant, and Duration. This is enough for performance measurements and simple timers. But when it comes to working with time zones in Rust, the standard library falls short: it has neither parsing of strings like "2024-03-15T10:30:00+05:00", nor information about time zones, nor conversion from UTC to local time.

\n\n

This is where the chrono crate enters the stage. It's a Swiss Army knife for dates and times in Rust. Let's add it to Cargo.toml:

\n\n
[dependencies]\nchrono = { version = "0.4", features = ["serde"] }
\n\n

The serde flag is needed for serialization/deserialization — useful if you're working with a JSON API.

\n\n

Chrono Basics: UTC, Local, and Naive Time

\n\n

In chrono, there are three main types for representing a point in time:

\n\n
    \n
  • DateTime<Utc> — time in UTC. The gold standard for servers.
  • \n
  • DateTime<Local> — the system's local time. Convenient for desktop logs.
  • \n
  • NaiveDateTime — "naive" time without a time zone. Dangerous, but sometimes necessary.
  • \n
\n\n

Let's see how to get the current time in different zones:

\n\n
use chrono::{Utc, Local, DateTime};\n\nfn main() {\n    let utc_now: DateTime<Utc> = Utc::now();\n    println!("Current time in UTC: {}", utc_now);\n\n    let local_now: DateTime<Local> = Local::now();\n    println!("Current time locally: {}", local_now);\n}
\n\n

Run this code — and you'll see the difference. Note: DateTime is a generic type parameterized by the time zone. This means the compiler won't let you accidentally add UTC and Local time without explicit conversion. Type safety guards your time!

\n\n

Converting Between Time Zones

\n\n

The most common task is converting UTC to the user's local time. Suppose your server stores everything in UTC, and the client is in the Asia/Yekaterinburg time zone (UTC+5). How do you do it?

\n\n

Use the with_timezone method:

\n\n
use chrono::{Utc, Local, TimeZone, DateTime};\n\nfn main() {\n    let utc_time: DateTime<Utc> = Utc::now();\n    \n    // Convert to system local time\n    let local_time: DateTime<Local> = utc_time.with_timezone(&Local);\n    println!("UTC: {} -> Local: {}", utc_time, local_time);\n    \n    // If you need a specific offset — use FixedOffset\n    let ekb_offset = chrono::FixedOffset::east_opt(5 * 3600).unwrap();\n    let ekb_time: DateTime<FixedOffset> = utc_time.with_timezone(&ekb_offset);\n    println!("UTC: {} -> EKB: {}", utc_time, ekb_time);\n}
\n\n

Note: FixedOffset::east_opt returns Option because not every offset is valid (for example, 25 hours is too much). Always handle None.

\n\n

But what if your working with time zones in Rust is more complex than just a fixed offset? For example, do you need to account for daylight saving time? This is where the

Blogs

Book Recommendations