[{"data":1,"prerenderedAt":1103},["ShallowReactive",2],{"guide-timezone-database-timestamps":3},{"id":4,"title":5,"body":6,"date":1095,"description":1096,"extension":1097,"meta":1098,"navigation":86,"path":1099,"readingTime":77,"seo":1100,"stem":1101,"__hash__":1102},"guides\u002Fguides\u002Ftimezone-database-timestamps.md","Timezone Handling in Database Timestamps: Best Practices",{"type":7,"value":8,"toc":1072},"minimark",[9,14,18,21,25,30,33,106,113,117,124,173,179,208,212,283,287,291,294,451,455,458,653,656,660,663,688,867,871,889,968,972,976,996,1000,1007,1011,1014,1018,1050,1054,1063,1068],[10,11,13],"h2",{"id":12},"the-timezone-problem-in-databases","The Timezone Problem in Databases",[15,16,17],"p",{},"Timezone mishandling is one of the most common sources of bugs in web applications. Appointments show up on the wrong day. Daily reports include data from the previous day. Scheduled tasks fire at unexpected hours. The root cause is almost always inconsistent timezone handling between the application layer and the database.",[15,19,20],{},"The solution is straightforward in principle: store timestamps in UTC, and convert to local time only at the display layer. In practice, the details matter.",[10,22,24],{"id":23},"storage-strategies","Storage Strategies",[26,27,29],"h3",{"id":28},"strategy-1-always-store-utc","Strategy 1: Always Store UTC",[15,31,32],{},"This is the most widely recommended approach. Every timestamp enters the database as UTC, and the application converts to the user's local timezone at render time.",[34,35,40],"pre",{"className":36,"code":37,"language":38,"meta":39,"style":39},"language-sql shiki shiki-themes github-light github-dark","-- PostgreSQL: TIMESTAMP WITHOUT TIME ZONE storing UTC values\nCREATE TABLE events (\n  id SERIAL PRIMARY KEY,\n  name TEXT NOT NULL,\n  created_at TIMESTAMP NOT NULL  -- always UTC, even though the column doesn't enforce it\n);\n\n-- Insert as UTC\nINSERT INTO events (name, created_at)\nVALUES ('User signup', '2024-05-28 14:30:00');\n","sql","",[41,42,43,51,57,63,69,75,81,88,94,100],"code",{"__ignoreMap":39},[44,45,48],"span",{"class":46,"line":47},"line",1,[44,49,50],{},"-- PostgreSQL: TIMESTAMP WITHOUT TIME ZONE storing UTC values\n",[44,52,54],{"class":46,"line":53},2,[44,55,56],{},"CREATE TABLE events (\n",[44,58,60],{"class":46,"line":59},3,[44,61,62],{},"  id SERIAL PRIMARY KEY,\n",[44,64,66],{"class":46,"line":65},4,[44,67,68],{},"  name TEXT NOT NULL,\n",[44,70,72],{"class":46,"line":71},5,[44,73,74],{},"  created_at TIMESTAMP NOT NULL  -- always UTC, even though the column doesn't enforce it\n",[44,76,78],{"class":46,"line":77},6,[44,79,80],{},");\n",[44,82,84],{"class":46,"line":83},7,[44,85,87],{"emptyLinePlaceholder":86},true,"\n",[44,89,91],{"class":46,"line":90},8,[44,92,93],{},"-- Insert as UTC\n",[44,95,97],{"class":46,"line":96},9,[44,98,99],{},"INSERT INTO events (name, created_at)\n",[44,101,103],{"class":46,"line":102},10,[44,104,105],{},"VALUES ('User signup', '2024-05-28 14:30:00');\n",[15,107,108,112],{},[109,110,111],"strong",{},"Risk",": The database does not enforce UTC. A developer can insert local time by mistake, and nothing catches the error until a user reports wrong timestamps.",[26,114,116],{"id":115},"strategy-2-use-timestamptz","Strategy 2: Use TIMESTAMPTZ",[15,118,119,120,123],{},"PostgreSQL's ",[41,121,122],{},"TIMESTAMPTZ"," column type stores the timestamp converted to UTC internally but remembers the timezone offset for input:",[34,125,127],{"className":36,"code":126,"language":38,"meta":39,"style":39},"CREATE TABLE events (\n  id SERIAL PRIMARY KEY,\n  name TEXT NOT NULL,\n  created_at TIMESTAMPTZ NOT NULL  -- stores UTC internally\n);\n\n-- Input with offset — PostgreSQL converts to UTC automatically\nINSERT INTO events (name, created_at)\nVALUES ('Meeting', '2024-05-28 14:30:00+02:00');\n-- Stored internally as 2024-05-28 12:30:00 UTC\n",[41,128,129,133,137,141,146,150,154,159,163,168],{"__ignoreMap":39},[44,130,131],{"class":46,"line":47},[44,132,56],{},[44,134,135],{"class":46,"line":53},[44,136,62],{},[44,138,139],{"class":46,"line":59},[44,140,68],{},[44,142,143],{"class":46,"line":65},[44,144,145],{},"  created_at TIMESTAMPTZ NOT NULL  -- stores UTC internally\n",[44,147,148],{"class":46,"line":71},[44,149,80],{},[44,151,152],{"class":46,"line":77},[44,153,87],{"emptyLinePlaceholder":86},[44,155,156],{"class":46,"line":83},[44,157,158],{},"-- Input with offset — PostgreSQL converts to UTC automatically\n",[44,160,161],{"class":46,"line":90},[44,162,99],{},[44,164,165],{"class":46,"line":96},[44,166,167],{},"VALUES ('Meeting', '2024-05-28 14:30:00+02:00');\n",[44,169,170],{"class":46,"line":102},[44,171,172],{},"-- Stored internally as 2024-05-28 12:30:00 UTC\n",[15,174,175,176,178],{},"When you query a ",[41,177,122],{}," column, PostgreSQL returns the value in the session's timezone setting:",[34,180,182],{"className":36,"code":181,"language":38,"meta":39,"style":39},"-- Set session timezone\nSET timezone = 'America\u002FNew_York';\n\nSELECT created_at FROM events;\n-- Returns: 2024-05-28 08:30:00-04:00\n",[41,183,184,189,194,198,203],{"__ignoreMap":39},[44,185,186],{"class":46,"line":47},[44,187,188],{},"-- Set session timezone\n",[44,190,191],{"class":46,"line":53},[44,192,193],{},"SET timezone = 'America\u002FNew_York';\n",[44,195,196],{"class":46,"line":59},[44,197,87],{"emptyLinePlaceholder":86},[44,199,200],{"class":46,"line":65},[44,201,202],{},"SELECT created_at FROM events;\n",[44,204,205],{"class":46,"line":71},[44,206,207],{},"-- Returns: 2024-05-28 08:30:00-04:00\n",[26,209,211],{"id":210},"comparison","Comparison",[213,214,215,234],"table",{},[216,217,218],"thead",{},[219,220,221,225,228,231],"tr",{},[222,223,224],"th",{},"Approach",[222,226,227],{},"Enforces UTC",[222,229,230],{},"Timezone-Aware Queries",[222,232,233],{},"Portability",[235,236,237,255,270],"tbody",{},[219,238,239,246,249,252],{},[240,241,242,245],"td",{},[41,243,244],{},"TIMESTAMP"," (UTC by convention)",[240,247,248],{},"No",[240,250,251],{},"Manual",[240,253,254],{},"High",[219,256,257,261,264,267],{},[240,258,259],{},[41,260,122],{},[240,262,263],{},"Yes (internal)",[240,265,266],{},"Yes",[240,268,269],{},"PostgreSQL-specific",[219,271,272,275,278,280],{},[240,273,274],{},"Unix epoch integer",[240,276,277],{},"Yes (by definition)",[240,279,251],{},[240,281,282],{},"Highest",[10,284,286],{"id":285},"application-layer-handling","Application Layer Handling",[26,288,290],{"id":289},"sending-timestamps-to-the-database","Sending Timestamps to the Database",[15,292,293],{},"Always send timestamps in ISO 8601 format with UTC indicator:",[34,295,299],{"className":296,"code":297,"language":298,"meta":39,"style":39},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F Node.js — always send UTC to the database\nconst now = new Date();                           \u002F\u002F local time object\nconst utcISO = now.toISOString();                 \u002F\u002F \"2024-05-28T14:30:00.000Z\"\nconst epochSeconds = Math.floor(now.getTime() \u002F 1000); \u002F\u002F 1716898200\n\n\u002F\u002F With an ORM like Prisma\nawait prisma.event.create({\n  data: {\n    name: 'User signup',\n    createdAt: now,  \u002F\u002F Prisma handles UTC conversion\n  },\n});\n","javascript",[41,300,301,307,334,355,391,395,400,414,419,431,439,445],{"__ignoreMap":39},[44,302,303],{"class":46,"line":47},[44,304,306],{"class":305},"sJ8bj","\u002F\u002F Node.js — always send UTC to the database\n",[44,308,309,313,317,320,323,327,331],{"class":46,"line":53},[44,310,312],{"class":311},"szBVR","const",[44,314,316],{"class":315},"sj4cs"," now",[44,318,319],{"class":311}," =",[44,321,322],{"class":311}," new",[44,324,326],{"class":325},"sScJk"," Date",[44,328,330],{"class":329},"sVt8B","();                           ",[44,332,333],{"class":305},"\u002F\u002F local time object\n",[44,335,336,338,341,343,346,349,352],{"class":46,"line":59},[44,337,312],{"class":311},[44,339,340],{"class":315}," utcISO",[44,342,319],{"class":311},[44,344,345],{"class":329}," now.",[44,347,348],{"class":325},"toISOString",[44,350,351],{"class":329},"();                 ",[44,353,354],{"class":305},"\u002F\u002F \"2024-05-28T14:30:00.000Z\"\n",[44,356,357,359,362,364,367,370,373,376,379,382,385,388],{"class":46,"line":65},[44,358,312],{"class":311},[44,360,361],{"class":315}," epochSeconds",[44,363,319],{"class":311},[44,365,366],{"class":329}," Math.",[44,368,369],{"class":325},"floor",[44,371,372],{"class":329},"(now.",[44,374,375],{"class":325},"getTime",[44,377,378],{"class":329},"() ",[44,380,381],{"class":311},"\u002F",[44,383,384],{"class":315}," 1000",[44,386,387],{"class":329},"); ",[44,389,390],{"class":305},"\u002F\u002F 1716898200\n",[44,392,393],{"class":46,"line":71},[44,394,87],{"emptyLinePlaceholder":86},[44,396,397],{"class":46,"line":77},[44,398,399],{"class":305},"\u002F\u002F With an ORM like Prisma\n",[44,401,402,405,408,411],{"class":46,"line":83},[44,403,404],{"class":311},"await",[44,406,407],{"class":329}," prisma.event.",[44,409,410],{"class":325},"create",[44,412,413],{"class":329},"({\n",[44,415,416],{"class":46,"line":90},[44,417,418],{"class":329},"  data: {\n",[44,420,421,424,428],{"class":46,"line":96},[44,422,423],{"class":329},"    name: ",[44,425,427],{"class":426},"sZZnC","'User signup'",[44,429,430],{"class":329},",\n",[44,432,433,436],{"class":46,"line":102},[44,434,435],{"class":329},"    createdAt: now,  ",[44,437,438],{"class":305},"\u002F\u002F Prisma handles UTC conversion\n",[44,440,442],{"class":46,"line":441},11,[44,443,444],{"class":329},"  },\n",[44,446,448],{"class":46,"line":447},12,[44,449,450],{"class":329},"});\n",[26,452,454],{"id":453},"reading-timestamps-from-the-database","Reading Timestamps from the Database",[15,456,457],{},"Convert to the user's local timezone only at the presentation layer:",[34,459,461],{"className":296,"code":460,"language":298,"meta":39,"style":39},"\u002F\u002F Server: return UTC ISO string to client\napp.get('\u002Fevents', async (req, res) => {\n  const events = await db.query('SELECT * FROM events');\n  \u002F\u002F Send UTC timestamps — the client converts to local time\n  res.json(events);\n});\n\n\u002F\u002F Client: display in user's timezone\nfunction formatEventTime(utcISO) {\n  return new Date(utcISO).toLocaleString('en-US', {\n    timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n    dateStyle: 'medium',\n    timeStyle: 'short',\n  });\n}\n",[41,462,463,468,509,535,540,551,555,559,564,580,603,620,630,641,647],{"__ignoreMap":39},[44,464,465],{"class":46,"line":47},[44,466,467],{"class":305},"\u002F\u002F Server: return UTC ISO string to client\n",[44,469,470,473,476,479,482,485,488,491,495,497,500,503,506],{"class":46,"line":53},[44,471,472],{"class":329},"app.",[44,474,475],{"class":325},"get",[44,477,478],{"class":329},"(",[44,480,481],{"class":426},"'\u002Fevents'",[44,483,484],{"class":329},", ",[44,486,487],{"class":311},"async",[44,489,490],{"class":329}," (",[44,492,494],{"class":493},"s4XuR","req",[44,496,484],{"class":329},[44,498,499],{"class":493},"res",[44,501,502],{"class":329},") ",[44,504,505],{"class":311},"=>",[44,507,508],{"class":329}," {\n",[44,510,511,514,517,519,522,525,528,530,533],{"class":46,"line":59},[44,512,513],{"class":311},"  const",[44,515,516],{"class":315}," events",[44,518,319],{"class":311},[44,520,521],{"class":311}," await",[44,523,524],{"class":329}," db.",[44,526,527],{"class":325},"query",[44,529,478],{"class":329},[44,531,532],{"class":426},"'SELECT * FROM events'",[44,534,80],{"class":329},[44,536,537],{"class":46,"line":65},[44,538,539],{"class":305},"  \u002F\u002F Send UTC timestamps — the client converts to local time\n",[44,541,542,545,548],{"class":46,"line":71},[44,543,544],{"class":329},"  res.",[44,546,547],{"class":325},"json",[44,549,550],{"class":329},"(events);\n",[44,552,553],{"class":46,"line":77},[44,554,450],{"class":329},[44,556,557],{"class":46,"line":83},[44,558,87],{"emptyLinePlaceholder":86},[44,560,561],{"class":46,"line":90},[44,562,563],{"class":305},"\u002F\u002F Client: display in user's timezone\n",[44,565,566,569,572,574,577],{"class":46,"line":96},[44,567,568],{"class":311},"function",[44,570,571],{"class":325}," formatEventTime",[44,573,478],{"class":329},[44,575,576],{"class":493},"utcISO",[44,578,579],{"class":329},") {\n",[44,581,582,585,587,589,592,595,597,600],{"class":46,"line":102},[44,583,584],{"class":311},"  return",[44,586,322],{"class":311},[44,588,326],{"class":325},[44,590,591],{"class":329},"(utcISO).",[44,593,594],{"class":325},"toLocaleString",[44,596,478],{"class":329},[44,598,599],{"class":426},"'en-US'",[44,601,602],{"class":329},", {\n",[44,604,605,608,611,614,617],{"class":46,"line":441},[44,606,607],{"class":329},"    timeZone: Intl.",[44,609,610],{"class":325},"DateTimeFormat",[44,612,613],{"class":329},"().",[44,615,616],{"class":325},"resolvedOptions",[44,618,619],{"class":329},"().timeZone,\n",[44,621,622,625,628],{"class":46,"line":447},[44,623,624],{"class":329},"    dateStyle: ",[44,626,627],{"class":426},"'medium'",[44,629,430],{"class":329},[44,631,633,636,639],{"class":46,"line":632},13,[44,634,635],{"class":329},"    timeStyle: ",[44,637,638],{"class":426},"'short'",[44,640,430],{"class":329},[44,642,644],{"class":46,"line":643},14,[44,645,646],{"class":329},"  });\n",[44,648,650],{"class":46,"line":649},15,[44,651,652],{"class":329},"}\n",[10,654,230],{"id":655},"timezone-aware-queries",[26,657,659],{"id":658},"filtering-by-today-in-a-users-timezone","Filtering by \"Today\" in a User's Timezone",[15,661,662],{},"A common query is \"show me all events from today.\" If your database stores UTC, you must compute the UTC boundaries for the user's local day:",[34,664,666],{"className":36,"code":665,"language":38,"meta":39,"style":39},"-- Events on May 28, 2024 in America\u002FNew_York (UTC-4)\nSELECT * FROM events\nWHERE created_at >= '2024-05-28 04:00:00'  -- midnight EDT = 04:00 UTC\n  AND created_at \u003C  '2024-05-29 04:00:00'; -- next midnight EDT\n",[41,667,668,673,678,683],{"__ignoreMap":39},[44,669,670],{"class":46,"line":47},[44,671,672],{},"-- Events on May 28, 2024 in America\u002FNew_York (UTC-4)\n",[44,674,675],{"class":46,"line":53},[44,676,677],{},"SELECT * FROM events\n",[44,679,680],{"class":46,"line":59},[44,681,682],{},"WHERE created_at >= '2024-05-28 04:00:00'  -- midnight EDT = 04:00 UTC\n",[44,684,685],{"class":46,"line":65},[44,686,687],{},"  AND created_at \u003C  '2024-05-29 04:00:00'; -- next midnight EDT\n",[34,689,691],{"className":296,"code":690,"language":298,"meta":39,"style":39},"\u002F\u002F Compute UTC boundaries in application code\nfunction getDayBoundaries(date, timezone) {\n  const start = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));\n  const utcStart = new Date(start.toLocaleString('en-US', { timeZone: timezone }));\n  const offset = start - utcStart; \u002F\u002F timezone offset in ms\n  return {\n    start: new Date(start.getTime() + offset),\n    end: new Date(start.getTime() + offset + 86400000),\n  };\n}\n",[41,692,693,698,717,756,781,802,808,830,858,863],{"__ignoreMap":39},[44,694,695],{"class":46,"line":47},[44,696,697],{"class":305},"\u002F\u002F Compute UTC boundaries in application code\n",[44,699,700,702,705,707,710,712,715],{"class":46,"line":53},[44,701,568],{"class":311},[44,703,704],{"class":325}," getDayBoundaries",[44,706,478],{"class":329},[44,708,709],{"class":493},"date",[44,711,484],{"class":329},[44,713,714],{"class":493},"timezone",[44,716,579],{"class":329},[44,718,719,721,724,726,728,730,733,736,739,742,745,748,750,753],{"class":46,"line":59},[44,720,513],{"class":311},[44,722,723],{"class":315}," start",[44,725,319],{"class":311},[44,727,322],{"class":311},[44,729,326],{"class":325},[44,731,732],{"class":329},"(Date.",[44,734,735],{"class":325},"UTC",[44,737,738],{"class":329},"(date.",[44,740,741],{"class":325},"getFullYear",[44,743,744],{"class":329},"(), date.",[44,746,747],{"class":325},"getMonth",[44,749,744],{"class":329},[44,751,752],{"class":325},"getDate",[44,754,755],{"class":329},"()));\n",[44,757,758,760,763,765,767,769,772,774,776,778],{"class":46,"line":65},[44,759,513],{"class":311},[44,761,762],{"class":315}," utcStart",[44,764,319],{"class":311},[44,766,322],{"class":311},[44,768,326],{"class":325},[44,770,771],{"class":329},"(start.",[44,773,594],{"class":325},[44,775,478],{"class":329},[44,777,599],{"class":426},[44,779,780],{"class":329},", { timeZone: timezone }));\n",[44,782,783,785,788,790,793,796,799],{"class":46,"line":71},[44,784,513],{"class":311},[44,786,787],{"class":315}," offset",[44,789,319],{"class":311},[44,791,792],{"class":329}," start ",[44,794,795],{"class":311},"-",[44,797,798],{"class":329}," utcStart; ",[44,800,801],{"class":305},"\u002F\u002F timezone offset in ms\n",[44,803,804,806],{"class":46,"line":77},[44,805,584],{"class":311},[44,807,508],{"class":329},[44,809,810,813,816,818,820,822,824,827],{"class":46,"line":83},[44,811,812],{"class":329},"    start: ",[44,814,815],{"class":311},"new",[44,817,326],{"class":325},[44,819,771],{"class":329},[44,821,375],{"class":325},[44,823,378],{"class":329},[44,825,826],{"class":311},"+",[44,828,829],{"class":329}," offset),\n",[44,831,832,835,837,839,841,843,845,847,850,852,855],{"class":46,"line":90},[44,833,834],{"class":329},"    end: ",[44,836,815],{"class":311},[44,838,326],{"class":325},[44,840,771],{"class":329},[44,842,375],{"class":325},[44,844,378],{"class":329},[44,846,826],{"class":311},[44,848,849],{"class":329}," offset ",[44,851,826],{"class":311},[44,853,854],{"class":315}," 86400000",[44,856,857],{"class":329},"),\n",[44,859,860],{"class":46,"line":96},[44,861,862],{"class":329},"  };\n",[44,864,865],{"class":46,"line":102},[44,866,652],{"class":329},[26,868,870],{"id":869},"dst-transitions","DST Transitions",[15,872,873,874,877,878,484,881,884,885,888],{},"Daylight Saving Time complicates offset calculations. A timezone like ",[41,875,876],{},"America\u002FNew_York"," shifts between UTC-5 and UTC-4. Always use a timezone library (like ",[41,879,880],{},"luxon",[41,882,883],{},"date-fns-tz",", or ",[41,886,887],{},"moment-timezone",") rather than hardcoding offsets:",[34,890,892],{"className":296,"code":891,"language":298,"meta":39,"style":39},"const { DateTime } = require('luxon');\n\n\u002F\u002F Correct: library handles DST\nconst localTime = DateTime.fromISO('2024-03-10T02:30:00', { zone: 'America\u002FNew_York' });\n\u002F\u002F This time doesn't exist — clocks jump from 2:00 to 3:00 AM\n\u002F\u002F Luxon handles it by default (adjusts forward)\n",[41,893,894,920,924,929,958,963],{"__ignoreMap":39},[44,895,896,898,901,904,907,910,913,915,918],{"class":46,"line":47},[44,897,312],{"class":311},[44,899,900],{"class":329}," { ",[44,902,903],{"class":315},"DateTime",[44,905,906],{"class":329}," } ",[44,908,909],{"class":311},"=",[44,911,912],{"class":325}," require",[44,914,478],{"class":329},[44,916,917],{"class":426},"'luxon'",[44,919,80],{"class":329},[44,921,922],{"class":46,"line":53},[44,923,87],{"emptyLinePlaceholder":86},[44,925,926],{"class":46,"line":59},[44,927,928],{"class":305},"\u002F\u002F Correct: library handles DST\n",[44,930,931,933,936,938,941,944,946,949,952,955],{"class":46,"line":65},[44,932,312],{"class":311},[44,934,935],{"class":315}," localTime",[44,937,319],{"class":311},[44,939,940],{"class":329}," DateTime.",[44,942,943],{"class":325},"fromISO",[44,945,478],{"class":329},[44,947,948],{"class":426},"'2024-03-10T02:30:00'",[44,950,951],{"class":329},", { zone: ",[44,953,954],{"class":426},"'America\u002FNew_York'",[44,956,957],{"class":329}," });\n",[44,959,960],{"class":46,"line":71},[44,961,962],{"class":305},"\u002F\u002F This time doesn't exist — clocks jump from 2:00 to 3:00 AM\n",[44,964,965],{"class":46,"line":77},[44,966,967],{"class":305},"\u002F\u002F Luxon handles it by default (adjusts forward)\n",[10,969,971],{"id":970},"common-mistakes","Common Mistakes",[26,973,975],{"id":974},"storing-local-time-without-timezone","Storing Local Time Without Timezone",[34,977,979],{"className":36,"code":978,"language":38,"meta":39,"style":39},"-- Danger: no timezone info — ambiguous during DST transitions\nINSERT INTO events (created_at) VALUES ('2024-07-15 14:30:00');\n-- Is this 14:30 EDT or 14:30 UTC? The database doesn't know.\n",[41,980,981,986,991],{"__ignoreMap":39},[44,982,983],{"class":46,"line":47},[44,984,985],{},"-- Danger: no timezone info — ambiguous during DST transitions\n",[44,987,988],{"class":46,"line":53},[44,989,990],{},"INSERT INTO events (created_at) VALUES ('2024-07-15 14:30:00');\n",[44,992,993],{"class":46,"line":59},[44,994,995],{},"-- Is this 14:30 EDT or 14:30 UTC? The database doesn't know.\n",[26,997,999],{"id":998},"using-current_timestamp-without-understanding-it","Using CURRENT_TIMESTAMP Without Understanding It",[15,1001,1002,1003,1006],{},"In PostgreSQL, ",[41,1004,1005],{},"CURRENT_TIMESTAMP"," returns the current time in the session's timezone. If the session timezone is misconfigured, your inserts silently use the wrong offset.",[26,1008,1010],{"id":1009},"comparing-timestamp-and-timestamptz-columns","Comparing TIMESTAMP and TIMESTAMPTZ Columns",[15,1012,1013],{},"Mixing these column types in queries produces confusing results because PostgreSQL silently converts between them using the session timezone.",[10,1015,1017],{"id":1016},"key-takeaways","Key Takeaways",[1019,1020,1021,1032,1035,1041,1044,1047],"ul",{},[1022,1023,1024,1025,1027,1028,1031],"li",{},"Store all timestamps in UTC — either as ",[41,1026,122],{},", ISO 8601 strings with ",[41,1029,1030],{},"Z",", or Unix epoch integers",[1022,1033,1034],{},"Convert to local time only at the display layer, never in the database or API layer",[1022,1036,1037,1038,1040],{},"Use ",[41,1039,122],{}," in PostgreSQL for automatic UTC conversion on input",[1022,1042,1043],{},"Compute timezone boundaries in application code when filtering by \"today\" or date ranges",[1022,1045,1046],{},"Always use a timezone library for DST-aware calculations rather than hardcoded offsets",[1022,1048,1049],{},"Never store local time without an offset — it becomes ambiguous during DST transitions",[10,1051,1053],{"id":1052},"try-it-yourself","Try It Yourself",[15,1055,1056,1057,1062],{},"Convert timestamps between UTC, local time, and different timezone formats with our free ",[1058,1059,1061],"a",{"href":1060},"\u002Ftools\u002Ftimestamp-converter","Timestamp Converter",". Supports ISO 8601, Unix epoch, and custom formats — all processed locally in your browser.",[15,1064,1065],{},[1058,1066,1067],{"href":1060},"Try the Timestamp Converter →",[1069,1070,1071],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":39,"searchDepth":53,"depth":53,"links":1073},[1074,1075,1080,1084,1088,1093,1094],{"id":12,"depth":53,"text":13},{"id":23,"depth":53,"text":24,"children":1076},[1077,1078,1079],{"id":28,"depth":59,"text":29},{"id":115,"depth":59,"text":116},{"id":210,"depth":59,"text":211},{"id":285,"depth":53,"text":286,"children":1081},[1082,1083],{"id":289,"depth":59,"text":290},{"id":453,"depth":59,"text":454},{"id":655,"depth":53,"text":230,"children":1085},[1086,1087],{"id":658,"depth":59,"text":659},{"id":869,"depth":59,"text":870},{"id":970,"depth":53,"text":971,"children":1089},[1090,1091,1092],{"id":974,"depth":59,"text":975},{"id":998,"depth":59,"text":999},{"id":1009,"depth":59,"text":1010},{"id":1016,"depth":53,"text":1017},{"id":1052,"depth":53,"text":1053},"2026-05-28","Learn how to store and query timestamps with proper timezone handling. Compare UTC storage, timestamptz columns, and timezone-aware queries.","md",{"immutable":86},"\u002Fguides\u002Ftimezone-database-timestamps",{"title":5,"description":1096},"guides\u002Ftimezone-database-timestamps","GPdVKH265HxfVJuncwu0Ur0ZPu3mOK6VSEQFtadD4wk",1780401337579]