Overview
Unix time is traditionally seconds, but JavaScript Date values use milliseconds. Current seconds timestamps are usually 10 digits, while current millisecond timestamps are usually 13 digits. Confusing the two creates dates in 1970 or dates far in the future.
This guide focuses on practical implementation choices: how values should be stored, how they should cross API boundaries, and where developers most often introduce timezone or precision bugs. The safest pattern is to keep the stored value unambiguous, document the unit, and format the date only when it reaches a human-facing interface.
For timestamp-related work, a small wording mistake can become a production bug. A field named timestamp might mean Unix seconds in one API, JavaScript milliseconds in another, and an ISO 8601 string in a database export. The goal of this page is to make those decisions explicit so another developer can read the code, inspect an API response, or debug a log entry without guessing what the value represents.
When to use it
Use seconds for Unix CLI tools, many databases, and compact API fields. Use milliseconds for JavaScript Date, browser events, and APIs that explicitly document millisecond precision.
For production systems, also consider how the value will be indexed, logged, serialized, and read by other teams. A timestamp field that is obvious in one programming language can become ambiguous when it is consumed by JavaScript, SQL, mobile clients, or third-party integrations.
A good rule is to separate three concerns: the instant, the display format, and the user's timezone. The instant is the real moment being recorded. The display format is how that moment is presented, such as a Unix timestamp, ISO 8601 string, SQL datetime, or localized sentence. The timezone belongs at the formatting boundary unless the business rule itself depends on local civil time.
Developer examples
Use examples like this as a starting point, then adapt the timezone and precision to your application contract.
const seconds = 1717243200;
const milliseconds = seconds * 1000;
const date = new Date(milliseconds);
After converting the value, test both directions. Convert the timestamp to a readable date, then convert that date back to the original timestamp. If the result differs by hours, the problem is usually a timezone assumption. If the result differs by a factor of 1,000, the problem is usually seconds versus milliseconds. If the date lands near 1970 or thousands of years in the future, validate the unit before storing the value.
API and database design notes
When exposing milliseconds vs seconds behavior through an API, name fields with their unit or format. Prefer names such as created_at_unix_seconds, expires_at_ms, scheduled_at_utc, or created_at_iso over a vague field like date. Clear names reduce support tickets and prevent client teams from writing defensive conversion code around ambiguous values.
For databases, store the value in a type that matches the query pattern. Use date/time types when you need range queries, date truncation, reporting, and timezone-aware formatting. Use integer epoch values when you need compact event payloads, compatibility with message queues, or low-level interoperability. If you store epoch values, choose a range-safe integer type and document whether the column uses seconds, milliseconds, microseconds, or nanoseconds.
Debugging checklist
When a timestamp looks wrong, start with the raw value rather than the formatted output. Count the digits, identify the expected unit, and write down the timezone used by each layer: database session, backend runtime, API serializer, browser, and user profile. Then compare the value in UTC before checking local display. UTC makes it easier to distinguish storage bugs from formatting bugs.
Also test boundary dates. Include the Unix epoch, a current date, a daylight-saving transition for a relevant timezone, a leap day, and a far-future date if your product schedules future events. These cases quickly reveal hidden assumptions in parsers and formatters.
Common pitfalls
Digit length is a useful clue, not a contract. Always document field units with names like created_at_unix_seconds or createdAtMs.
Most timestamp bugs come from hidden assumptions: local time treated as UTC, seconds treated as milliseconds, formatted strings parsed without offsets, or narrow integer columns copied from old examples. Add tests for boundary dates and document the expected unit beside every external timestamp field.
Another common mistake is changing the stored value when only the presentation should change. For example, displaying an event in New York, London, and Tokyo should produce different local clock times, but the underlying instant should stay the same. If each display conversion writes a new timestamp back to storage, the data will drift and the original event time becomes hard to recover.
Production checklist
Before shipping code that depends on milliseconds vs seconds, confirm these items: the unit is documented, the timezone behavior is tested, API examples match real responses, database column ranges are large enough, and monitoring logs show both raw and formatted values where useful. Add validation that rejects obviously wrong units instead of silently accepting them.
Finally, include the conversion in your public documentation if external users or teammates will touch it. A short example payload with the expected timestamp value, UTC representation, and local display output is often more useful than a long abstract explanation.
FAQ
Why does JavaScript need * 1000?
JavaScript Date expects milliseconds since the Unix epoch, while Unix timestamps are commonly seconds.
Are 13-digit timestamps always milliseconds?
Usually for current dates, but APIs should still document the unit explicitly.