考虑程序的以下输入:
18:00
Europe/London
(或时区的任何合理表示,可能的示例包括 Europe__London
、Europe.London
等...请参阅注释)chrono::Utc::now()
中去掉日期字段来获得。是否可以将这些数据或类似的数据组合成一个
chrono::Datetime
对象?
注意:字符串的具体形式并不是特别重要,可以改变。该数据仅来自文本文件。
我认为可能有两种可能的方法。
format!
构造 rfc3339 格式的字符串表示形式,然后使用 datetime parse_from_rfc3339
函数对其进行解析。这似乎是错误的方法 - 创建更大的字符串然后解析它们感觉像是一种低效或“笨拙”的方法。不过好像比较容易做到。可以使用 rfc3339 格式的字符串构造
chrono::DateTime
对象。以下是如何做到这一点:
let datetime_rfc3339_format_string =
format!("{}T{}-{}",
date_string, time_string, timezone_string);
let datetime_remote = chrono::DateTime::parse_from_rfc3339(datetime_remote_rfc3339_format);
问题就变成了如何以字符串格式构建这三个组件。
我之前设法想出了一种从字符串构造
chrono_tz::Tz
对象的方法。请参阅以下链接问题。
let chrono_timezone = Tz::from_str(timezone.as_str())
.expect("failed to convert string to chrono tz");
这是可行的,假设字符串的格式如下:
Europe/London
但是为了使用 rfc3339 格式的内容,我们需要将这个“时区名称”转换为“小时数偏移”。这既取决于全球日期日期,也取决于夏令时等当地规则。
所以我在这里陷入困境。我不知道如何将
Tz
对象转换为以小时为单位的偏移量,这原则上取决于当前日期。
这部分比较简单。我们可以从
Utc::now()
构建一个 DateTime 对象,并使用 date_naive()
提取日期。然后可以将其格式化为字符串。
let datetime = chrono::Utc::now();
let date = datetime.date_naive();
let string_date = format!("{}", date);
我已经有了所需(字符串)格式的这些。例如,我可以从文本文件中读取这些内容,它们的格式例如:
08:00
由于我已经有一个时区对象,所以我的想法是可以使用它直接构造一个 DateTime 对象。看起来
FixedOffset
类型有 with_ymd_and_hms
功能。
这表明可以通过某种方式从 Timezone 对象构造 DateTime 对象,并使用我可以访问的附加信息。
但是,这就是我陷入困境的地方。我不知道如何继续这里,或者即使
FixedOffset
是我想要使用的类型。我不知道它与Tz
有什么关系,如果有的话。
let chrono_timezone = Tz::from_str(timezone.as_str())
.expect("failed to convert string to chrono tz");
这个答案演示了选项 1 的解决方案:
使用这个问题中提供的信息,我们可以解决如何将时区转换为偏移量的问题,然后将其转换为所需的字符串格式。
fn get_todays_offset(tz: chrono_tz::Tz) -> chrono::Duration {
let now = chrono::Utc::now().naive_utc();
let offset = tz.offset_from_utc_datetime(&now);
offset.base_utc_offset() + offset.dst_offset()
}
fn get_todays_offset_as_hh_mm(tz: chrono_tz::Tz) -> String {
let todays_offset = get_todays_offset(tz);
let todays_offset_sign = todays_offset.num_nanoseconds().unwrap().signum();
let todays_offset_hours = todays_offset.num_hours();
let todays_offset_minutes = todays_offset.num_minutes() % 60;
let mut todays_offset_hh_mm_string = format!("{:02}:{:02}", todays_offset_hours, todays_offset_minutes);
if todays_offset_sign >= 0 {
todays_offset_hh_mm_string = format!("+{}", todays_offset_hh_mm_string);
}
else {
todays_offset_hh_mm_string = format!("-{}", todays_offset_hh_mm_string);
}
return todays_offset_hh_mm_string;
}
由此,我们可以构造 rfc3339 字符串。
let timezone_string = get_todays_offset_as_hh_mm(tz);
let datetime_rfc3339_format =
format!("{}T{}-{}",
date_string, time_string, timezone_string);
let datetime =
chrono::DateTime::parse_from_rfc3339(
datetime_remote_rfc3339_format.as_str())
.expect("rfc3339 parse failed");