Twitter Snowflake ID: How to Decode It to a Timestamp
Decode a Twitter snowflake ID to the millisecond in Python or JavaScript, proved on real @NASA posts, plus the month account IDs began to hold dates.
Tarun Khatri
Published · Updated · 7 min read
A Twitter snowflake ID is a post's numeric ID, and its top bits store the exact millisecond the post was created.
Every post on X (Twitter) since November 2010 has one. If you just want a date, paste a post link or ID into our free tweet ID to date converter. You need no code, and it runs in your browser.
Or do the math yourself in Python:
from datetime import datetime, timezone
ms = (2119136607009734978 >> 22) + 1288834974657
print(datetime.fromtimestamp(ms / 1000, timezone.utc))
2026-11-07 18:35:13.422000+00:00
How a Twitter snowflake ID is built
A snowflake ID packs three numbers into one 64-bit integer: a time, a machine and a counter.
Twitter's engineering blog announced Snowflake on 1 June 2010, built from "timestamp, worker number and sequence number." The archived source code sets the numbers behind the chart:
twepoch = 1288834974657Lis the epoch: 01:42:54.657 UTC on 4 November 2010.workerIdBitsanddatacenterIdBitsare5Leach: the 10 machine bits.sequenceBits = 12L, so the time sits 22 bits up.
The README says that 41-bit clock "gives us 69 years." By our math, it runs out in July 2080.
The repo's README now calls Twitter's internal Snowflake "a full rewrite." The time bits still decode, but you should treat the low 22 bits as opaque.
Step 1: Decode a Twitter snowflake to a timestamp in Python
Shift the ID right by 22 bits, add the epoch, and read it as UTC, with the standard library only:
from datetime import datetime, timezone
EPOCH_MS = 1288834974657 # twepoch in Twitter's Snowflake code
def snowflake_time(x_id):
ms = (int(x_id) >> 22) + EPOCH_MS
return datetime.fromtimestamp(ms / 1000, timezone.utc)
for x_id in ["2119136607009734978", "2019881223666233717", "2115480207469560109"]:
print(x_id, snowflake_time(x_id).isoformat(timespec="milliseconds"))
We ran it on 7 November 2026 and got:
2119136607009734978 2026-11-07T18:35:13.422+00:00
2019881223666233717 2026-02-06T21:09:45.957+00:00
2115480207469560109 2026-10-28T16:25:59.839+00:00
You can pass the ID as a string or an int. Python's int has no size limit, so the ID never loses digits.
Step 2: Decode it in JavaScript with BigInt
In JavaScript you need BigInt, written with an n suffix. Every post ID made after 28 November 2010 is too big for a plain Number to hold exactly: X's docs say it's "limited to 53 bits."
const EPOCH = 1288834974657n; // twepoch in Twitter's Snowflake code
function snowflakeTime(id) {
return new Date(Number((BigInt(id) >> 22n) + EPOCH));
}
for (const id of ["2119136607009734978", "2019881223666233717", "2115480207469560109"]) {
console.log(id, snowflakeTime(id).toISOString());
}
Node 22 printed:
2119136607009734978 2026-11-07T18:35:13.422Z
2019881223666233717 2026-02-06T21:09:45.957Z
2115480207469560109 2026-10-28T16:25:59.839Z
Proof: decoded IDs match X's own timestamps
On 7 November 2026, we fetched the first post on the @NASA, @XDevelopers and @github timelines through Weir: three pinned posts, for 12 credits.
Each decoded time matched Weir's createdAt to the second:
| Account | Post ID | Decoded | Weir createdAt |
|---|---|---|---|
| @NASA | 2119136607009734978 | 2026-11-07 18:35:13.422 | 2026-11-07 18:35:13 |
| @XDevelopers | 2019881223666233717 | 2026-02-06 21:09:45.957 | 2026-02-06 21:09:45 |
| @github | 2115480207469560109 | 2026-10-28 16:25:59.839 | 2026-10-28 16:25:59 |
createdAt stops at whole seconds, so the ID gives you the sharper clock. The media IDs we tested were snowflakes too: the @NASA video's decoded to 24 seconds before its post.
Which IDs are snowflakes? Posts since 2010, accounts since 2016
Posts switched first. Twitter's API team gave developers the date: "Snowflake will be turned on" on "4th November 2010 (Thursday)."
The same note calls the IDs before it "sequential," so you'll find no time in them. Account IDs switched more than five years later, as six public accounts show:
| Account | Created (UTC) | ID digits | Holds the time? |
|---|---|---|---|
| @NASA | 19 Dec 2007 | 8 | No |
| @XDevelopers | 14 Dec 2013 | 10 | No |
| @OpenAI | 6 Dec 2015 | 10 | No |
| @LaLaLand | 4 Jan 2016 | 10 | No |
| @arrivalmovie | 14 Jun 2016 | 18 | Yes, to the second |
| @AnthropicAI | 25 Jan 2021 | 19 | Yes, 12 s early |
A counter ID decodes to seconds after the epoch: @NASA's user ID lands at 01:42:54 UTC on 4 November 2010. That date tells you there's no time inside.
So from about March 2016 on, an 18- or 19-digit user ID gives you the sign-up time, give or take seconds. For an older account, our free account age checker reads X's stored date after a free sign-in, and our guide to when someone joined Twitter covers other routes.
X's docs call Space IDs "Alphanumeric, not Snowflake format." We didn't test List or DM IDs.
Turn a time into an ID: how since_id and max_id windows work
Run it backwards and you get the smallest ID X could make at a moment: subtract the epoch, then shift left 22 bits.
from datetime import datetime, timedelta, timezone
EPOCH_MS = 1288834974657
UNIX = datetime(1970, 1, 1, tzinfo=timezone.utc)
def first_id_at(iso):
ms = (datetime.fromisoformat(iso) - UNIX) // timedelta(milliseconds=1)
return (ms - EPOCH_MS) << 22
start = first_id_at("2026-11-07T18:35:13+00:00")
end = first_id_at("2026-11-07T18:35:14+00:00")
print(start, end)
print(start <= 2119136607009734978 < end)
print(f"from:NASA since_id:{start - 1} max_id:{end - 1}")
2119136605238198272 2119136609432502272
True
from:NASA since_id:2119136605238198271 max_id:2119136609432502271
X's since_id: keeps posts newer than an ID, and max_id: keeps that ID and older. So you subtract 1 from each bound.
We ran that query through Weir's search on 7 November 2026. It returned exactly one post, @NASA's, for 2 credits. Both operators also passed our X search operator tests on 27 October.
Which bound should you use?
- Whole seconds:
since_time:anduntil_time:take Unix seconds and are simpler. - Milliseconds or X's API: use IDs, since X's search endpoint takes
since_idanduntil_id. - Weir: its
sinceanduntilfields turn into ID bounds for you.
Common mistakes: precision, seconds and time zones
The first two slips, run on @NASA's ID:
const body = '{"id": 2119136607009734978, "id_str": "2119136607009734978"}';
const post = JSON.parse(body);
console.log(post.id); // digits lost
console.log(post.id_str); // exact
console.log(post.id >> 22); // a 32-bit shift
console.log(new Date(Number((BigInt(post.id_str) >> 22n) + 1288834974657n)).toISOString());
2119136607009735000
2119136607009734978
205
2026-11-07T18:35:13.422Z
- Parsing the ID as a Number.
JSON.parsechanged it. Read the string:id_strin X's v1.1,idin Weir and v2, as our tweet JSON example shows. >>on a Number. JavaScript shifts Numbers as 32-bit integers, which is how you get 205. Shift aBigInt.- Seconds where milliseconds belong.
new Date()reads its input as milliseconds, so a seconds value lands in January 1970. - The wrong time zone. Decoded times are UTC. Day operators like
since:follow Japan time through Weir, but ID bounds ignore time zones.
How the Twitter snowflake algorithm generates unique IDs
Each ID server makes IDs alone, with no central counter: "an uncoordinated approach," in Twitter's words. The code takes four steps:
- Read the clockMilliseconds since the epoch.
- Shift it up 22 bitsThe time fills the top of the number.
- Add the machineA 5-bit datacenter ID and a 5-bit worker ID.
- Add the sequenceA 12-bit count within the same millisecond.
Two guards stop duplicates. Past 4,096 IDs in one millisecond, a worker waits for the next one. If the clock runs backwards, it refuses: "Clock moved backwards."
IDs are only "roughly sortable," to about a second, so don't trust ID order for events milliseconds apart. If you build your own unique ID generator this way, keep both guards.
Caveats: when the ID won't help, and when to skip Weir
We run Weir, so here's the honest list:
- You don't need an API for post dates. The converter or the Step 1 script gives them free.
- Old accounts hold no date. Before about March 2016, read the Joined line or call a profile API, such as Weir's at 3 credits.
- The low 22 bits have no public map, so don't build on them.
- Weir is read-only. It reads public data and isn't licensed by X, so access can change.
FAQ
What is a Twitter snowflake ID?
It's the 64-bit number X gives each post, built from a millisecond timestamp, a machine number and a counter. Twitter turned it on for posts on 4 November 2010 so its servers could make unique, time-ordered IDs.
How do you convert a Twitter snowflake to a timestamp?
Shift the ID right by 22 bits. Then add X's epoch, 1288834974657, and you have Unix time in milliseconds, in UTC. In JavaScript, shift a BigInt, never a Number.
Is there a free Twitter snowflake ID decoder?
Yes. Our tweet ID to date converter decodes a post link or ID in your browser, with no sign-in. It also reads 18- and 19-digit account IDs.
Does a Twitter user ID show when the account was created?
Only if the account was made from about March 2016 on. Its ID then has 18 or 19 digits and decodes to the sign-up, within seconds. Older accounts have shorter counter IDs with no date.
Sources
Checked 7 November 2026 (UTC):
- Twitter Engineering, "Announcing Snowflake" (1 June 2010; Wayback copy, 28 September 2026): https://blog.x.com/engineering/en_us/a/2010/announcing-snowflake
- Snowflake code and README, snowflake-2010 tag: https://github.com/twitter-archive/snowflake/blob/snowflake-2010/src/main/scala/com/twitter/service/snowflake/IdWorker.scala and https://github.com/twitter-archive/snowflake/blob/snowflake-2010/README.mkd
- Snowflake README on master: https://github.com/twitter-archive/snowflake
- Matt Harris, "Snowflake: An update and some very important information" (19 October 2010): https://groups.google.com/g/twitter-api-announce/c/ahbvo3VTIYI
- X docs, X IDs: https://docs.x.com/fundamentals/x-ids
- X docs, Search Recent Posts: https://docs.x.com/x-api/posts/search-recent-posts
- Weir searchX reference: https://docs.weirapp.io/reference/x/searchX
- Weir X search operator tests (27 October 2026): https://weirapp.io/x-search-operators
- Our Weir calls, 7 November 2026, as described above