in below/common/src/dateutil.rs [284:360]
fn parse_absolute(date: &str, default_date: fn(char) -> &'static str) -> Option<Self> {
let date = date.trim();
// Hg internal format. "unixtime offset"
let parts: Vec<_> = date.split(" ").collect();
if parts.len() == 2 {
if let Ok(unixtime) = parts[0].parse() {
if let Ok(offset) = parts[1].parse() {
if is_valid_offset(offset) {
return Some(Self { unixtime, offset });
}
}
}
}
// Normalize UTC timezone name to +0000. The parser does not know
// timezone names.
let date = if date.ends_with("GMT") || date.ends_with("UTC") {
format!("{} +0000", &date[..date.len() - 3])
} else {
date.to_string()
};
let mut now = None; // cached, lazily calculated "now"
// Try all formats!
for naive_format in DEFAULT_FORMATS.iter() {
// Fill out default fields. See mercurial.util.strdate.
// This makes it possible to parse partial dates like "month/day",
// or "hour:minute", since the missing fields will be filled.
let mut default_format = String::new();
let mut date_with_defaults = date.clone();
let mut use_now = false;
for part in ["S", "M", "HI", "d", "mb", "Yy"] {
if part
.chars()
.any(|ch| naive_format.contains(&format!("%{}", ch)))
{
// For example, if the user specified "d" (day), but
// not other things, we should use 0 for "H:M:S", and
// "now" for "Y-m" (year, month).
use_now = true;
} else {
let format_char = part.chars().nth(0).unwrap();
default_format += &format!(" @%{}", format_char);
if use_now {
// For example, if the user only specified "month/day",
// then we should use the current "year", instead of
// year 0.
let now = now.get_or_insert_with(|| Local::now());
date_with_defaults +=
&format!(" @{}", now.format(&format!("%{}", format_char)));
} else {
// For example, if the user only specified
// "hour:minute", then we should use "second 0", instead
// of the current second.
date_with_defaults += " @";
date_with_defaults += default_date(format_char);
}
}
}
// Try parse with timezone.
// See https://docs.rs/chrono/0.4.9/chrono/format/strftime/index.html#specifiers
let format = format!("{}%#z{}", naive_format, default_format);
if let Ok(parsed) = DateTime::parse_from_str(&date_with_defaults, &format) {
return Some(parsed.into());
}
// Without timezone.
let format = format!("{}{}", naive_format, default_format);
if let Ok(parsed) = NaiveDateTime::parse_from_str(&date_with_defaults, &format) {
return Some(parsed.into());
}
}
None
}