Guides

Invalid Timestamp: Quick Diagnostics and Fixes

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)

// JavaScript: validate & normalize to milliseconds
export function normalizeEpoch(raw) {
  const trimmed = raw.trim();
  if (!/^[0-9]+$/.test(trimmed)) throw new Error("Digits only");
  const len = trimmed.length;
  if (len === 10) return Number(trimmed) * 1000;
  if (len === 13) return Number(trimmed);
  if (len === 16) return Number(trimmed) / 1000;
  if (len === 19) return Number(trimmed) / 1_000_000;
  throw new Error("Invalid length");
}
# Python: validate & to datetime (UTC)
from datetime import datetime, timezone

def parse_epoch(raw: str) -> datetime:
    if not raw.isdigit():
        raise ValueError("Digits only")
    n = len(raw)
    if n == 10:
        ts = int(raw)
    elif n == 13:
        ts = int(raw) / 1000
    elif n == 16:
        ts = int(raw) / 1_000_000
    elif n == 19:
        ts = int(raw) / 1_000_000_000
    else:
        raise ValueError("Invalid length")
    return datetime.fromtimestamp(ts, tz=timezone.utc)
-- SQL (PostgreSQL): validate timestamp length in a table
SELECT id, ts_raw,
       CASE
         WHEN ts_raw ~ '^[0-9]{10}$' THEN 'seconds'
         WHEN ts_raw ~ '^[0-9]{13}$' THEN 'milliseconds'
         WHEN ts_raw ~ '^[0-9]{16}$' THEN 'microseconds'
         WHEN ts_raw ~ '^[0-9]{19}$' THEN 'nanoseconds'
         ELSE 'invalid'
       END AS ts_precision
FROM events
WHERE ts_raw !~ '^[0-9]{10}$'
   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 < 2000 or > 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.

Related tools and guides