Store every vulnerability timestamp in UTC using an unambiguous format such as RFC 3339, and convert to local time only when displaying. Mixed time zones shift events across day boundaries, which distorts time to remediate, SLA results and daily counts, and they make data from different tools impossible to join cleanly.
What the OSV schema does
The OSV schema is a useful reference. Its modified and published fields are RFC 3339 timestamps in UTC, ending in the letter Z. It also says that when two entries share an identifier, the one with the later modified time is the authoritative one. That second rule matters: it means timestamps are not decoration, they decide which version of a record wins. If your pipeline stores local times without offsets, you can pick the wrong version.
How time zone errors show up
- Day boundary shifts. An event late in the evening in one zone is already tomorrow in another. Daily charts then show findings on different days depending on who built the report.
- Negative durations. A fix time recorded in one zone and a detection time in another can produce a resolution that seems to happen before the detection.
- Daylight saving jumps. A local clock repeats or skips an hour twice a year. Durations computed from local times can be an hour wrong.
- Join failures. Matching events between scanner and ticket system on date strings fails when each uses a different convention.
- Off by one SLA decisions. A deadline defined as end of day can mean different instants in different zones.
Rules that prevent most of it
- Store instants as UTC with an explicit offset marker.
- Never store a date without a time if you also need durations. If only a date is known, store it as a date and mark it as such.
- Keep the original string from the source in a raw field for audit.
- Convert for display at the last step, and show the zone label on the chart.
- Define business day deadlines explicitly, including which zone's calendar applies.
Test cases to run
| Case | What to check |
|---|---|
| Event at 23:30 in one zone, 00:30 in the next day elsewhere | Same instant, same record, one day assigned by the rule |
| Daylight saving change weekend | Durations across the change are correct |
| Scanner reports date only | Stored as date, excluded from hour level metrics |
| Two systems report the same event | Joined on instant, not on string |
Audit your pipeline
Choose twenty findings and compare the timestamp in the source tool, the stored value and the displayed value. Look for shifts of hours or days. Also search for resolved times earlier than detected times, which should never exist and are a quick sign of a mismatch.
Documentation
Write the convention in the metric definitions: "All times are UTC, displayed in UTC unless stated." A single sentence prevents many arguments in review meetings.
Safeguard does this kind of counting in one place: SBOM and dependency scanning, asset discovery and reachability analysis feed the same inventory, so each number can be traced back to its source. Records are stored with consistent event times so intervals between detection and resolution can be computed. You can try a free scan at gold.safeguard.sh/scan.
Quick check
Is a date enough for vulnerability events?
Only for day level metrics. For time to remediate in hours, store a full timestamp.
Where should local time be used?
Only in the display layer, labelled with the zone.
Sources
Last reviewed: 19 October 2026.