GitoxideLabs/gitoxide · error
Could not convert date to a point in time
Error message
Could not convert date to a point in time
What it means
The final step of `Fields::normalize()` converts the normalized civil datetime plus time into a `Zoned` point in time using the configured timezone; if jiff cannot perform that conversion (e.g. ambiguity/timezone resolution failure), the code raises Error 'Could not convert date to a point in time'. This indicates the calendar date is valid but cannot be anchored to a concrete instant.
Solutions
- Ensure a valid timezone is configured (valid TZ environment/database entry) or pass an explicit known-good `TimeZone`
- Catch the Error and retry with UTC as a fallback timezone
- Verify the gix-date/jiff timezone database feature is enabled in your build
Example fix
// before
parse_relative("2 weeks ago", None) // relies on ambient TZ
// after
parse_relative("2 weeks ago", Some(TimeZone::UTC)) Defensive patterns
Strategy: fallback
Validate before calling
let tz = gix_date::time::TimeZone::from_env().unwrap_or(TimeZone::UTC);
Try / catch
let zoned = fields.normalize().or_else(|_| normalize_in_utc());
Prevention
- Always configure a valid timezone or default to UTC
- Ensure the timezone database is available in your deployment (e.g. feature flags for jiff tz data)
- Avoid relying on ambient TZ in containers/minimal images
When it happens
Trigger: Relative-date parsing where `to_zoned(timezone)` fails for the computed date/time in the given timezone — e.g. a timezone whose database lookup fails or a local time that cannot be resolved at that date.
Common situations: Systems with missing/invalid TZ settings, or relative dates near timezone-boundary edge cases when gix-date is used to compute '3 weeks ago'-style timestamps.
Related errors
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/5b04812c6f1dc563.
Report an issue: GitHub.
Appendix: source
Thrown at gix-date/src/parse/relative.rs:177
time: zdt.time(),
timezone: zdt.time_zone().clone(),
}
}
}
impl Fields {
/// Turn the fields back into a point in time: a day beyond the end of the month rolls over into the
/// following month. One month before May 31st is thus May 1st, a day after April 30th.
fn normalize(&self) -> Result<Zoned, Exn<Error>> {
let first_of_month = civil::Date::new(self.year, self.month, 1)
.or_raise(|| Error::new(format!("Date lies out of range: {}-{:02}", self.year, self.month)))?;
let days_beyond_first = SignedDuration::from_secs((i64::from(self.day) - 1) * 24 * 60 * 60);
first_of_month
.checked_add(days_beyond_first)
.or_raise(|| Error::new(format!("Day {} lies out of range", self.day)))?
.to_datetime(self.time)
.to_zoned(self.timezone.clone())
.or_raise(|| Error::new("Could not convert date to a point in time"))
}
}
let now = now.ok_or(ValidationError::new("Missing current time"))?;
let mut fields = Fields::from(now);
for Pair { period, count, unit } in pairs {
let err = || Error::new(format!("Couldn't parse span from '{period} {count}'"));
match unit {
Unit::Seconds(factor) => {
let seconds = count
.checked_mul(*factor)
.map(SignedDuration::from_secs)
.ok_or_else(err)?;
let ts = fields.normalize()?.timestamp().checked_sub(seconds).or_raise(err)?;
fields = ts.to_zoned(fields.timezone.clone()).into();
}
Unit::Months(factor) => {
let months = count.checked_mul(*factor).ok_or_else(err)?;View on GitHub (pinned to e73179060b)