[{"data":1,"prerenderedAt":1065},["ShallowReactive",2],{"guide-date-arithmetic-different-languages":3},{"id":4,"title":5,"body":6,"date":1057,"description":1058,"extension":1059,"meta":1060,"navigation":133,"path":1061,"readingTime":148,"seo":1062,"stem":1063,"__hash__":1064},"guides\u002Fguides\u002Fdate-arithmetic-different-languages.md","Date Arithmetic in Different Languages",{"type":7,"value":8,"toc":1035},"minimark",[9,14,18,22,27,103,114,118,152,159,163,193,207,211,240,247,251,271,286,290,382,386,451,462,466,491,495,498,589,592,726,730,733,777,784,787,825,828,832,985,989,1018,1022,1031],[10,11,13],"h2",{"id":12},"why-date-arithmetic-is-hard","Why Date Arithmetic Is Hard",[15,16,17],"p",{},"Dates look simple — add days, subtract months, find the difference. But edge cases multiply fast: leap years, month lengths, daylight saving transitions, and time zone offsets all introduce complexity. Every language handles these differently.",[10,19,21],{"id":20},"adding-days-to-a-date","Adding Days to a Date",[23,24,26],"h3",{"id":25},"javascript","JavaScript",[28,29,33],"pre",{"className":30,"code":31,"language":25,"meta":32,"style":32},"language-javascript shiki shiki-themes github-light github-dark","const date = new Date('2026-01-15');\ndate.setDate(date.getDate() + 30);\n\u002F\u002F 2026-02-14 — handles month rollover automatically\n","",[34,35,36,70,96],"code",{"__ignoreMap":32},[37,38,41,45,49,52,55,59,63,67],"span",{"class":39,"line":40},"line",1,[37,42,44],{"class":43},"szBVR","const",[37,46,48],{"class":47},"sj4cs"," date",[37,50,51],{"class":43}," =",[37,53,54],{"class":43}," new",[37,56,58],{"class":57},"sScJk"," Date",[37,60,62],{"class":61},"sVt8B","(",[37,64,66],{"class":65},"sZZnC","'2026-01-15'",[37,68,69],{"class":61},");\n",[37,71,73,76,79,82,85,88,91,94],{"class":39,"line":72},2,[37,74,75],{"class":61},"date.",[37,77,78],{"class":57},"setDate",[37,80,81],{"class":61},"(date.",[37,83,84],{"class":57},"getDate",[37,86,87],{"class":61},"() ",[37,89,90],{"class":43},"+",[37,92,93],{"class":47}," 30",[37,95,69],{"class":61},[37,97,99],{"class":39,"line":98},3,[37,100,102],{"class":101},"sJ8bj","\u002F\u002F 2026-02-14 — handles month rollover automatically\n",[15,104,105,106,109,110,113],{},"JavaScript's ",[34,107,108],{},"Date"," mutates in place and auto-normalizes overflow. ",[34,111,112],{},"setDate(35)"," on January silently becomes February 4.",[23,115,117],{"id":116},"python","Python",[28,119,122],{"className":120,"code":121,"language":116,"meta":32,"style":32},"language-python shiki shiki-themes github-light github-dark","from datetime import date, timedelta\n\nd = date(2026, 1, 15)\nresult = d + timedelta(days=30)\n# datetime.date(2026, 2, 14)\n",[34,123,124,129,135,140,146],{"__ignoreMap":32},[37,125,126],{"class":39,"line":40},[37,127,128],{},"from datetime import date, timedelta\n",[37,130,131],{"class":39,"line":72},[37,132,134],{"emptyLinePlaceholder":133},true,"\n",[37,136,137],{"class":39,"line":98},[37,138,139],{},"d = date(2026, 1, 15)\n",[37,141,143],{"class":39,"line":142},4,[37,144,145],{},"result = d + timedelta(days=30)\n",[37,147,149],{"class":39,"line":148},5,[37,150,151],{},"# datetime.date(2026, 2, 14)\n",[15,153,154,155,158],{},"Python's ",[34,156,157],{},"timedelta"," is explicit and immutable — the original date is never modified.",[23,160,162],{"id":161},"java","Java",[28,164,167],{"className":165,"code":166,"language":161,"meta":32,"style":32},"language-java shiki shiki-themes github-light github-dark","import java.time.LocalDate;\n\nLocalDate date = LocalDate.of(2026, 1, 15);\nLocalDate result = date.plusDays(30);\n\u002F\u002F 2026-02-14\n",[34,168,169,174,178,183,188],{"__ignoreMap":32},[37,170,171],{"class":39,"line":40},[37,172,173],{},"import java.time.LocalDate;\n",[37,175,176],{"class":39,"line":72},[37,177,134],{"emptyLinePlaceholder":133},[37,179,180],{"class":39,"line":98},[37,181,182],{},"LocalDate date = LocalDate.of(2026, 1, 15);\n",[37,184,185],{"class":39,"line":142},[37,186,187],{},"LocalDate result = date.plusDays(30);\n",[37,189,190],{"class":39,"line":148},[37,191,192],{},"\u002F\u002F 2026-02-14\n",[15,194,195,196,199,200,202,203,206],{},"Java 8+ ",[34,197,198],{},"java.time"," is immutable and fluent. Avoid the legacy ",[34,201,108],{}," and ",[34,204,205],{},"Calendar"," classes.",[23,208,210],{"id":209},"go","Go",[28,212,215],{"className":213,"code":214,"language":209,"meta":32,"style":32},"language-go shiki shiki-themes github-light github-dark","import \"time\"\n\ndate := time.Date(2026, 1, 15, 0, 0, 0, 0, time.UTC)\nresult := date.AddDate(0, 0, 30)\n\u002F\u002F 2026-02-14\n",[34,216,217,222,226,231,236],{"__ignoreMap":32},[37,218,219],{"class":39,"line":40},[37,220,221],{},"import \"time\"\n",[37,223,224],{"class":39,"line":72},[37,225,134],{"emptyLinePlaceholder":133},[37,227,228],{"class":39,"line":98},[37,229,230],{},"date := time.Date(2026, 1, 15, 0, 0, 0, 0, time.UTC)\n",[37,232,233],{"class":39,"line":142},[37,234,235],{},"result := date.AddDate(0, 0, 30)\n",[37,237,238],{"class":39,"line":148},[37,239,192],{},[15,241,242,243,246],{},"Go's ",[34,244,245],{},"AddDate"," takes years, months, days — making complex offsets straightforward.",[23,248,250],{"id":249},"php","PHP",[28,252,255],{"className":253,"code":254,"language":249,"meta":32,"style":32},"language-php shiki shiki-themes github-light github-dark","$date = new DateTime('2026-01-15');\n$date->modify('+30 days');\n\u002F\u002F 2026-02-14\n",[34,256,257,262,267],{"__ignoreMap":32},[37,258,259],{"class":39,"line":40},[37,260,261],{},"$date = new DateTime('2026-01-15');\n",[37,263,264],{"class":39,"line":72},[37,265,266],{},"$date->modify('+30 days');\n",[37,268,269],{"class":39,"line":98},[37,270,192],{},[15,272,273,274,277,278,281,282,285],{},"PHP's ",[34,275,276],{},"modify"," accepts natural language strings like ",[34,279,280],{},"\"+1 month\""," or ",[34,283,284],{},"\"next Tuesday\"",".",[10,287,289],{"id":288},"calculating-the-difference-between-dates","Calculating the Difference Between Dates",[291,292,293,309],"table",{},[294,295,296],"thead",{},[297,298,299,303,306],"tr",{},[300,301,302],"th",{},"Language",[300,304,305],{},"Code",[300,307,308],{},"Returns",[310,311,312,325,338,353,368],"tbody",{},[297,313,314,317,322],{},[315,316,26],"td",{},[315,318,319],{},[34,320,321],{},"date2 - date1",[315,323,324],{},"Milliseconds",[297,326,327,329,333],{},[315,328,117],{},[315,330,331],{},[34,332,321],{},[315,334,335,337],{},[34,336,157],{}," (days, seconds)",[297,339,340,342,347],{},[315,341,162],{},[315,343,344],{},[34,345,346],{},"ChronoUnit.DAYS.between(d1, d2)",[315,348,349,352],{},[34,350,351],{},"long"," (days)",[297,354,355,357,362],{},[315,356,210],{},[315,358,359],{},[34,360,361],{},"d2.Sub(d1).Hours() \u002F 24",[315,363,364,367],{},[34,365,366],{},"float64"," (hours→days)",[297,369,370,372,377],{},[315,371,250],{},[315,373,374],{},[34,375,376],{},"$d1->diff($d2)->days",[315,378,379,352],{},[34,380,381],{},"int",[23,383,385],{"id":384},"javascript-convert-milliseconds-to-days","JavaScript — Convert Milliseconds to Days",[28,387,389],{"className":30,"code":388,"language":25,"meta":32,"style":32},"const msPerDay = 1000 * 60 * 60 * 24;\nconst days = Math.round((date2 - date1) \u002F msPerDay);\n",[34,390,391,421],{"__ignoreMap":32},[37,392,393,395,398,400,403,406,409,411,413,415,418],{"class":39,"line":40},[37,394,44],{"class":43},[37,396,397],{"class":47}," msPerDay",[37,399,51],{"class":43},[37,401,402],{"class":47}," 1000",[37,404,405],{"class":43}," *",[37,407,408],{"class":47}," 60",[37,410,405],{"class":43},[37,412,408],{"class":47},[37,414,405],{"class":43},[37,416,417],{"class":47}," 24",[37,419,420],{"class":61},";\n",[37,422,423,425,428,430,433,436,439,442,445,448],{"class":39,"line":72},[37,424,44],{"class":43},[37,426,427],{"class":47}," days",[37,429,51],{"class":43},[37,431,432],{"class":61}," Math.",[37,434,435],{"class":57},"round",[37,437,438],{"class":61},"((date2 ",[37,440,441],{"class":43},"-",[37,443,444],{"class":61}," date1) ",[37,446,447],{"class":43},"\u002F",[37,449,450],{"class":61}," msPerDay);\n",[15,452,453,454,457,458,461],{},"Use ",[34,455,456],{},"Math.round",", not ",[34,459,460],{},"Math.floor",", to handle daylight saving offsets that shift the result by an hour.",[23,463,465],{"id":464},"python-full-interval","Python — Full Interval",[28,467,469],{"className":120,"code":468,"language":116,"meta":32,"style":32},"delta = date2 - date1\nprint(delta.days)       # total days\nprint(delta.seconds)    # remaining seconds (0-86399)\nprint(delta.total_seconds())  # exact seconds as float\n",[34,470,471,476,481,486],{"__ignoreMap":32},[37,472,473],{"class":39,"line":40},[37,474,475],{},"delta = date2 - date1\n",[37,477,478],{"class":39,"line":72},[37,479,480],{},"print(delta.days)       # total days\n",[37,482,483],{"class":39,"line":98},[37,484,485],{},"print(delta.seconds)    # remaining seconds (0-86399)\n",[37,487,488],{"class":39,"line":142},[37,489,490],{},"print(delta.total_seconds())  # exact seconds as float\n",[10,492,494],{"id":493},"adding-months-the-dangerous-operation","Adding Months: The Dangerous Operation",[15,496,497],{},"Adding months is where most date bugs live. What happens when you add one month to January 31?",[291,499,500,515],{},[294,501,502],{},[297,503,504,506,509,512],{},[300,505,302],{},[300,507,508],{},"Jan 31 + 1 month",[300,510,511],{},"Result",[300,513,514],{},"Logic",[310,516,517,532,547,562,576],{},[297,518,519,521,526,529],{},[315,520,26],{},[315,522,523],{},[34,524,525],{},"setMonth(1)",[315,527,528],{},"Mar 3",[315,530,531],{},"Feb 31 → Mar 3 (overflow)",[297,533,534,536,541,544],{},[315,535,117],{},[315,537,538],{},[34,539,540],{},"replace(month=2)",[315,542,543],{},"ValueError",[315,545,546],{},"Feb 31 does not exist",[297,548,549,551,556,559],{},[315,550,162],{},[315,552,553],{},[34,554,555],{},"plusMonths(1)",[315,557,558],{},"Feb 28",[315,560,561],{},"Clamps to last day of Feb",[297,563,564,566,571,573],{},[315,565,210],{},[315,567,568],{},[34,569,570],{},"AddDate(0, 1, 0)",[315,572,528],{},[315,574,575],{},"Same overflow as JS",[297,577,578,580,585,587],{},[315,579,250],{},[315,581,582],{},[34,583,584],{},"modify('+1 month')",[315,586,528],{},[315,588,575],{},[15,590,591],{},"Only Java clamps to the month's last day by default. Other languages overflow into the next month. If you want \"end of month\" semantics, you must implement it explicitly:",[28,593,595],{"className":30,"code":594,"language":25,"meta":32,"style":32},"function addMonths(date, months) {\n  const result = new Date(date);\n  result.setMonth(result.getMonth() + months);\n  \u002F\u002F If day overflowed, clamp to last day of target month\n  if (result.getDate() !== date.getDate()) {\n    result.setDate(0); \u002F\u002F Last day of previous month\n  }\n  return result;\n}\n",[34,596,597,620,637,658,663,686,705,711,720],{"__ignoreMap":32},[37,598,599,602,605,607,611,614,617],{"class":39,"line":40},[37,600,601],{"class":43},"function",[37,603,604],{"class":57}," addMonths",[37,606,62],{"class":61},[37,608,610],{"class":609},"s4XuR","date",[37,612,613],{"class":61},", ",[37,615,616],{"class":609},"months",[37,618,619],{"class":61},") {\n",[37,621,622,625,628,630,632,634],{"class":39,"line":72},[37,623,624],{"class":43},"  const",[37,626,627],{"class":47}," result",[37,629,51],{"class":43},[37,631,54],{"class":43},[37,633,58],{"class":57},[37,635,636],{"class":61},"(date);\n",[37,638,639,642,645,648,651,653,655],{"class":39,"line":98},[37,640,641],{"class":61},"  result.",[37,643,644],{"class":57},"setMonth",[37,646,647],{"class":61},"(result.",[37,649,650],{"class":57},"getMonth",[37,652,87],{"class":61},[37,654,90],{"class":43},[37,656,657],{"class":61}," months);\n",[37,659,660],{"class":39,"line":142},[37,661,662],{"class":101},"  \u002F\u002F If day overflowed, clamp to last day of target month\n",[37,664,665,668,671,673,675,678,681,683],{"class":39,"line":148},[37,666,667],{"class":43},"  if",[37,669,670],{"class":61}," (result.",[37,672,84],{"class":57},[37,674,87],{"class":61},[37,676,677],{"class":43},"!==",[37,679,680],{"class":61}," date.",[37,682,84],{"class":57},[37,684,685],{"class":61},"()) {\n",[37,687,689,692,694,696,699,702],{"class":39,"line":688},6,[37,690,691],{"class":61},"    result.",[37,693,78],{"class":57},[37,695,62],{"class":61},[37,697,698],{"class":47},"0",[37,700,701],{"class":61},"); ",[37,703,704],{"class":101},"\u002F\u002F Last day of previous month\n",[37,706,708],{"class":39,"line":707},7,[37,709,710],{"class":61},"  }\n",[37,712,714,717],{"class":39,"line":713},8,[37,715,716],{"class":43},"  return",[37,718,719],{"class":61}," result;\n",[37,721,723],{"class":39,"line":722},9,[37,724,725],{"class":61},"}\n",[10,727,729],{"id":728},"time-zone-pitfalls","Time Zone Pitfalls",[23,731,26],{"id":732},"javascript-1",[28,734,736],{"className":30,"code":735,"language":25,"meta":32,"style":32},"\u002F\u002F These produce different dates depending on the system time zone\nnew Date('2026-01-15');        \u002F\u002F Parsed as UTC midnight\nnew Date('2026-01-15T00:00');  \u002F\u002F Parsed as local midnight\n",[34,737,738,743,760],{"__ignoreMap":32},[37,739,740],{"class":39,"line":40},[37,741,742],{"class":101},"\u002F\u002F These produce different dates depending on the system time zone\n",[37,744,745,748,750,752,754,757],{"class":39,"line":72},[37,746,747],{"class":43},"new",[37,749,58],{"class":57},[37,751,62],{"class":61},[37,753,66],{"class":65},[37,755,756],{"class":61},");        ",[37,758,759],{"class":101},"\u002F\u002F Parsed as UTC midnight\n",[37,761,762,764,766,768,771,774],{"class":39,"line":98},[37,763,747],{"class":43},[37,765,58],{"class":57},[37,767,62],{"class":61},[37,769,770],{"class":65},"'2026-01-15T00:00'",[37,772,773],{"class":61},");  ",[37,775,776],{"class":101},"\u002F\u002F Parsed as local midnight\n",[15,778,779,780,783],{},"Date-only strings (",[34,781,782],{},"YYYY-MM-DD",") are UTC. Date-time strings without a zone offset are local. This inconsistency causes bugs when servers and clients are in different zones.",[23,785,117],{"id":786},"python-1",[28,788,790],{"className":120,"code":789,"language":116,"meta":32,"style":32},"from datetime import datetime, timezone\n\n# Naive — no zone info, do NOT use for arithmetic across zones\nnaive = datetime(2026, 1, 15, 12, 0)\n\n# Aware — carries zone info\naware = datetime(2026, 1, 15, 12, 0, tzinfo=timezone.utc)\n",[34,791,792,797,801,806,811,815,820],{"__ignoreMap":32},[37,793,794],{"class":39,"line":40},[37,795,796],{},"from datetime import datetime, timezone\n",[37,798,799],{"class":39,"line":72},[37,800,134],{"emptyLinePlaceholder":133},[37,802,803],{"class":39,"line":98},[37,804,805],{},"# Naive — no zone info, do NOT use for arithmetic across zones\n",[37,807,808],{"class":39,"line":142},[37,809,810],{},"naive = datetime(2026, 1, 15, 12, 0)\n",[37,812,813],{"class":39,"line":148},[37,814,134],{"emptyLinePlaceholder":133},[37,816,817],{"class":39,"line":688},[37,818,819],{},"# Aware — carries zone info\n",[37,821,822],{"class":39,"line":707},[37,823,824],{},"aware = datetime(2026, 1, 15, 12, 0, tzinfo=timezone.utc)\n",[15,826,827],{},"Always use aware datetimes when time zones matter. Subtracting naive datetimes across DST boundaries produces incorrect intervals.",[10,829,831],{"id":830},"quick-reference-table","Quick Reference Table",[291,833,834,851],{},[294,835,836],{},[297,837,838,841,843,845,847,849],{},[300,839,840],{},"Operation",[300,842,26],{},[300,844,117],{},[300,846,162],{},[300,848,210],{},[300,850,250],{},[310,852,853,882,911,939,968],{},[297,854,855,858,862,867,872,877],{},[315,856,857],{},"Add days",[315,859,860],{},[34,861,78],{},[315,863,864],{},[34,865,866],{},"+ timedelta",[315,868,869],{},[34,870,871],{},"plusDays",[315,873,874],{},[34,875,876],{},"AddDate(0,0,n)",[315,878,879],{},[34,880,881],{},"modify('+n days')",[297,883,884,887,891,896,901,906],{},[315,885,886],{},"Add months",[315,888,889],{},[34,890,644],{},[315,892,893],{},[34,894,895],{},"replace",[315,897,898],{},[34,899,900],{},"plusMonths",[315,902,903],{},[34,904,905],{},"AddDate(0,n,0)",[315,907,908],{},[34,909,910],{},"modify('+n months')",[297,912,913,916,919,922,927,933],{},[315,914,915],{},"Difference",[315,917,918],{},"subtraction → ms",[315,920,921],{},"subtraction → timedelta",[315,923,924],{},[34,925,926],{},"ChronoUnit.DAYS.between",[315,928,929,932],{},[34,930,931],{},"Sub"," → Duration",[315,934,935,938],{},[34,936,937],{},"diff"," → DateInterval",[297,940,941,944,949,954,959,963],{},[315,942,943],{},"Format",[315,945,946],{},[34,947,948],{},"toLocaleDateString",[315,950,951],{},[34,952,953],{},"strftime",[315,955,956],{},[34,957,958],{},"DateTimeFormatter",[315,960,961],{},[34,962,943],{},[315,964,965],{},[34,966,967],{},"format",[297,969,970,973,976,979,981,983],{},[315,971,972],{},"Immutable",[315,974,975],{},"No",[315,977,978],{},"Yes",[315,980,978],{},[315,982,978],{},[315,984,975],{},[10,986,988],{"id":987},"key-takeaways","Key Takeaways",[990,991,992,999,1002,1005,1008],"ul",{},[993,994,995,996,998],"li",{},"JavaScript ",[34,997,108],{}," is mutable — all others return new objects",[993,1000,1001],{},"Adding months to day-31 dates causes overflow in most languages — Java clamps, others roll over",[993,1003,1004],{},"Date-only strings parse as UTC; date-time strings parse as local — this JavaScript inconsistency causes subtle bugs",[993,1006,1007],{},"Always use time-zone-aware objects when arithmetic crosses DST boundaries",[993,1009,1010,1011,1014,1015,1017],{},"Use built-in libraries (Python ",[34,1012,1013],{},"datetime",", Java ",[34,1016,198],{},") instead of hand-rolled date math",[10,1019,1021],{"id":1020},"try-it-yourself","Try It Yourself",[15,1023,1024,1025,1030],{},"Calculate exact age differences and date intervals with our ",[1026,1027,1029],"a",{"href":1028},"\u002Ftools\u002Fage-calculator","Age Calculator",". Enter two dates and see the precise difference in years, months, and days.",[1032,1033,1034],"style",{},"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 .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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 .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":32,"searchDepth":72,"depth":72,"links":1036},[1037,1038,1045,1049,1050,1054,1055,1056],{"id":12,"depth":72,"text":13},{"id":20,"depth":72,"text":21,"children":1039},[1040,1041,1042,1043,1044],{"id":25,"depth":98,"text":26},{"id":116,"depth":98,"text":117},{"id":161,"depth":98,"text":162},{"id":209,"depth":98,"text":210},{"id":249,"depth":98,"text":250},{"id":288,"depth":72,"text":289,"children":1046},[1047,1048],{"id":384,"depth":98,"text":385},{"id":464,"depth":98,"text":465},{"id":493,"depth":72,"text":494},{"id":728,"depth":72,"text":729,"children":1051},[1052,1053],{"id":732,"depth":98,"text":26},{"id":786,"depth":98,"text":117},{"id":830,"depth":72,"text":831},{"id":987,"depth":72,"text":988},{"id":1020,"depth":72,"text":1021},"2026-05-28","Compare date arithmetic approaches across JavaScript, Python, Java, Go, and PHP — from adding days to calculating intervals and handling time zones.","md",{"immutable":133},"\u002Fguides\u002Fdate-arithmetic-different-languages",{"title":5,"description":1058},"guides\u002Fdate-arithmetic-different-languages","cU6vNrc8BUFTvDOfsIvPpOmCr0s8Jz4ctz0q4xzEBtA",1780401333315]