Unix time: seconds or milliseconds
Sumit Jha · Updated 2026-11-06
Unix time counts from 1970-01-01T00:00:00Z. APIs that say “unix timestamp” usually mean seconds. JavaScript Date.now() and many JSON fields use milliseconds. 10 digits means seconds. 13 digits means milliseconds. Convert units before you convert time zones.
Count the digits before you convert
1_700_000_000 seconds is November 2023. The same digits interpreted as milliseconds are January 1970 plus about 19 days. The other direction is worse: treating a millisecond value as seconds lands you in the year 50000. If a log is unreadable, check the unit before you blame the timezone.
Date parsing in JavaScript uses milliseconds. Dividing a Date.now() value by 1000 is the usual way to store seconds. Forgetting the divide, or dividing twice, is the entire bug.
seconds: 1700000000 milliseconds: 1700000000000
The zone is a separate question
An epoch is an instant. A timezone converts that instant to a wall clock. UTC and America/New_York show different hours for the same number. Abbreviations such as EST are not zone ids. Prefer America/New_York and let the zone database apply DST.
Cron expressions are not epochs. They are calendars in whatever zone the runner uses. Convert a timestamp when you have a number. Parse cron when you have five fields.
Two conversions that catch the unit bug
Take 1700000000. As seconds it is 2023-11-14T22:13:20Z. As milliseconds it is 1970-01-20. If a log viewer shows January 1970 for a recent event, you divided by 1000 when the value was already seconds, or you passed seconds to a Date constructor. Date expects milliseconds, so multiply a 10-digit value by 1000 before you construct one. A 13-digit value is already in milliseconds. Do not multiply it again.
The other direction shows up in APIs. A field documented as unix time that arrives as 1700000000000 is milliseconds even if the doc says seconds. Trust the magnitude. Years past 3000 or dates stuck in 1970 are unit bugs, not timezone bugs. Only after the instant is right should you print it in America/New_York or Asia/Kolkata. EST is not an id you can rely on. The zone database name is.
ISO-8601 strings such as 2023-11-14T22:13:20Z already carry the instant and the offset. You do not convert those by counting digits. Parse them, then format. Mixing a Date.parse result (milliseconds) into a database column of integer seconds is the same bug with a different source. The DevTooKit converter is for the integer. It does not change your schema.
A third shape shows up in some APIs: seconds with a fractional part, such as 1700000000.250. That is still seconds. Truncating or rounding before you store it is a product choice. Multiplying the whole token by 1000, including the fraction, gives milliseconds. Splitting on the dot and treating the left side as milliseconds does not. Document the unit next to the field name. “timestamp” alone has caused both bugs in this note.
When you compare two systems, print both values in UTC first. If the UTC instants match and the wall clocks differ, you have a zone question and the timezone tool is the next stop. If the UTC instants differ by a factor of about one thousand, you still have a unit question and no zone will fix it. Cron expressions are a calendar in the runner’s zone, not an epoch, so a “run at this unix time” feature is a different job from “parse this five-field line.”
FAQ
Is JavaScript Date in seconds?
No. Date uses milliseconds since the epoch. Divide by 1000 only when the API asked for seconds.
Does a timestamp include a timezone?
The number is an absolute instant. The zone only affects how you print it.
Related tools
- Time Zone ConverterConvert a date/time across 18 common time zones with live current-time ticker and DST detection.
- Cron Expression ParserParse a cron expression into human-readable descriptions and see the next run times.
Limitation: this note describes the DevTooKit tool and the general rule behind it. Production libraries, clocks, and schedulers can differ. Check those docs before you ship.