Как перейти от NaiveDate к определенному часовому поясу с помощью Chrono?

Я анализирую дату и время в Rust с помощью chrono crate. Дата и время взяты с веб-сайта, на котором дата и время взяты из разных разделов страницы.

Дата отображается в формате %d/%m/%Y (пример: 27.08.2018). Время отображается только с часами (например: 12, 10, 21 и т. Д.)

Я хочу сохранить эти даты в формате UTC, чтобы я мог вычислить время, оставшееся до заданной даты и времени с этого момента, без привязки к часовому поясу. Я знаю, в каком часовом поясе эти даты (время Парижа).

Я создал NaiveDate из ввода даты (эта работа еще не завершена, поэтому обработки ошибок пока нет):

let naive_date = NaiveDate::parse_from_str(date, "%d/%m/%Y").unwrap()

С этого момента, как лучше всего получить UTC DateTime, учитывая, что у меня есть строка с часом?

Я запутался в различных _5 _ / _ 6_ чертах и ​​не знаю, следует ли мне использовать Local или FixedOffset, а затем конвертировать в Utc.


person Justmaker    schedule 13.05.2018    source источник
comment
Дата отображается в следующем формате:% d /% m /% Y (пример: 27.08.2018). Время всего час (12, 10, 21 и т.д.), где часы 27.08.2018?   -  person Stargateur    schedule 13.05.2018
comment
Я получаю час в другом элементе. Итак, я анализирую две строки, одну для получения даты, другую для получения часа. Я хотел бы избежать создания поддельной строки даты и времени и указать, из какого часового пояса находится дата и время.   -  person Justmaker    schedule 13.05.2018
comment
Я замечаю несогласованность. Все экземпляры даты и времени находятся в одном часовом поясе или нет? Пожалуйста, обновите вопрос вместо того, чтобы оставлять полезную информацию в комментариях.   -  person E_net4 the curator    schedule 13.05.2018
comment
Ваш вопрос не имеет смысла, NaiveDate уже без часового пояса, это первое, что пишут в документе. naive_date.and_hms(hour, 0, 0); ????   -  person Stargateur    schedule 13.05.2018
comment
Думаю, я понял вопрос. У вас есть время и дата, которые наивны - к ним не привязаны часовые пояса. Но вы действительно знаете, что часовой пояс, например, +0100. Теперь вы хотите создать DateTime<Utc>, правильно настроенный для часового пояса. Это примерно так?   -  person Peter Hall    schedule 13.05.2018
comment
@PeterHall точно   -  person Justmaker    schedule 13.05.2018
comment
@Stargateur Я имел в виду, что хочу иметь дату и время с часовым поясом, но с поправкой на UTC. Так, например, скажем, мой элемент даты - 27/08/2018, а элемент часа - 12. Я знаю, что часовой пояс - Париж (в настоящее время UTC + 2). Итак, я хочу создать DateTime ‹Utc› из этой информации. Извините, если это было непонятно ...   -  person Justmaker    schedule 13.05.2018


Ответы (3)


Документацию Chrono, вероятно, можно было бы улучшить, чтобы упростить поиск, как это сделать.

Предполагая, что это ваша отправная точка:

use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};

// The date you parsed
let date = NaiveDate::from_ymd(2018, 5, 13);
// The known 1 hour time offset in seconds
let tz_offset = FixedOffset::east(1 * 3600);
// The known time
let time = NaiveTime::from_hms(17, 0, 0);
// Naive date time, with no time zone information
let datetime = NaiveDateTime::new(date, time);

Затем вы можете использовать FixedOffset для создания DateTime:

let dt_with_tz: DateTime<FixedOffset> = tz_offset.from_local_datetime(&datetime).unwrap();

Если вам нужно преобразовать его в DateTime<Utc>, вы можете сделать это:

let dt_with_tz_utc: DateTime<Utc> = Utc.from_utc_datetime(&dt_with_tz.naive_utc());
person Peter Hall    schedule 13.05.2018
comment
Тогда это именно то, что мне нужно, большое спасибо за ответ. - person Justmaker; 13.05.2018
comment
Для информации, использование chrono-tz намного удобнее: pub fn create_date_time_from_paris (date: NaiveDate, time: NaiveTime) - ›DateTime ‹Utc› {let naive_datetime = NaiveDateTime :: new (дата, время); let paris_time = Paris.from_local_datetime (& naive_datetime) .unwrap (); paris_time.with_timezone (& Utc)} - person Justmaker; 14.05.2018
comment
@Justmaker Спасибо, я тоже кое-что узнал. Изучив документацию chrono-tz, я понял, что вы можете сделать то же самое с FixedOffset, который у вас уже был. Я обновил свой ответ этим, так как это намного лучше, чем вычитание смещений. - person Peter Hall; 14.05.2018
comment
Да, но тогда вам нужно будет вручную выполнять переход на летнее время, тогда как chrono-tz сделает это за вас;) - person Justmaker; 14.05.2018
comment
@Justmaker Это зависит от того, какая информация у вас есть. Если вы знаете, что текущий часовой пояс - UTC + 0100, тогда все в порядке. Если вы знаете, что находитесь в Париже, то chrono-tz кажется лучше. Я все еще не уверен, как вы можете гарантировать выбор правильного часового пояса для произвольного города? - person Peter Hall; 14.05.2018
comment
В моем случае использования мне не нужно об этом беспокоиться, даты, как известно, из Парижа. Меня больше всего беспокоит сравнение даты и времени пользователя (который может быть где угодно) с парижским. Я не думаю, что для выбора правильного часового пояса для произвольного города это можно сделать, не имея информации. Вы бы положились на свой фронт или другие средства, чтобы дать вам дату, время и часовой пояс. - person Justmaker; 14.05.2018

Я открыл для себя chrono-tz, и пользоваться им стало намного проще. Например:

pub fn create_date_time_from_paris(date: NaiveDate, time: NaiveTime) -> DateTime<Utc> {
    let naive_datetime = NaiveDateTime::new(date, time);
    let paris_time = Paris.from_local_datetime(&naive_datetime).unwrap();
    paris_time.with_timezone(&Utc)
}
person Justmaker    schedule 15.05.2018

Дата и время взяты с веб-сайта, на котором дата и время взяты из разных разделов страницы.

Вот пример того, как можно постепенно анализировать несколько значений из отдельных строк, предоставлять значения по умолчанию для неанализируемой информации и использовать встроенное преобразование часового пояса Chrono.

Ключ заключается в использовании функции parse для обновления структура Parsed. Для продолжения можно использовать итератор StrftimeItems использовать более читаемые строки формата.

extern crate chrono;

use chrono::prelude::*;

fn example(date: &str, hour: &str) -> chrono::ParseResult<DateTime<Utc>> {
    use chrono::format::{self, strftime::StrftimeItems, Parsed};

    // Set up a struct to perform successive parsing into
    let mut p = Parsed::default();

    // Parse the date information
    format::parse(&mut p, date.trim(), StrftimeItems::new("%d/%m/%Y"))?;
    // Parse the time information and provide default values we don't parse
    format::parse(&mut p, hour.trim(), StrftimeItems::new("%H"))?;
    p.minute = Some(0);
    p.second = Some(0);

    // Convert parsed information into a DateTime in the Paris timezone
    let paris_time_zone_offset = FixedOffset::east(1 * 3600);
    let dt = p.to_datetime_with_timezone(&paris_time_zone_offset)?;

    // You can also use chrono-tz instead of hardcoding it
    // let dt = p.to_datetime_with_timezone(&chrono_tz::Europe::Paris)?;

    // Convert to UTC
    Ok(dt.with_timezone(&Utc))
}

fn main() {
    let date = "27/08/2018";
    let hour = "12";

    println!("dt = {:?}", example(date, hour)); // Ok(2018-08-27T11:00:00Z)
}
person Shepmaster    schedule 13.05.2018
comment
Может быть p.offset = Some(1 * 3600); или format::parse(&mut p, timezone.trim(), StrftimeItems::new("%z"))?; - person Stargateur; 14.05.2018