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:
1798761599is inside 2026.1798761600is 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+002026-12-31 23:59:59.500+002026-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:
- The timezone is explicit: UTC, or a named IANA timezone for local reporting.
- The unit is explicit: seconds, milliseconds, microseconds, or nanoseconds.
- The upper bound is exclusive:
< 1798761600, not<= 1798761599, unless your contract is truly second-only. - The date column precision is known: whole seconds, milliseconds, microseconds, or more.
- The test fixture includes a row after
23:59:59.000but before00: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
- MDN JavaScript Date - JavaScript
Datestores milliseconds since the Unix epoch andDate.UTC()returns a millisecond timestamp. - Python datetime documentation - Python recommends timezone-aware UTC datetimes for timestamp conversion.
- PostgreSQL date/time functions - PostgreSQL describes time periods as half-open intervals in its overlap logic.
- IANA Time Zone Database - Use IANA timezone names for local calendar boundaries and changing timezone rules.
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.