Date & Time Formats Reference

Date and time formats reference: standard formats like Unix timestamp, ISO 8601, RFC 3339, RFC 2822 and common display patterns with meaning and examples.

Practical Notes

  • A Unix timestamp is UTC, "the current timezone" is notThe timestamp itself has no timezone; timezone only matters when formatting. Storing timestamps and rendering per local timezone is correct — storing local wall-clock time as if it were a timestamp produces multi-hour drift across regions.
  • The Z or +08:00 suffix in ISO 8601 is not optionalWithout an offset, 2026-10-01T12:00:00 is interpreted in each runtime local timezone, so one string means different instants. APIs should always emit a full form with Z or an explicit offset.
  • MySQL DATETIME stores no timezone; TIMESTAMP convertsDATETIME is written and read verbatim, while TIMESTAMP is converted to UTC on write and back on read using the session timezone. The same row shows different values on connections with different session timezones, so decide this semantic up front.

Data Sources

  • ISO 8601-1:2019
  • RFC 3339
  • RFC 5322 (Internet message date)
  • RFC 9557 (IXDTF)

Codes, names and definitions above come from public specifications; we claim no originality over the specification data itself. The arrangement, Chinese annotations and practical notes on this page are written by us.

How It Works

Time representation has two layers: the "absolute instant" — a unique point on the timeline (e.g. Unix timestamp 1693564800) independent of display — and the "display format", a human-readable writing affected by locale, calendar and timezone. The same instant renders differently across regions, so store the absolute instant plus timezone and format for display per user locale.

Formats originate differently: the Unix timestamp counts seconds/ms since 1970-01-01 UTC and is best for computation; ISO 8601 / RFC 3339 are human-readable yet machine-unambiguous standards ideal for APIs and logs; RFC 2822 is common in email and HTTP headers. When mixing them, always confirm the unit (seconds vs ms) and timezone, or you get a 1000x error or a wrong-zone offset.

When to Use This Table

This table is for choosing a time format for APIs, logs or storage. It lines up Unix timestamps, ISO 8601, RFC 3339, RFC 2822, SQL formats and localised formats with their readability, timezone handling and appropriate use.

When not to consult it: you are handling the business semantics of timezone conversion, or cross-timezone scheduling and calendar arithmetic. A format is only a representation — which three o clock the user meant is a business rule the table cannot answer.

Rule of thumb: pick by use. Machine-to-machine transport and storage use ISO 8601 or Unix timestamps; human-facing logs and interfaces use readable formats; HTTP headers must use the IMF-fixdate defined by RFC 7231. Never invent a custom format — a hand-rolled YYYY-MM-DD HH:mm causes trouble across timezones and platforms.

Mind three pitfalls of Unix timestamps: whether they are seconds or milliseconds is inconsistent across stacks (JavaScript Date.now() is milliseconds, databases often use seconds), they carry no timezone and are conventionally UTC yet often treated as local time, and the 2038 problem still exists on 32-bit systems.

Boundaries and Common Pitfalls

  • Mixing seconds with milliseconds is the most common API failure

    A client sends 1717171717 (seconds) while the server parses it as milliseconds, yielding January 1970; sending 1717171717000 the other way overflows some Go and Java parsers. Symptoms are dates in 1970 or centuries in the future. Defences: state the unit in the contract (a suffix like Ms or S, or use ISO 8601) and validate magnitude server side — anything above 1e11 cannot be seconds.

  • Mixing local time with UTC storage causes offsets

    Writing local time and reading it as UTC (or the reverse) is the most subtle timezone bug: the same data differs by eight hours between a developer machine at UTC+8 and a production host at UTC, with no error raised. Keep one rule — UTC everywhere in storage, render in the user timezone at the display layer, and never store a local datetime string without zone information such as 2024-06-01 12:00:00, which makes the zone unresolvable.

  • Local times on DST transition days do not exist or repeat

    In most zones the spring transition makes some local times never occur (such as 02:30) and the autumn transition makes others occur twice (such as 01:30). Scheduling by local time therefore runs twice or not at all on transition days. Avoid it by scheduling in UTC or expressing local time with a zone name (CRON_TZ in cron) rather than a bare local instant, and use IANA zone names instead of fixed offsets for cross-zone schedules.

How This Relates to Neighbours

For code points or character encodings, use the in-site character-encoding page; this one is about choosing and converting time formats.

To compute intervals or add and subtract dates, use the in-site time tools; this page is a format reference, not date arithmetic.

Scheduling semantics (cron expressions, missed windows, jitter) belong to scheduling systems and are out of scope here.

If the goal is debugging a time display bug, you usually need to inspect stored format, server timezone configuration and client rendering together — the format table alone will not localise it.

Practical Snippet

Key points: (1) declare the timestamp unit in the contract and validate magnitude server side — anything above 1e11 cannot be seconds; (2) store UTC as an ISO string or a number, never a zoneless string such as 2024-06-01 12:00:00; (3) Date.toString() embeds the local zone with English month names and is not reversibly parseable, so it must not be persisted; (4) HTTP header dates must use the IMF-fixdate form from toUTCString(); (5) bare local times do not exist or repeat on DST transition days, so schedule in UTC or with CRON_TZ.

const d = new Date()

// ① 三种输出,各自的用途
console.log(d.toISOString())            // 2024-06-01T12:00:00.000Z  ← 存储/传输用这个
console.log(d.toJSON())                 // 同上(Date 专有)
console.log(d.getTime())                // 1717243200000          毫秒,注意是 13 位

// ② 🔴 单位混用的防御:量级校验
function toDate(v) {
  if (typeof v === 'number') {
    if (v < 1e11) return new Date(v * 1000)     // 看着像秒 ⇒ 当秒处理
    if (v > 1e14) throw new Error('不像毫秒时间戳: ' + v)
    return new Date(v)                          // 13 位 ⇒ 毫秒
  }
  if (typeof v === 'string') {
    if (/^d{10}$/.test(v)) return new Date(Number(v) * 1000)
    return new Date(v)                          // ISO 字符串直接解析
  }
  throw new TypeError('不支持的类型')
}
console.log(toDate(1717171717).toISOString())    // 秒 ⇒ 正常
console.log(toDate(1717171717000).toISOString())  // 毫秒 ⇒ 正常

// ③ 存储一律 UTC,展示再本地化(不要存本地时间字符串)
const record = { createdAt: d.toISOString() }    // ✅
const LOCAL = '2024-06-01 12:00:00'             // ❌ 不带时区,无法推断

// ④ 手动格式化(仅用于展示;库更省事)
const pad = n => String(n).padStart(2, '0')
const fmtLocal = x => x.getFullYear() + '-' +
  pad(x.getMonth() + 1) + '-' + pad(x.getDate()) + ' ' +
  pad(x.getHours()) + ':' + pad(x.getMinutes())

// ⑤ RFC 7231 的 HTTP 头日期(必须用 UTC 的英文格式)
console.log(new Date().toUTCString())
// Mon, 01 Jun 2024 12:00:00 GMT

// ⑥ 陷阱:toString() 结果不可解析,不要用于持久化
console.log(d.toString())       // 本地时区 + 空格分隔 + 英文月份,不可逆
FormatMeaningExample
Unix timestampSeconds (or ms) since 1970-01-01 UTC1693564800
ISO 8601ISO date-time format2023-09-01T12:00:00Z
ISO 8601 (with UTC offset)Local time with +08:00 style offset2023-09-01T20:00:00+08:00
RFC 3339Strict subset of ISO 8601, common in APIs2023-09-01T12:00:00+00:00
RFC 2822 / 1123Date format common in HTTP headersFri, 01 Sep 2023 12:00:00 GMT
YYYY-MM-DDDate only (ISO date)2023-09-01
YYYY/MM/DDSlash-separated date (Chinese convention)2023/09/01
Chinese long dateChinese long dateSeptember 1, 2023
HH:mm:ss24-hour time12:00:00
hh:mm A12-hour time with AM/PM12:00 PM
YYYY-MM-DD HH:mm:ssCommon database datetime2023-09-01 12:00:00
Relative timee.g. "3 minutes ago", for social/log display3 minutes ago
Quarter Qn-YYYYFiscal/quarter representationQ3-2023
ISO week Www-yyyyISO week numberW35-2023
Duration(ISO 8601)Time duration notationP1Y2M3DT4H5M6S
Millisecond timestampValue returned by JavaScript Date.now()1693564800000

Frequently Asked Questions

Is a Unix timestamp seconds or milliseconds?

Usually seconds (e.g. 1693564800), but JavaScript Date.now() and many frontend libs return milliseconds (13 digits). Confirm the unit when interoperating, converting with ×1000 or ÷1000 as needed — otherwise you get a 1000x error landing in 1970 or the year 50000.

What is the difference between ISO 8601 and RFC 3339?

RFC 3339 is a strict subset of ISO 8601: it requires a full date-time, a timezone (Z or ±hh:mm), and forbids a space between date and time. Prefer RFC 3339 for APIs — it is the most unambiguous.

What is the relationship between UTC, GMT and +08:00?

UTC and GMT are effectively equal in daily use (GMT is a timezone name, UTC a time standard). +08:00 means 8 hours ahead of UTC (e.g. China Standard Time). Store times in UTC (or with offset) and convert to the user's zone only for display.

Which time format should databases store?

Prefer native datetime/timestamp types in relational databases (the DB handles timezone and format). If storing as a string, use ISO 8601/RFC 3339 with an explicit timezone, avoiding ambiguous "2023-09-01 12:00" without zone.