clockworklabs/SpacetimeDB · error
SystemTime predates the Unix epoch
Error message
SystemTime predates the Unix epoch
What it means
`Timestamp::from_system_time` calls `system_time.duration_since(SystemTime::UNIX_EPOCH).expect("SystemTime predates the Unix epoch")`, so converting any SystemTime earlier than 1970-01-01 panics — even though Timestamp itself can represent pre-epoch times via signed micros. The trigger is a clock reading before 1970 or code that computes UNIX_EPOCH minus a duration.
Source
Thrown at crates/sats/src/timestamp.rs:110
Ok(positive) => SystemTime::UNIX_EPOCH
.checked_add(positive)
.expect("Timestamp with i64 microseconds since Unix epoch overflows SystemTime"),
Err(negative) => SystemTime::UNIX_EPOCH
.checked_sub(negative)
.expect("Timestamp with i64 microseconds before Unix epoch overflows SystemTime"),
}
}
/// Convert a [`SystemTime`] into a [`Timestamp`] which refers to approximately the same point in time.
///
/// This conversion may panic if `system_time` is out of bounds for [`Duration`].
/// [`SystemTime`]'s range is larger than [`Timestamp`] on both Unix and Windows targets,
/// so times in the far past or far future may panic.
/// [`Timestamp`]'s range is approximately 292 years before and after the Unix epoch.
pub fn from_system_time(system_time: SystemTime) -> Self {
let duration = system_time
.duration_since(SystemTime::UNIX_EPOCH)
.expect("SystemTime predates the Unix epoch");
Self::from_duration_since_unix_epoch(duration)
}
/// Returns the [`Duration`] delta between `self` and `earlier`, if `earlier` predates `self`.
///
/// Returns `None` if `earlier` is strictly greater than `self`,
/// or if the difference between `earlier` and `self` overflows an `i64`.
pub fn duration_since(self, earlier: Timestamp) -> Option<Duration> {
self.time_duration_since(earlier)?.to_duration().ok()
}
/// Returns the [`TimeDuration`] delta between `self` and `earlier`.
///
/// The result may be negative if `earlier` is actually later than `self`.
///
/// Returns `None` if the subtraction overflows or underflows `i64` microseconds.
pub fn time_duration_since(self, earlier: Timestamp) -> Option<TimeDuration> {
let delta = selfView on GitHub (pinned to 524b4487d9)
Solutions
- Handle pre-epoch times explicitly: match on duration_since's Err and build `Timestamp::from_micros_since_unix_epoch(-micros)` instead of converting via from_system_time.
- Fix the host clock (NTP/systemd-timesyncd) if it genuinely reads before 1970.
- Avoid computing UNIX_EPOCH - dur and feeding the result to from_system_time.
Example fix
// before: panics because the value predates the epoch
let ts = Timestamp::from_system_time(SystemTime::UNIX_EPOCH - Duration::from_secs(60));
// after: construct pre-epoch values from signed micros
let ts = match SystemTime::UNIX_EPOCH.checked_sub(Duration::from_secs(60)) {
Some(t) if t >= SystemTime::UNIX_EPOCH => Timestamp::from_system_time(t),
_ => Timestamp::from_micros_since_unix_epoch(-60_000_000),
}; Defensive patterns
Strategy: validation
Validate before calling
if system_time >= SystemTime::UNIX_EPOCH {
let ts = Timestamp::from_system_time(system_time);
} else {
// build from signed micros: Timestamp::from_micros_since_unix_epoch(-micros)
} Prevention
- Match on duration_since's Result instead of expecting Ok.
- Keep host clocks NTP-synced, especially VMs and boards with RTC batteries.
- In tests, construct pre-epoch values from signed micros rather than subtracting from UNIX_EPOCH.
When it happens
Trigger: Passing `SystemTime::UNIX_EPOCH - Duration::from_secs(...)` (e.g. tests simulating past dates), or a machine clock erroneously set pre-1970 (dead RTC battery, unsynced VM), into from_system_time.
Common situations: Unit tests of date logic that subtract from the epoch; VMs or embedded boards with dead/unsynchronized RTCs; accidental negative durations in time math.
Related errors
- Duration since Unix epoch overflows i64 microseconds
- timestamp before unix epoch
- Duration overflows i64 microseconds
- Timestamp with i64 microseconds since Unix epoch overflows S
- Timestamp with i64 microseconds before Unix epoch overflows
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/ca5553d8cb753647.
Report an issue: GitHub.