Avatar ·

Как получить текущее время в миллисекундах в Rust?

Всем привет! Я только начал изучать Rust и столкнулся с задачей, которая в других языках решается очень просто, а тут вызывает трудности. Мне нужно замерить время выполнения какого-то участка кода, а для этого я хочу получить текущее время в миллисекундах (timestamp с начала эпохи Unix, 1 января 1970 года). Я написал такой код, но он не компилируется: ```rust use std::time; fn main() { let now = time::now(); let millis = now.elapsed().as_millis(); println!("Current time in ms: {}", millis); } ``` Компилятор ругается, что `time::now()` не существует, а метод `elapsed()` вообще не подходит. Я посмотрел документацию, но там куча разных структур: `SystemTime`, `Instant`, `Duration` — я запутался. В Python я бы написал `time.time() * 1000`, в JavaScript — `Date.now()`, а в Rust всё как-то сложно. Пожалуйста, подскажите самый простой и правильный способ получить текущий timestamp в миллисекундах. Желательно с понятным примером, который можно сразу скопировать и вставить. Заранее спасибо! <<>>

Правильное решение: используем std::time::SystemTime

В Rust для получения текущего времени в миллисекундах с эпохи Unix нужно использовать модуль std::time и структуру SystemTime. В отличие от Instant, который предназначен только для измерения интервалов (и не привязан к реальному времени), SystemTime хранит момент времени, связанный с системными часами.

Вот рабочий пример:

use std::time::{SystemTime, UNIX_EPOCH};

fn main() {
    let now = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .expect("System clock is before 1970");
    
    let millis = now.as_millis();
    println!("Текущее время в миллисекундах: {}", millis);
}

Как это работает?

  1. SystemTime::now() — возвращает текущий момент времени, который поддерживается операционной системой.
  2. duration_since(UNIX_EPOCH) — вычисляет разницу между текущим моментом и началом эпохи Unix (1 января 1970 года 00:00:00 UTC). Возвращает Result<Duration, SystemTimeError>.
  3. expect() — обрабатывает ошибку (например, если системные часы установлены на дату до 1970 года, что маловероятно, но Rust требует явной обработки).
  4. as_millis() — метод структуры Duration, возвращающий количество полных миллисекунд как u128.

Более безопасный вариант с обработкой ошибок

Если вы предпочитаете избегать паники, используйте match или unwrap_or:

use std::time::{SystemTime, UNIX_EPOCH};

fn get_unix_millis() -> u128 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap_or(Duration::ZERO)
        .as_millis()
}

fn main() {
    let millis = get_unix_millis();
    println!("{}", millis);
}

Зачем нужен UNIX_EPOCH?

В Rust нет глобальной константы "сейчас". Вместо этого вы явно указываете опорную точку — начало эпохи. Это даёт гибкость: вы можете измерить разницу между любыми двумя моментами, а не только с 1970 года.

Важные замечания

  • Тип возвращаемого значения: as_millis() возвращает u128. Если вам нужен u64 (как в большинстве API), приведите: millis as u64.
  • Точность: Duration может содержать наносекунды, поэтому метод as_millis() отбрасывает остаток. Если нужна дробная часть, используйте as_secs_f64() * 1000.0.
  • Кроссплатформенность: SystemTime работает на Windows, Linux, macOS и других ОС.

Пример с дробными миллисекундами (f64)

use std::time::{SystemTime, UNIX_EPOCH};

fn get_unix_millis_f64() -> f64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_secs_f64() * 1000.0
}

fn main() {
    println!("{:.3}", get_unix_millis_f64()); // например: 1698765432.123
}

Этот способ подходит для высокоточных замеров, где важна дробная часть миллисекунды.

<<>>

Альтернатива: крейт chrono

Если вы работаете с датами и временем в более сложных сценариях (форматирование, часовые пояса, парсинг), рекомендую популярный крейт chrono. Он предоставляет более удобный API, чем стандартная библиотека.

Добавьте в Cargo.toml:

[dependencies]
chrono = "0.4"

Пример получения миллисекунд:

use chrono::Utc;

fn main() {
    let millis = Utc::now().timestamp_millis();
    println!("{}", millis); // i64
}

Метод timestamp_millis() возвращает i64 (а не u128), что удобно для совместимости с базами данных и API. Также chrono поддерживает:

  • Форматирование даты (format("%Y-%m-%d %H:%M:%S"))
  • Работу с часовыми поясами (Local::now())
  • Парсинг строк (NaiveDateTime::parse_from_str)

Для простого замера времени выполнения кода лучше использовать std::time::Instant (он не зависит от системных часов и не может "скакнуть" при корректировке времени), но для получения абсолютного timestamp chrono — отличный выбор.