RFC 3339 · · Proposed Standard

The timestamp format you google ten times a week.

The official title is "Date and Time on the Internet: Timestamps." What it actually decides: one unambiguous way to write a moment in time, like 2026-07-05T14:30:00Z, that machines in every country read the exact same way.

Status
Proposed standard
Updated by
RFC 9557

Written by Noel Lang · IT trainer

TL;DR

RFC 3339 is the internet’s timestamp format. It pins down one strict, unambiguous way to write a date and time, such as 2026-07-05T14:30:00Z, as a tightly constrained profile of ISO 8601 with a required UTC offset. It is what most JSON APIs, logs and databases mean when they say “ISO-format timestamp”, because it strips out the ambiguities that full ISO 8601 still allows.

The problem it solves

Dates are where systems quietly betray each other. Is 03/04/2026 in March or April? Does a bare 14:30 mean the server’s clock, the user’s clock, or UTC? For decades every language, database and country wrote timestamps a little differently, and “a little” is enough to book a flight on the wrong day.

ISO 8601 was the international answer, and it helped. But it is a big standard with many optional forms: week numbers, day-of-year counts, missing separators, offsets you can leave off. Two systems can both be perfectly valid ISO 8601 and still disagree about how to write the same instant, which means a parser still has to guess.

RFC 3339’s move is subtraction. It takes ISO 8601 and throws away almost every option, leaving one rigid shape: four-digit year, dashes, a literal T, a time, and a UTC offset that is never optional. Because there is nothing left to guess, a parser can be a short regular expression, and a timestamp survives crossing from a phone in Osaka to a server in Ohio without changing meaning. That predictability is the whole reason it became the default for APIs, logs, and anything where a moment leaves one machine and lands on another.

The passport-stamp analogy

Think of a timestamp as a passport stamp for a moment in time. A note scribbled in a diary (“half two, Tuesday”) means something to you and nobody else: no year, no place, no way to check. ISO 8601 is the full international rulebook for stamps, thick enough that two border posts can follow it and still produce stamps that look different.

RFC 3339 is the one approved stamp design every booth agrees to use. Fixed fields, fixed order, and a mandatory line for the time zone, because a stamp that does not say where the clock was is a stamp you cannot trust. The Z at the end is the booth writing “read this against UTC”, the one clock the whole world shares. A time without an offset is a moment without a country; RFC 3339 refuses to issue one.

One timestamp, every field labeled

This is the shape RFC 3339 insists on. Nine fields, always the same order, always with the separators. The only optional piece is the fractional second; the offset at the end is never optional.

2026-07-05T14:30:00.500+02:00year · 4 digitsmonth · daytime · 24-hourUTC offset · requiredseparator (a space also works)fraction · any length, optional
Read the end first: +02:00 or Z is what turns wall-clock digits into an actual instant.

The format, field by field

The grammar in section 5.6 is only a dozen lines, and most of it you already read above. A few fields are worth a sentence each, because they are exactly the parts people get wrong.

The year is always four digits. RFC 3339 spends a whole short section (section 3) banning two-digit years, a small permanent monument to the Y2K panic. The month and day are two digits with the obvious ranges, and yes, the day is checked against the month, so 2026-02-30 is not a date.

The T is a literal letter joining date and time. A note lets you use a space instead for readability (that is what date --rfc-3339 does), and both the T and the Z may be written in lower case. So 2026-07-05t14:30:00z is legal, if a little cursed.

The fractional second is a dot followed by as many digits as you like: milliseconds, microseconds, nanoseconds, whatever your clock produces. RFC 3339 fixes no length, so a parser should accept 2026-07-05T14:30:00.5Z and ...00.123456789Z alike.

The Z means a zero offset from UTC. The spec itself notes it is “often spoken Zulu”, from the ICAO phonetic alphabet, which is why aviation and ops people say “fourteen thirty Zulu” out loud. Z is shorthand for +00:00.

Two genuinely surprising corners. Seconds can be 60: 1990-12-31T23:59:60Z is a real, legal timestamp marking a leap second, the extra tick occasionally added at the end of June or December to keep atomic clocks in step with the planet’s slightly irregular spin. And the offset -00:00 is not the same as +00:00: RFC 3339 defines the negative zero to mean “we know the UTC time, but we genuinely do not know the local offset”, a quiet, honest shrug that ISO 8601 does not even allow you to write.

What the RFC actually says

The original is ten pages and unusually pleasant to read. The map, in case you want to visit:

Section In plain words
1 · Introduction Why a single, tight timestamp format is worth writing down at all: the internet is global, and dates are where systems quietly disagree.
2 · Definitions The vocabulary: UTC, the meaning of Z (and why it is spoken "Zulu"), what an offset is. Short and worth reading.
3 · Two digit years A one-line ban: no. Four digits, always. The Y2K scar tissue made permanent.
4 · Local time Offsets, the unknown-offset trick (-00:00), and why the standard nudges you toward UTC.
5 · Date and time format The heart of it: the ABNF grammar, the fractional second, the leap second, and the notes about lower case and the space separator.
Appendices The ISO 8601 grammar for comparison, plus worked examples including a leap second. Handy when you argue with someone.

RFC 3339 vs ISO 8601, the argument that never ends

This is the question everyone actually types into a search box, so here is the honest answer: RFC 3339 is neither a subset nor a superset of ISO 8601. They overlap heavily, and most timestamps you meet are valid under both, but each allows something the other does not.

ISO 8601 is the sprawling parent. It allows week dates (2026-W27), ordinal dates (2026-186), a separator-free basic format (20260705T143000Z), and, crucially, times with no offset at all. RFC 3339 forbids every one of those, which is the entire point: fewer shapes, no guessing.

Going the other way, RFC 3339 permits -00:00 with its special “offset unknown” meaning, and ISO 8601 flatly forbids a negative zero offset. So a valid RFC 3339 timestamp can be invalid ISO 8601. That single case is why careful people say “profile of” rather than “subset of”.

Where the two formats overlap

Most real timestamps live in the middle. The edges are where the two standards quietly disagree, and where the “3339 vs 8601” arguments come from.

ISO 8601RFC 33392026-W272026-186no offset20260705the common ground2026-07-05T14:30:00Z-00:00(offset unknown)space insteadof T
Neither circle contains the other. That is why “RFC 3339 is just ISO 8601” is wrong in both directions.

The differences, rule by rule

Same idea as the diagram, but as a checklist you can copy into a code review:

Rule RFC 3339 vs ISO 8601
Four-digit year Both use four digits. ISO 8601 additionally allows expanded years like +002026 by prior agreement; RFC 3339 does not.
UTC offset RFC 3339 requires it. ISO 8601 makes it optional, which is exactly the ambiguity 3339 exists to remove.
Date/time separator Both use a literal T. Both also allow a space, RFC 3339 by an explicit note, ISO 8601 only "by mutual agreement".
Week dates (2026-W27) ISO 8601 only. RFC 3339 speaks nothing but plain year-month-day calendar dates.
Ordinal dates (2026-186) ISO 8601 only. Day-of-year counting is not part of the RFC 3339 grammar.
Basic format (20260705) ISO 8601 only. RFC 3339 always keeps the dashes and colons, so machines never have to guess where a field ends.
Negative zero offset (-00:00) RFC 3339 only. It means "UTC known, local offset unknown". ISO 8601 forbids a negative zero offset outright.

What is valid where

Concrete strings, checked against the grammar. This is the table to keep when someone insists their timestamp is fine:

Written like this Valid where
2026-07-05T14:30:00Z Valid in both. The canonical form: UTC, Z as the zero offset.
2026-07-05T16:30:00+02:00 Valid in both. Same instant as the line above, written in Berlin local time.
2026-07-05 14:30:00Z RFC 3339 accepts the space (per its note). ISO 8601 only by mutual agreement. This is what date --rfc-3339 prints.
2026-07-05T14:30:00 ISO 8601 only. No offset, so RFC 3339 rejects it: is that London or Tokyo?
2026-W27-1 ISO 8601 only. A week date (Monday of week 27). RFC 3339 has no idea what a week number is.
2026-07-05T14:30:00-00:00 RFC 3339 only. UTC is known, the local offset is deliberately unknown. ISO 8601 forbids the negative zero.

Try it: is this a valid RFC 3339 timestamp?

Paste any timestamp. We'll say whether it's strict RFC 3339, only the broader ISO 8601, or simply broken, and break down every field.

Waiting for a timestamp ...

Things people get wrong

  • "RFC 3339 is just ISO 8601."

    Close, but the equals sign is wrong. RFC 3339 is a strict profile: it keeps a small, safe slice of ISO 8601 and bolts on one rule of its own. ISO 8601 lets you write week dates, ordinal dates, and times with no offset; RFC 3339 forbids all three. Meanwhile RFC 3339 permits -00:00, which ISO 8601 does not. Neither is a clean subset of the other, so "the same as" fails in both directions.

  • "Z and +00:00 are identical."

    For the instant, yes: both are zero offset from UTC. The trap is -00:00. RFC 3339 defines it to mean "the UTC time is known, but the local offset is not". So Z and +00:00 assert UTC as the intended reference, while -00:00 quietly admits it does not know where on Earth this happened. Same numbers, different meaning.

  • "The T is optional and 23:59:60 is a typo."

    Two myths in one. The T is part of the grammar; you may swap it for a space only because a note explicitly allows it, and it may be lower case. And 23:59:60 is not a bug: seconds legally run to 60 for a leap second, the extra tick the world occasionally inserts at the end of June or December to keep clocks aligned with Earth's wobble.

  • "A Unix timestamp is RFC 3339."

    No. A Unix timestamp is one integer, seconds since 1 January 1970, like 1783000200. RFC 3339 is readable text, 2026-07-05T14:30:00Z. Both name an instant, but one is a number and the other is a string. You convert; you do not rename.

Where you'll meet this format

You have almost certainly read a hundred RFC 3339 timestamps today without noticing. A field guide:

You see You're looking at
A JSON API field "createdAt": "2026-07-05T14:30:00Z". JSON has no date type, so REST and GraphQL APIs almost universally serialize instants as RFC 3339 strings.
Kubernetes and cloud logs Every kubectl log line and most structured loggers stamp events in RFC 3339, so timelines from different machines line up.
date --rfc-3339=seconds GNU coreutils has a dedicated flag. It prints 2026-07-05 14:30:00+00:00, using the space separator the note permits.
JavaScript toISOString() new Date().toISOString() returns 2026-07-05T14:30:00.000Z. It is RFC 3339 by construction, which is why the two names blur together in practice.
Databases (Postgres, SQLite) timestamptz columns render as RFC 3339, and it is the safest text format to feed back in without a locale surprise.
Atom feeds, TOML, OpenAPI All three point at RFC 3339 for their date-time values, one of the quiet reasons it became the default.

Questions people actually ask

Is RFC 3339 the same as ISO 8601? +

Not quite. RFC 3339 is a strict profile of ISO 8601: a small, unambiguous subset with a few of its own rules. Most RFC 3339 timestamps are valid ISO 8601, but ISO 8601 also permits forms that RFC 3339 forbids (week dates, ordinal dates, missing offsets), and RFC 3339 permits -00:00, which ISO 8601 does not. So neither is fully contained in the other.

What is an example of an RFC 3339 timestamp? +

2026-07-05T14:30:00Z means 5 July 2026, 14:30:00 UTC. The T separates date and time, and Z means Zulu, a zero offset from UTC. An offset can replace Z: 2026-07-05T16:30:00+02:00 is the same instant in Central European Summer Time.

Does RFC 3339 support milliseconds? +

Yes. A fractional second is allowed right after the seconds, with any number of digits: 2026-07-05T14:30:00.123Z is 123 milliseconds, 2026-07-05T14:30:00.123456Z is microseconds. RFC 3339 does not fix the length, so parsers should accept whatever digits they get.

Is the T mandatory in RFC 3339? +

In the core grammar, yes: date and time are joined by a literal T. But the spec adds a note allowing a space instead, for readability, so 2026-07-05 14:30:00Z is also accepted. Both the T and the Z may be lower case (t and z). The one thing you cannot drop is the offset.

What is the difference between Z and +00:00? +

For the actual instant, nothing: both are zero offset from UTC. The subtle case is -00:00, which RFC 3339 defines to mean 'the UTC time is known, but the local offset is not'. So Z and +00:00 assert UTC as the reference; -00:00 quietly says the offset is unknown.

Is a Unix timestamp an RFC 3339 timestamp? +

No. A Unix timestamp is a single integer counting seconds since 1970 (like 1783000200). RFC 3339 is a human-readable text format (2026-07-05T14:30:00Z). They describe the same kind of thing, an instant, but they are not interchangeable text; you convert between them.

How do I get an RFC 3339 timestamp in code? +

In JavaScript, new Date().toISOString() returns 2026-07-05T14:30:00.000Z, which is valid RFC 3339. In Python, datetime.now(timezone.utc).isoformat() gives 2026-07-05T14:30:00+00:00. On the shell, date --rfc-3339=seconds prints 2026-07-05 14:30:00+00:00 with a space separator.

Referenced by

Other explainers on this site that point back to this RFC:

How RFC 3339 connects

What it works with