RTC hardware and the limits of older clocks¶
Timestamps are only as good as the clock that produced them. On older machines that clock was a small battery-backed chip with a 2-digit year, a coarse periodic tick, and no network discipline. Understanding it explains a whole class of forensic artifacts — implausible floor dates, quantized sub-second times, and timezone-blind local stamps.
The CMOS real-time clock — Motorola MC146818¶
The IBM PC/AT (1984) introduced a battery-backed real-time clock plus low-power CMOS
RAM on one chip, the Motorola MC146818A (and compatibles), accessed via I/O ports
0x70 (index) / 0x71 (data). Its registers hold the wall clock to 1-second
resolution:
| Offset | Field | Range |
|---|---|---|
0x00 |
Seconds | 0–59 |
0x02 |
Minutes | 0–59 |
0x04 |
Hours | 0–23 (or 1–12 + PM bit) |
0x07 |
Day of month | 1–31 |
0x08 |
Month | 1–12 |
0x09 |
Year | 0–99 (two digits) |
0x32 |
Century (if present) | non-standard |
0x0A |
Status A | bit 7 = update-in-progress |
0x0B |
Status B | bit 1 = 24h, bit 2 = binary (else BCD) |
Values are BCD unless Status B bit 2 is set; the oscillator is the canonical 32.768 kHz crystal, updating once per second. Source: OSDev CMOS and OSDev RTC (the live wiki blocks automated fetches; these are verified archive snapshots).
The 2-digit year (a structural Y2K problem)
The on-chip year is two digits, and originally there was no century
register. Manufacturers later added one (commonly at 0x32) but, in the words of
the OSDev reference, "there was no official standard … different manufacturers used
different registers"; ACPI's FADT later added a pointer naming which register holds
the century (0 = none). So a CMOS-sourced date's century is, on pre-ACPI hardware, a
BIOS/OS guess (typically "year ≥ 90 → 19YY, else 20YY"). See Y2K.
There is also an update-in-progress hazard: reading the registers mid-update can
return inconsistent values (e.g. 8:60), so software must poll Status A bit 7 first.
The weekday register is, per the same reference, "entirely unreliable."
The 18.2 Hz PC timer tick¶
MS-DOS did not read the RTC for time-of-day; it counted ticks from the 8253/8254 Programmable Interval Timer (PIT). The PIT runs at ~1.193182 MHz (the 14.31818 MHz master oscillator ÷ 12). With the BIOS default reload value of 65 536, channel 0 fires IRQ0 at:
Source: OSDev PIT.
DOS sub-second times are quantized
MS-DOS wall-clock time read from the BIOS tick counter is quantized to ~54.925 ms — a DOS-era fractional second can take only ~18 discrete values. Any finer "precision" in a DOS timestamp is not real. (This is why FAT settled on a coarse 2-second write granularity.)
The MS-DOS 1980 epoch¶
FAT/DOS dates encode the year as a 7-bit "offset from 1980" (0–127 → 1980–2107), so the minimum representable FAT date is 1980-01-01 and any earlier date is structurally impossible. Source: DosDateTimeToFileTime, exFAT specification. See the FAT/DOS format reference.
Clock resets, drift, and the absence of NTP¶
A dead CMOS battery loses the clock; on next boot the firmware re-seeds from an invalid or floor value. Common "reset" sinks seen in evidence:
- 1980-01-01 — the FAT/DOS floor (most common on DOS/FAT systems).
- 1970-01-01 — the Unix epoch floor.
- a hardcoded BIOS default / manufacture date (often the BIOS build year).
A cluster of floor dates means a reset clock, not activity
A group of files all stamped at a single implausible floor date — especially with identical times — is a strong indicator of a dead CMOS battery or cleared NVRAM, not of genuine user activity. Treat such timestamps as "clock-was-reset" markers.
Older machines also had no NTP: the RTC ran free, drifting fast or slow, corrected only by manual setting. Pre-NTP network protocols were crude — the TIME protocol (RFC 868) returns a 32-bit count of seconds since 1900 and rolls over in 2036. And DOS/FAT store local wall-clock time with no timezone or DST tag, so those timestamps cannot be converted to UTC without independent knowledge of the machine's then-current locale. Dual-booting two OSes that both DST-adjust the RTC can corrupt it further. Source: OSDev Time And Date.
Modern Unix: hardware clock vs. system clock¶
Linux separates the battery-backed hardware clock (RTC) from the kernel's
system clock. hwclock(8)
reads or sets the RTC (--hctosys, --systohc), applies a stored drift factor from
/etc/adjtime (--adjust), and notes the kernel's "11-minute mode": when NTP
discipline is active the kernel silently copies system time back into the RTC roughly
every 11 minutes.
Forensic leverage
On an NTP-disciplined Linux box the RTC reflects recently disciplined time, not the
last manual set. Meanwhile /etc/adjtime records the historical drift factor and the
last-set timestamp — which can corroborate or contradict a claim about how the clock
behaved.
See also¶
- Precision — sub-second resolution in general.
- Epoch rollovers — Y2K, the 2036 (NTP/TIME) rollover, and Year 2106.
- Formats: Windows — FAT/DOS.