[{"data":1,"prerenderedAt":716},["ShallowReactive",2],{"guide-datetime-programming-tips":3},{"id":4,"title":5,"body":6,"date":708,"description":709,"extension":710,"meta":711,"navigation":59,"path":712,"readingTime":134,"seo":713,"stem":714,"__hash__":715},"guides\u002Fguides\u002Fdatetime-programming-tips.md","DateTime Programming Tips: Common Pitfalls and Solutions",{"type":7,"value":8,"toc":685},"minimark",[9,14,18,21,25,30,73,80,84,158,169,173,177,180,188,194,198,205,232,237,241,247,252,256,259,265,268,281,285,371,377,381,385,417,421,424,438,442,463,467,583,597,601,644,648,669,673,681],[10,11,13],"h2",{"id":12},"datetime-bugs-are-silent-killers","DateTime Bugs Are Silent Killers",[15,16,17],"p",{},"DateTime errors rarely crash your app. Instead, they produce wrong data — scheduled emails sent at the wrong hour, expired tokens that still work, reports covering the wrong date range. These bugs are hard to catch in testing and expensive to fix in production.",[15,19,20],{},"Here are the most common pitfalls and how to avoid them.",[10,22,24],{"id":23},"time-zone-pitfalls","Time Zone Pitfalls",[26,27,29],"h3",{"id":28},"pitfall-storing-local-time","Pitfall: Storing Local Time",[31,32,37],"pre",{"className":33,"code":34,"language":35,"meta":36,"style":36},"language-python shiki shiki-themes github-light github-dark","# BAD — what timezone is this?\nevent_time = \"2025-05-26 14:00:00\"\n\n# GOOD — always store in UTC\nevent_time = \"2025-05-26T18:00:00Z\"  # 2 PM EDT = 6 PM UTC\n","python","",[38,39,40,48,54,61,67],"code",{"__ignoreMap":36},[41,42,45],"span",{"class":43,"line":44},"line",1,[41,46,47],{},"# BAD — what timezone is this?\n",[41,49,51],{"class":43,"line":50},2,[41,52,53],{},"event_time = \"2025-05-26 14:00:00\"\n",[41,55,57],{"class":43,"line":56},3,[41,58,60],{"emptyLinePlaceholder":59},true,"\n",[41,62,64],{"class":43,"line":63},4,[41,65,66],{},"# GOOD — always store in UTC\n",[41,68,70],{"class":43,"line":69},5,[41,71,72],{},"event_time = \"2025-05-26T18:00:00Z\"  # 2 PM EDT = 6 PM UTC\n",[15,74,75,79],{},[76,77,78],"strong",{},"Rule:"," Store every timestamp in UTC. Convert to local time only when rendering to users. This eliminates ambiguity and makes arithmetic consistent.",[26,81,83],{"id":82},"pitfall-ignoring-offset-in-parsing","Pitfall: Ignoring Offset in Parsing",[31,85,89],{"className":86,"code":87,"language":88,"meta":36,"style":36},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F BAD — interprets as local time\nnew Date(\"2025-05-26T14:00:00\")\n\u002F\u002F In New York: May 26, 10:00 AM EDT\n\u002F\u002F In Tokyo: May 26, 11:00 PM JST\n\n\u002F\u002F GOOD — explicit UTC\nnew Date(\"2025-05-26T14:00:00Z\")\n\u002F\u002F Everywhere: May 26, 2:00 PM UTC\n","javascript",[38,90,91,97,118,123,128,132,138,152],{"__ignoreMap":36},[41,92,93],{"class":43,"line":44},[41,94,96],{"class":95},"sJ8bj","\u002F\u002F BAD — interprets as local time\n",[41,98,99,103,107,111,115],{"class":43,"line":50},[41,100,102],{"class":101},"szBVR","new",[41,104,106],{"class":105},"sScJk"," Date",[41,108,110],{"class":109},"sVt8B","(",[41,112,114],{"class":113},"sZZnC","\"2025-05-26T14:00:00\"",[41,116,117],{"class":109},")\n",[41,119,120],{"class":43,"line":56},[41,121,122],{"class":95},"\u002F\u002F In New York: May 26, 10:00 AM EDT\n",[41,124,125],{"class":43,"line":63},[41,126,127],{"class":95},"\u002F\u002F In Tokyo: May 26, 11:00 PM JST\n",[41,129,130],{"class":43,"line":69},[41,131,60],{"emptyLinePlaceholder":59},[41,133,135],{"class":43,"line":134},6,[41,136,137],{"class":95},"\u002F\u002F GOOD — explicit UTC\n",[41,139,141,143,145,147,150],{"class":43,"line":140},7,[41,142,102],{"class":101},[41,144,106],{"class":105},[41,146,110],{"class":109},[41,148,149],{"class":113},"\"2025-05-26T14:00:00Z\"",[41,151,117],{"class":109},[41,153,155],{"class":43,"line":154},8,[41,156,157],{"class":95},"\u002F\u002F Everywhere: May 26, 2:00 PM UTC\n",[15,159,160,161,164,165,168],{},"A timestamp string without a timezone offset means different things in different environments. Always include ",[38,162,163],{},"Z"," or an offset like ",[38,166,167],{},"+05:30",".",[10,170,172],{"id":171},"daylight-saving-time-issues","Daylight Saving Time Issues",[26,174,176],{"id":175},"the-ambiguous-hour","The Ambiguous Hour",[15,178,179],{},"When clocks fall back (e.g., 2:00 AM → 1:00 AM in autumn), the same local time occurs twice. Which one did the user mean?",[31,181,186],{"className":182,"code":184,"language":185,"meta":36},[183],"language-text","2025-11-02 01:30:00 (first occurrence, EDT)\n2025-11-02 01:30:00 (second occurrence, EST)\n","text",[38,187,184],{"__ignoreMap":36},[15,189,190,193],{},[76,191,192],{},"Solution:"," Use UTC internally. If you must accept local time, ask for the offset or use a timezone-aware library.",[26,195,197],{"id":196},"the-missing-hour","The Missing Hour",[15,199,200,201,204],{},"When clocks spring forward (e.g., 2:00 AM → 3:00 AM in spring), ",[38,202,203],{},"2:30 AM"," never exists.",[31,206,208],{"className":86,"code":207,"language":88,"meta":36,"style":36},"\u002F\u002F In EDT→EST transition zones:\nnew Date(\"2025-03-09T02:30:00\")  \u002F\u002F jumps to 3:30 AM\n",[38,209,210,215],{"__ignoreMap":36},[41,211,212],{"class":43,"line":44},[41,213,214],{"class":95},"\u002F\u002F In EDT→EST transition zones:\n",[41,216,217,219,221,223,226,229],{"class":43,"line":50},[41,218,102],{"class":101},[41,220,106],{"class":105},[41,222,110],{"class":109},[41,224,225],{"class":113},"\"2025-03-09T02:30:00\"",[41,227,228],{"class":109},")  ",[41,230,231],{"class":95},"\u002F\u002F jumps to 3:30 AM\n",[15,233,234,236],{},[76,235,192],{}," Validate user-provided local times against DST transitions. Alert the user when a time does not exist.",[26,238,240],{"id":239},"duration-calculations-across-dst","Duration Calculations Across DST",[31,242,245],{"className":243,"code":244,"language":185,"meta":36},[183],"Nov 1, 2025 1:00 AM EDT → Nov 2, 2025 1:00 AM EST\nElapsed: 25 hours (not 24)\n",[38,246,244],{"__ignoreMap":36},[15,248,249,251],{},[76,250,192],{}," Calculate durations in UTC or use wall-clock libraries that account for DST.",[10,253,255],{"id":254},"leap-seconds","Leap Seconds",[15,257,258],{},"Leap seconds add or remove one second from UTC to keep it aligned with Earth's rotation. There have been 27 leap seconds since 1972.",[31,260,263],{"className":261,"code":262,"language":185,"meta":36},[183],"2016-12-31T23:59:60Z  ← a valid UTC time\n",[38,264,262],{"__ignoreMap":36},[15,266,267],{},"Most software ignores leap seconds. Unix timestamps skip them — each day is always 86400 seconds. This means:",[269,270,271,275,278],"ul",{},[272,273,274],"li",{},"Sub-second-precision applications may drift",[272,276,277],{},"High-frequency trading and scientific software must handle them explicitly",[272,279,280],{},"Web applications can usually ignore leap seconds safely",[10,282,284],{"id":283},"serialization-best-practices","Serialization Best Practices",[286,287,288,304],"table",{},[289,290,291],"thead",{},[292,293,294,298,301],"tr",{},[295,296,297],"th",{},"Guideline",[295,299,300],{},"Do",[295,302,303],{},"Don't",[305,306,307,319,330,345,360],"tbody",{},[292,308,309,313,316],{},[310,311,312],"td",{},"API payloads",[310,314,315],{},"Use ISO 8601 with offset",[310,317,318],{},"Send local time without offset",[292,320,321,324,327],{},[310,322,323],{},"Databases",[310,325,326],{},"Store as UTC timestamp or timestamptz",[310,328,329],{},"Store as local time without zone",[292,331,332,335,340],{},[310,333,334],{},"JSON",[310,336,337],{},[38,338,339],{},"\"2025-05-26T18:00:00Z\"",[310,341,342],{},[38,343,344],{},"\"05\u002F26\u002F2025 6:00 PM\"",[292,346,347,350,355],{},[310,348,349],{},"Filenames & logs",[310,351,352],{},[38,353,354],{},"2025-05-26T18-00-00Z.log",[310,356,357],{},[38,358,359],{},"May 26th.log",[292,361,362,365,368],{},[310,363,364],{},"User-facing",[310,366,367],{},"Convert to local format at render",[310,369,370],{},"Show raw UTC to users",[15,372,373,376],{},[76,374,375],{},"Consistency wins."," Pick one format, document it, and enforce it across your entire stack.",[10,378,380],{"id":379},"testing-strategies","Testing Strategies",[26,382,384],{"id":383},"freeze-time-in-tests","Freeze Time in Tests",[31,386,388],{"className":86,"code":387,"language":88,"meta":36,"style":36},"\u002F\u002F Use a mock or library to set a fixed \"now\"\nvi.setSystemTime(new Date(\"2025-05-26T12:00:00Z\"))\n",[38,389,390,395],{"__ignoreMap":36},[41,391,392],{"class":43,"line":44},[41,393,394],{"class":95},"\u002F\u002F Use a mock or library to set a fixed \"now\"\n",[41,396,397,400,403,405,407,409,411,414],{"class":43,"line":50},[41,398,399],{"class":109},"vi.",[41,401,402],{"class":105},"setSystemTime",[41,404,110],{"class":109},[41,406,102],{"class":101},[41,408,106],{"class":105},[41,410,110],{"class":109},[41,412,413],{"class":113},"\"2025-05-26T12:00:00Z\"",[41,415,416],{"class":109},"))\n",[26,418,420],{"id":419},"test-dst-boundaries","Test DST Boundaries",[15,422,423],{},"Write tests for:",[269,425,426,429,432,435],{},[272,427,428],{},"Times during the spring-forward gap",[272,430,431],{},"Times during the fall-back overlap",[272,433,434],{},"Midnight crossing in different time zones",[272,436,437],{},"Week-long calculations that span a DST change",[26,439,441],{"id":440},"test-edge-cases","Test Edge Cases",[269,443,444,447,450,457,460],{},[272,445,446],{},"February 29 (leap year)",[272,448,449],{},"December 31 → January 1 (year boundary)",[272,451,452,453,456],{},"Timestamp ",[38,454,455],{},"0"," (Unix epoch)",[272,458,459],{},"Very large timestamps (beyond 2038)",[272,461,462],{},"Negative timestamps (before 1970)",[10,464,466],{"id":465},"recommended-libraries","Recommended Libraries",[286,468,469,482],{},[289,470,471],{},[292,472,473,476,479],{},[295,474,475],{},"Language",[295,477,478],{},"Library",[295,480,481],{},"Why",[305,483,484,497,509,526,540,554,570],{},[292,485,486,489,494],{},[310,487,488],{},"JavaScript",[310,490,491],{},[38,492,493],{},"date-fns",[310,495,496],{},"Modular, tree-shakable, immutable",[292,498,499,501,506],{},[310,500,488],{},[310,502,503],{},[38,504,505],{},"dayjs",[310,507,508],{},"Lightweight, moment-compatible API",[292,510,511,514,523],{},[310,512,513],{},"Python",[310,515,516,519,520],{},[38,517,518],{},"zoneinfo"," + ",[38,521,522],{},"datetime",[310,524,525],{},"Built-in, no extra dependency",[292,527,528,531,537],{},[310,529,530],{},"Go",[310,532,533,536],{},[38,534,535],{},"time"," package",[310,538,539],{},"Stdlib, handles zones and parsing",[292,541,542,545,551],{},[310,543,544],{},"Java",[310,546,547,550],{},[38,548,549],{},"java.time"," (JSR 310)",[310,552,553],{},"Modern, immutable, timezone-aware",[292,555,556,559,567],{},[310,557,558],{},"Ruby",[310,560,561,519,564],{},[38,562,563],{},"TZInfo",[38,565,566],{},"Time",[310,568,569],{},"Full IANA timezone database",[292,571,572,575,580],{},[310,573,574],{},"PHP",[310,576,577],{},[38,578,579],{},"DateTimeImmutable",[310,581,582],{},"Built-in, handles DST correctly",[15,584,585,586,589,590,593,594,596],{},"Avoid: ",[38,587,588],{},"moment.js"," (deprecated), Python ",[38,591,592],{},"pytz"," (replaced by ",[38,595,518],{},"), any library that mutates objects in place.",[10,598,600],{"id":599},"quick-checklist","Quick Checklist",[269,602,605,614,620,626,632,638],{"className":603},[604],"contains-task-list",[272,606,609,613],{"className":607},[608],"task-list-item",[610,611],"input",{"disabled":59,"type":612},"checkbox"," All timestamps stored in UTC",[272,615,617,619],{"className":616},[608],[610,618],{"disabled":59,"type":612}," API responses include timezone offsets",[272,621,623,625],{"className":622},[608],[610,624],{"disabled":59,"type":612}," DST transitions handled in scheduling logic",[272,627,629,631],{"className":628},[608],[610,630],{"disabled":59,"type":612}," Duration calculations use UTC, not local time",[272,633,635,637],{"className":634},[608],[610,636],{"disabled":59,"type":612}," Tests cover timezone boundaries and leap years",[272,639,641,643],{"className":640},[608],[610,642],{"disabled":59,"type":612}," No deprecated datetime libraries in dependencies",[10,645,647],{"id":646},"related-guides","Related Guides",[269,649,650,657,663],{},[272,651,652],{},[653,654,656],"a",{"href":655},"\u002Fguides\u002Funix-timestamp-guide","Unix Timestamp Explained",[272,658,659],{},[653,660,662],{"href":661},"\u002Fguides\u002Ftimestamp-formats-explained","Timestamp Formats Explained",[272,664,665],{},[653,666,668],{"href":667},"\u002Fguides\u002Fcommon-cron-schedules","Common Cron Schedules",[10,670,672],{"id":671},"try-it-yourself","Try It Yourself",[15,674,675,676,680],{},"Use our free ",[653,677,679],{"href":678},"\u002Ftools\u002Ftimestamp-converter","Timestamp Converter"," to verify your timestamp conversions and catch timezone issues before they reach production.",[682,683,684],"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 .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}",{"title":36,"searchDepth":50,"depth":50,"links":686},[687,688,692,697,698,699,704,705,706,707],{"id":12,"depth":50,"text":13},{"id":23,"depth":50,"text":24,"children":689},[690,691],{"id":28,"depth":56,"text":29},{"id":82,"depth":56,"text":83},{"id":171,"depth":50,"text":172,"children":693},[694,695,696],{"id":175,"depth":56,"text":176},{"id":196,"depth":56,"text":197},{"id":239,"depth":56,"text":240},{"id":254,"depth":50,"text":255},{"id":283,"depth":50,"text":284},{"id":379,"depth":50,"text":380,"children":700},[701,702,703],{"id":383,"depth":56,"text":384},{"id":419,"depth":56,"text":420},{"id":440,"depth":56,"text":441},{"id":465,"depth":50,"text":466},{"id":599,"depth":50,"text":600},{"id":646,"depth":50,"text":647},{"id":671,"depth":50,"text":672},"2026-05-27","Avoid common datetime programming mistakes. Time zones, DST, leap seconds, and best practices for reliable date handling.","md",{"immutable":59},"\u002Fguides\u002Fdatetime-programming-tips",{"title":5,"description":709},"guides\u002Fdatetime-programming-tips","U7xSkxnmT7wrambNaalq2WL76AU3lrh6DGXRhhIBJrc",1780401324864]