← All posts

End of 2026 Unix Timestamp: 1798761600 vs 1798761599

Use 1798761600 for the end of 2026 when you mean the boundary at 2027-01-01 00:00:00 UTC. Use 1798761599 only when you specifically need the last whole second inside 2026. The safer production pattern is a half-open range: start inclusive, end exclusive.

Quick answer

If you are filtering events, logs, orders, invoices, sessions, or analytics rows for the calendar year 2026 in UTC, use this range:

WHERE event_time >= 1767225600
  AND event_time <  1798761600

That includes everything from 2026-01-01T00:00:00Z up to, but not including, 2027-01-01T00:00:00Z.

Meaning Unix seconds UTC time Use it for
Start of 2026 1767225600 2026-01-01 00:00:00 UTC Inclusive lower bound
Last whole second of 2026 1798761599 2026-12-31 23:59:59 UTC Labels, second-precision displays
End of 2026 / start of 2027 1798761600 2027-01-01 00:00:00 UTC Exclusive upper bound

The short rule:

Use 1798761600 in code.
Use 1798761599 only when you mean "the final whole second."

Why 1798761600 is the cleaner "end" of 2026

The phrase "end of 2026" is ambiguous. Humans often mean the last visible clock reading on December 31. Databases usually need the first instant outside the interval.

Those are not the same thing:

  • 1798761599 is inside 2026.
  • 1798761600 is the boundary immediately after 2026.
  • A half-open interval writes that boundary as start <= time < end.

That pattern is not just style. It prevents the small bug that appears when a system starts storing fractional seconds.

Suppose a payment is captured at:

2026-12-31T23:59:59.500Z

That event is clearly inside 2026. But if your upper bound is the inclusive whole-second value 1798761599, the event can be dropped:

-- Fragile when event_time has fractional seconds
WHERE event_time BETWEEN 1767225600 AND 1798761599

Use the next boundary instead:

-- Safe for seconds, milliseconds, microseconds, and nanoseconds
WHERE event_time >= 1767225600
  AND event_time <  1798761600

This is why production date filters usually store the end as the start of the next period.

1798761599 is still useful, just narrower

There are valid cases for 1798761599:

  • A plain-English label: "the last second of 2026"
  • A countdown display that works only at whole-second precision
  • A file name or export note that expects the final included second
  • A legacy API contract that accepts only inclusive second endpoints

But it is not a good general-purpose upper bound once the data can be more precise than seconds.

The safer way to say it in a UI is:

Report range: Jan 1, 2026 00:00:00 UTC through Dec 31, 2026 23:59:59 UTC
Query range:  [1767225600, 1798761600)

That keeps the human label and the machine boundary separate.

Seconds, milliseconds, microseconds, and nanoseconds

Unix timestamps are often shown in seconds, but many systems store a larger unit. JavaScript Date, for example, uses milliseconds internally. Telemetry and database systems may use microseconds or nanoseconds.

Unit Exclusive end of 2026 Last whole second of 2026
Seconds 1798761600 1798761599
Milliseconds 1798761600000 1798761599000
Microseconds 1798761600000000 1798761599000000
Nanoseconds 1798761600000000000 1798761599000000000

Be careful with the right column. 1798761599000 is the millisecond value for exactly 23:59:59.000, not the last possible millisecond of the year. The final millisecond before 2027 would be 1798761599999.

That is another reason half-open ranges age better. You do not have to calculate the final millisecond, microsecond, or nanosecond.

Use these field names in schemas and logs:

created_at_seconds
created_at_ms
event_time_us
trace_time_ns

Avoid a bare field named timestamp when several units exist in the same codebase.

SQL examples

Epoch seconds column

If the column stores Unix seconds as an integer:

SELECT *
FROM events
WHERE event_ts_seconds >= 1767225600
  AND event_ts_seconds <  1798761600;

This also works if the column later changes from integer seconds to decimal seconds.

Epoch milliseconds column

If the column stores milliseconds:

SELECT *
FROM events
WHERE event_ts_ms >= 1767225600000
  AND event_ts_ms <  1798761600000;

Do not compare a millisecond column to second values:

-- Wrong: milliseconds column, seconds boundary
WHERE event_ts_ms < 1798761600

That kind of unit mismatch usually makes all modern rows look far in the future or far in the past.

PostgreSQL timestamp column

For timestamptz, compare actual UTC instants:

SELECT *
FROM events
WHERE event_time >= TIMESTAMPTZ '2026-01-01 00:00:00+00'
  AND event_time <  TIMESTAMPTZ '2027-01-01 00:00:00+00';

If you need to show the epoch equivalent in PostgreSQL:

SELECT EXTRACT(EPOCH FROM TIMESTAMPTZ '2027-01-01 00:00:00+00');
-- 1798761600

PostgreSQL's own date/time docs describe time periods as half-open intervals for overlap logic, which is the same shape used here.

What to avoid

This looks harmless but is brittle:

WHERE event_time BETWEEN '2026-01-01 00:00:00+00'
                     AND '2026-12-31 23:59:59+00'

It can miss:

  • 2026-12-31 23:59:59.001+00
  • 2026-12-31 23:59:59.500+00
  • 2026-12-31 23:59:59.999999+00

Use the next midnight instead.

JavaScript examples

In JavaScript, Date.UTC() returns milliseconds. Divide by 1000 when you need Unix seconds:

const end2026ExclusiveSeconds = Date.UTC(2027, 0, 1) / 1000;
const end2026ExclusiveMs = Date.UTC(2027, 0, 1);
const lastWholeSecond2026 = end2026ExclusiveSeconds - 1;

console.log(end2026ExclusiveSeconds);
// 1798761600

console.log(new Date(end2026ExclusiveMs).toISOString());
// 2027-01-01T00:00:00.000Z

console.log(new Date(lastWholeSecond2026 * 1000).toISOString());
// 2026-12-31T23:59:59.000Z

Filter events like this:

const start2026 = Date.UTC(2026, 0, 1);
const end2026 = Date.UTC(2027, 0, 1);

const rowsIn2026 = rows.filter((row) => {
  const t = row.createdAtMs;
  return t >= start2026 && t < end2026;
});

The month argument in Date.UTC(year, monthIndex, day) is zero-based. January is 0, not 1.

Python examples

Use timezone-aware UTC datetimes:

from datetime import datetime, timezone

start_2026 = datetime(2026, 1, 1, tzinfo=timezone.utc)
end_2026 = datetime(2027, 1, 1, tzinfo=timezone.utc)

print(int(start_2026.timestamp()))
# 1767225600

print(int(end_2026.timestamp()))
# 1798761600

print(int(end_2026.timestamp()) - 1)
# 1798761599

Avoid this shape in code review:

# Risky: naive datetime may be interpreted as local time
datetime(2027, 1, 1).timestamp()

Python's datetime.timestamp() documentation notes that naive datetimes are treated as local time. That is fine if local time is what you mean, but it is a common source of UTC boundary bugs.

Shell commands

On Linux with GNU date:

date -u -d '2027-01-01 00:00:00' +%s
# 1798761600

date -u -d @1798761600 '+%Y-%m-%dT%H:%M:%SZ'
# 2027-01-01T00:00:00Z

On macOS or BSD date:

date -u -j -f '%Y-%m-%d %H:%M:%S' '2027-01-01 00:00:00' +%s
# 1798761600

date -u -r 1798761599 '+%Y-%m-%dT%H:%M:%SZ'
# 2026-12-31T23:59:59Z

If your local shell command prints a December 31 date for 1798761600, check whether you forgot -u. Without UTC output, your terminal is showing the same instant in your local timezone.

UTC boundary vs local-year boundary

This page defines the end of 2026 in UTC. That is the right default for Unix timestamps, APIs, logs, databases, and cross-region systems.

The same instant can still be December 31 locally:

Timezone Local time at Unix 1798761600
UTC 2027-01-01 00:00:00
America/New_York 2026-12-31 19:00:00
America/Los_Angeles 2026-12-31 16:00:00
Europe/London 2027-01-01 00:00:00
Asia/Shanghai 2027-01-01 08:00:00
Asia/Tokyo 2027-01-01 09:00:00

If your product reports by a user's local calendar year, compute the local boundary first, then convert that instant to UTC.

Examples for the exclusive end of local calendar year 2026:

Reporting timezone Local boundary UTC instant Unix seconds
UTC 2027-01-01 00:00:00 2027-01-01 00:00:00Z 1798761600
America/New_York 2027-01-01 00:00:00 2027-01-01 05:00:00Z 1798779600
America/Los_Angeles 2027-01-01 00:00:00 2027-01-01 08:00:00Z 1798790400
Asia/Shanghai 2027-01-01 00:00:00 2026-12-31 16:00:00Z 1798732800
Asia/Tokyo 2027-01-01 00:00:00 2026-12-31 15:00:00Z 1798729200

Use an IANA timezone name such as America/New_York, not a hard-coded offset like UTC-5, when local reporting matters. Offset rules can change, and daylight-saving rules are not the same around the world.

Why 2026 has exactly 31,536,000 Unix seconds

2026 is not a leap year. For normal Unix timestamp math, that means:

365 days * 86,400 seconds = 31,536,000 seconds

Check the boundary:

1798761600 - 1767225600 = 31,536,000

Do not compute future year boundaries by repeatedly adding 365 * 86400. Leap years will eventually break that shortcut. Let a date library calculate January 1 of the next year:

function utcYearRangeSeconds(year) {
  return {
    start: Date.UTC(year, 0, 1) / 1000,
    endExclusive: Date.UTC(year + 1, 0, 1) / 1000,
  };
}

console.log(utcYearRangeSeconds(2026));
// { start: 1767225600, endExclusive: 1798761600 }

Copy-paste validation checklist

Before shipping a hard-coded end-of-year timestamp, check these five things:

  1. The timezone is explicit: UTC, or a named IANA timezone for local reporting.
  2. The unit is explicit: seconds, milliseconds, microseconds, or nanoseconds.
  3. The upper bound is exclusive: < 1798761600, not <= 1798761599, unless your contract is truly second-only.
  4. The date column precision is known: whole seconds, milliseconds, microseconds, or more.
  5. The test fixture includes a row after 23:59:59.000 but before 00:00:00.000.

A small regression fixture catches the important case:

2026-12-31T23:59:58.900Z  included
2026-12-31T23:59:59.000Z  included
2026-12-31T23:59:59.500Z  included
2027-01-01T00:00:00.000Z  excluded

That last included row is exactly what the 1798761599 inclusive endpoint often misses.

Official references

Related timestamp guides

FAQ

What is the Unix timestamp for the end of 2026?
For date ranges, the end of 2026 is Unix timestamp 1798761600, which is 2027-01-01 00:00:00 UTC and should be used as an exclusive upper bound. The last whole second still inside 2026 is 1798761599, or 2026-12-31 23:59:59 UTC.
Why is the end of 2026 1798761600 and not 1798761599?
Because a year boundary is the first instant after the year, not the final representable value inside the year. 1798761600 marks the exact start of 2027. 1798761599 is only the previous whole second, so it misses fractional-second events that happen before midnight.
Is 1798761599 wrong?
No, but it answers a narrower question. 1798761599 is correct for the last whole second of 2026 at second precision. It is not the best upper bound for SQL, logs, analytics, or event data that may store milliseconds, microseconds, or nanoseconds.
What is the millisecond timestamp for the end of 2026?
The exclusive millisecond timestamp is 1798761600000. The inclusive last-whole-second millisecond value is 1798761599000, but it still does not include events such as 2026-12-31T23:59:59.500Z unless you use a half-open upper bound.
What SQL WHERE clause should I use for all events in 2026?
Use a half-open range: WHERE event_time >= 1767225600 AND event_time < 1798761600 for epoch seconds. For timestamp columns, use event_time >= '2026-01-01 00:00:00+00' AND event_time < '2027-01-01 00:00:00+00'.
Is 1798761600 also the start of 2027?
Yes. 1798761600 is both the exclusive end of 2026 and the inclusive start of 2027 in UTC.
Does local timezone change the end-of-2026 timestamp?
The UTC boundary does not change: it is always 1798761600. A local-calendar year boundary can be different. For example, 2027-01-01 00:00 in America/New_York is 1798779600, five hours after the UTC boundary.
How do I calculate the end of 2026 in JavaScript?
Use Date.UTC(2027, 0, 1) / 1000 for the exclusive end boundary, or subtract 1 for the last whole second: Date.UTC(2027, 0, 1) / 1000 - 1.
How do I calculate the end of 2026 in Python?
Use an aware UTC datetime: int(datetime(2027, 1, 1, tzinfo=timezone.utc).timestamp()). Avoid naive UTC datetimes because Python may treat them as local time in some timestamp conversions.