The quick diagnostic checklist
- Check length: 10=seconds, 13=ms, 16=µs, 19=ns.
- Check digits: numbers only; remove spaces/letters.
- Check range: is the resulting date plausible and 64-bit safe?
- Check timezone: convert in UTC first, then apply target offset.
- Check DST edge: if localizing, use an IANA zone (
America/New_York).
Need to verify right now? Jump to Unix Timestamp Converter or Batch Converter.
Common error types
- Length mismatch: 13-digit treated as seconds → far future date.
- Non-digit characters: hidden spaces, commas, or letters.
- Out-of-range: 32-bit seconds overflow beyond 2038; negatives unsupported in some systems.
- Timezone ambiguity: server local time vs. expected UTC.
- DST shifts: parsing into local time during the missing hour causes failure.
Validation steps (copy-paste)
JAVASCRIPT1// JavaScript: validate & normalize to milliseconds 2export function normalizeEpoch(raw) { 3 const trimmed = raw.trim(); 4 if (!/^[0-9]+$/.test(trimmed)) throw new Error("Digits only"); 5 const len = trimmed.length; 6 if (len === 10) return Number(trimmed) * 1000; 7 if (len === 13) return Number(trimmed); 8 if (len === 16) return Number(trimmed) / 1000; 9 if (len === 19) return Number(trimmed) / 1_000_000; 10 throw new Error("Invalid length"); 11}
PYTHON1# Python: validate & to datetime (UTC) 2from datetime import datetime, timezone 3 4def parse_epoch(raw: str) -> datetime: 5 if not raw.isdigit(): 6 raise ValueError("Digits only") 7 n = len(raw) 8 if n == 10: 9 ts = int(raw) 10 elif n == 13: 11 ts = int(raw) / 1000 12 elif n == 16: 13 ts = int(raw) / 1_000_000 14 elif n == 19: 15 ts = int(raw) / 1_000_000_000 16 else: 17 raise ValueError("Invalid length") 18 return datetime.fromtimestamp(ts, tz=timezone.utc)
SQL1-- SQL (PostgreSQL): validate timestamp length in a table 2SELECT id, ts_raw, 3 CASE 4 WHEN ts_raw ~ '^[0-9]{10}$' THEN 'seconds' 5 WHEN ts_raw ~ '^[0-9]{13}$' THEN 'milliseconds' 6 WHEN ts_raw ~ '^[0-9]{16}$' THEN 'microseconds' 7 WHEN ts_raw ~ '^[0-9]{19}$' THEN 'nanoseconds' 8 ELSE 'invalid' 9 END AS ts_precision 10FROM events 11WHERE ts_raw !~ '^[0-9]{10}$' 12 OR ts_raw::numeric > 32503680000; -- > 3000-01-01 as a sanity bound
Fix templates
- Precision fix: detect length → scale to milliseconds → re-run parsing.
- Trim / sanitize: strip whitespace and commas before regex validation.
- Range guard: cap or discard values outside plausible window (e.g., year
< 2000or> 2100). - Timezone fix: parse as UTC, then format to user’s target offset/zone.
- DST-safe parsing: prefer UTC; if local is required, use IANA zone libraries.
FAQ
- What’s the safest default? Parse as UTC, then format to the requested timezone.
- How do I prevent 2038 issues? Store as 64-bit integers; avoid 32-bit second-based storage.
- How to batch clean data? Use a regex pre-filter + length-based scaling, then pipe into a converter; try Batch Timestamp Converter.