Работа с датами и временем в Rust: полное руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в работу с датами и временем в Rust

Работа с датами и временем — одна из ключевых задач в большинстве современных приложений. Будь то логирование событий, расчёт дедлайнов, обработка временных меток из API или работа с календарём — без качественной библиотеки для работы с временем не обойтись. В экосистеме Rust стандартная библиотека предоставляет лишь базовые возможности (std::time::Instant и std::time::Duration), которые подходят для замера производительности, но не для полноценной работы с календарными датами.

На помощь приходит крейт chrono — де-факто стандарт для работы с датами и временем в Rust. Он предлагает широкий функционал: от создания простых дат до работы с часовыми поясами, форматированием и арифметикой. В этой статье мы подробно разберём основные возможности chrono, приведём практические примеры и покажем, как избежать типичных ошибок.

1. Установка и основные типы chrono

Для начала добавьте зависимость в ваш Cargo.toml:

[dependencies]
chrono = "0.4"

После этого вы можете импортировать необходимые типы. Chrono предлагает три ключевых типа для представления дат и времени:

  • NaiveDate — дата без времени (год, месяц, день).
  • NaiveDateTime — дата и время без учёта часового пояса.
  • DateTime<Tz> — дата и время с привязкой к часовому поясу (например, Utc или Local).

Рассмотрим простейший пример создания этих типов:

use chrono::{NaiveDate, NaiveDateTime, DateTime, Utc, Local};

fn main() {
    // Создаём наивную дату (без времени)
    let date = NaiveDate::from_ymd_opt(2025, 10, 15).unwrap();
    println!("Дата: {}", date);

    // Создаём наивное время (без даты)
    let time = NaiveTime::from_hms_opt(14, 30, 0).unwrap();
    println!("Время: {}", time);

    // Комбинируем в NaiveDateTime
    let naive_dt = NaiveDateTime::new(date, time);
    println!("Наивный datetime: {}", naive_dt);

    // Текущее время в UTC и локальное
    let now_utc: DateTime<Utc> = Utc::now();
    let now_local: DateTime<Local> = Local::now();
    println!("Сейчас UTC: {}", now_utc);
    println!("Сейчас локальное: {}", now_local);
}

Обратите внимание на использование from_ymd_opt и from_hms_opt — они возвращают Option, что защищает от создания невалидных дат (например, 32 января).

2. Форматирование и парсинг дат

Chrono использует мощную систему форматирования на основе спецификаторов, очень похожую на strftime из C/PHP. Это позволяет гибко преобразовывать даты в строки и обратно.

2.1 Форматирование даты в строку

use chrono::{Utc, DateTime};

fn main() {
    let now: DateTime<Utc> = Utc::now();
    
    // Стандартный ISO 8601
    println!("ISO: {}", now.to_rfc3339());
    
    // Кастомный формат
    println!("Кастом: {}", now.format("%Y-%m-%d %H:%M:%S"));
    println!("День недели: {}", now.format("%A"));
    println!("Месяц: {}", now.format("%B"));
    println!("Год-месяц-день: {}", now.format("%d.%m.%Y"));
}

Основные спецификаторы форматирования:

  • %Y — год (4 цифры)
  • %m — месяц (01-12)
  • %d — день месяца (01-31)
  • %H — часы (00-23)
  • %M — минуты (00-59)
  • %S — секунды (00-60)
  • %A — полное название дня недели
  • %B — полное название месяца

2.2 Парсинг строки в дату

Для обратного преобразования используется метод parse_from_str:

use chrono::{NaiveDateTime, DateTime, Utc, format::ParseResult};

fn main() {
    // Парсинг наивного datetime
    let date_str = "2025-10-15 14:30:00";
    let naive = NaiveDateTime::parse_from_str(date_str, "%Y-%m-%d %H:%M:%S");
    match naive {
        Ok(dt) => println!("Распарсено: {}", dt),
        Err(e) => eprintln!("Ошибка парсинга: {}", e),
    }

    // Парсинг с часовым поясом
    let rfc_str = "2025-10-15T14:30:00+03:00";
    let dt_with_tz = DateTime::parse_from_rfc3339(rfc_str);
    println!("С часовым поясом: {:?}", dt_with_tz);

    // Преобразование в UTC
    if let Ok(dt) = dt_with_tz {
        let utc_dt = dt.with_timezone(&Utc);
        println!("В UTC: {}", utc_dt);
    }
}

Важно: при парсинге всегда обрабатывайте ошибки через match или unwrap_or_else, так как пользовательский ввод может быть некорректным.

3. Арифметика с датами и временем

Chrono поддерживает сложение и вычитание с помощью Duration (из стандартной библиотеки) и собственного TimeDelta. Это позволяет легко выполнять операции вроде "добавить 3 дня" или "вычесть 2 часа".

use chrono::{NaiveDate, Duration, TimeDelta};

fn main() {
    let start = NaiveDate::from_ymd_opt(2025, 10, 15).unwrap();
    
    // Добавляем дни
    let plus_10_days = start + Duration::days(10);
    println!("Через 10 дней: {}", plus_10_days);
    
    // Вычитаем недели
    let minus_2_weeks = start - Duration::weeks(2);
    println!("2 недели назад: {}", minus_2_weeks);
    
    // Используем TimeDelta (более гибко)
    let delta = TimeDelta::try_days(30).unwrap();
    let plus_month = start + delta;
    println!("Через 30 дней: {}", plus_month);
    
    // Разница между датами
    let end = NaiveDate::from_ymd_opt(                

Блоги

Рекомендаций по книгам