[{"data":1,"prerenderedAt":2405},["ShallowReactive",2],{"doc:\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-dates-times-and-durations-with-xlsxwriter":3,"surround:\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-dates-times-and-durations-with-xlsxwriter":2370,"ancestors:\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-dates-times-and-durations-with-xlsxwriter":2379,"children:\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-dates-times-and-durations-with-xlsxwriter":2384,"related:\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-dates-times-and-durations-with-xlsxwriter":2385},{"id":4,"title":5,"body":6,"dateModified":2337,"datePublished":2337,"description":2338,"extension":2339,"faq":2340,"keyword":2349,"kind":2350,"meta":2351,"navigation":124,"path":2359,"seo":2360,"slug":2363,"stem":2364,"topics":2365,"type":2368,"__hash__":2369},"docs\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-dates-times-and-durations-with-xlsxwriter\u002Findex.md","Write Dates, Times and Durations with XlsxWriter",{"type":7,"value":8,"toc":2326},"minimark",[9,48,53,81,88,237,241,511,538,541,647,650,887,891,894,1203,1218,1222,1432,1461,1545,1549,1555,1684,1687,1693,1998,2042,2161,2177,2181,2230,2234,2254,2258,2264,2270,2283,2289,2293,2322],[10,11,12,13,17,18,22,23,22,26,29,30,33,34,37,38,41,42,47],"p",{},"Excel has no date type. A date is a number of days since the end of 1899 — 2 October 2026 is 46297 — and a time is a fraction of a day, so 08:00 is 0.3333. What makes a cell ",[14,15,16],"em",{},"look"," like a date is its number format. XlsxWriter converts Python ",[19,20,21],"code",{},"datetime",", ",[19,24,25],{},"date",[19,27,28],{},"time"," and ",[19,31,32],{},"timedelta"," objects to those numbers for you, but the formatting, timezones and a few edge cases are left to your code, and each produces a recognisable symptom: a column of five-digit numbers where dates should be, a ",[19,35,36],{},"TypeError"," about timezones, a shift duration of 37 hours showing as 13:05, or a historical date that turns into ",[19,39,40],{},"########",". This page goes through each with XlsxWriter directly and through pandas, checking what Excel will display with a LibreOffice export. It belongs to ",[43,44,46],"a",{"href":45},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002F","Building Excel Reports with xlsxwriter",".",[49,50,52],"h2",{"id":51},"prerequisites","Prerequisites",[54,55,60],"pre",{"className":56,"code":57,"language":58,"meta":59,"style":59},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install xlsxwriter pandas\n","bash","",[19,61,62],{"__ignoreMap":59},[63,64,67,71,75,78],"span",{"class":65,"line":66},"line",1,[63,68,70],{"class":69},"sMTad","pip",[63,72,74],{"class":73},"srMev"," install",[63,76,77],{"class":73}," xlsxwriter",[63,79,80],{"class":73}," pandas\n",[10,82,83,84,87],{},"The examples were run with XlsxWriter 3.2. LibreOffice (",[19,85,86],{},"soffice",") is used to export each cell as displayed; a small helper wraps that:",[54,89,93],{"className":90,"code":91,"language":92,"meta":59,"style":59},"language-python shiki shiki-themes github-light github-dark-high-contrast","import subprocess\nfrom pathlib import Path\n\ndef displayed(path):\n    subprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"csv:Text - txt - csv (StarCalc):44,34,76,1,,0,false,true,true\",\n                    \"--outdir\", \"calc\", path], check=True, capture_output=True)\n    return Path(\"calc\", Path(path).stem + \".csv\").read_text(encoding=\"utf-8\").splitlines()\n","python",[19,94,95,105,119,126,139,166,203],{"__ignoreMap":59},[63,96,97,101],{"class":65,"line":66},[63,98,100],{"class":99},"s-kum","import",[63,102,104],{"class":103},"skGVy"," subprocess\n",[63,106,108,111,114,116],{"class":65,"line":107},2,[63,109,110],{"class":99},"from",[63,112,113],{"class":103}," pathlib ",[63,115,100],{"class":99},[63,117,118],{"class":103}," Path\n",[63,120,122],{"class":65,"line":121},3,[63,123,125],{"emptyLinePlaceholder":124},true,"\n",[63,127,129,132,136],{"class":65,"line":128},4,[63,130,131],{"class":99},"def",[63,133,135],{"class":134},"s_Opv"," displayed",[63,137,138],{"class":103},"(path):\n",[63,140,142,145,148,150,153,155,158,160,163],{"class":65,"line":141},5,[63,143,144],{"class":103},"    subprocess.run([",[63,146,147],{"class":73},"\"soffice\"",[63,149,22],{"class":103},[63,151,152],{"class":73},"\"--headless\"",[63,154,22],{"class":103},[63,156,157],{"class":73},"\"--convert-to\"",[63,159,22],{"class":103},[63,161,162],{"class":73},"\"csv:Text - txt - csv (StarCalc):44,34,76,1,,0,false,true,true\"",[63,164,165],{"class":103},",\n",[63,167,169,172,174,177,180,184,187,191,193,196,198,200],{"class":65,"line":168},6,[63,170,171],{"class":73},"                    \"--outdir\"",[63,173,22],{"class":103},[63,175,176],{"class":73},"\"calc\"",[63,178,179],{"class":103},", path], ",[63,181,183],{"class":182},"sa561","check",[63,185,186],{"class":99},"=",[63,188,190],{"class":189},"sP0c6","True",[63,192,22],{"class":103},[63,194,195],{"class":182},"capture_output",[63,197,186],{"class":99},[63,199,190],{"class":189},[63,201,202],{"class":103},")\n",[63,204,206,209,212,214,217,220,223,226,229,231,234],{"class":65,"line":205},7,[63,207,208],{"class":99},"    return",[63,210,211],{"class":103}," Path(",[63,213,176],{"class":73},[63,215,216],{"class":103},", Path(path).stem ",[63,218,219],{"class":99},"+",[63,221,222],{"class":73}," \".csv\"",[63,224,225],{"class":103},").read_text(",[63,227,228],{"class":182},"encoding",[63,230,186],{"class":99},[63,232,233],{"class":73},"\"utf-8\"",[63,235,236],{"class":103},").splitlines()\n",[49,238,240],{"id":239},"step-1-a-date-needs-a-format","Step 1 — A date needs a format",[54,242,244],{"className":90,"code":243,"language":92,"meta":59,"style":59},"import datetime as dt\nimport xlsxwriter\n\nwb = xlsxwriter.Workbook(\"dates.xlsx\")\nws = wb.add_worksheet()\ndate_fmt = wb.add_format({\"num_format\": \"dd mmm yyyy\"})\nstamp_fmt = wb.add_format({\"num_format\": \"yyyy-mm-dd hh:mm\"})\nws.write(0, 0, dt.date(2026, 10, 2))                          # no format\nws.write(1, 0, dt.date(2026, 10, 2), date_fmt)\nws.write_datetime(2, 0, dt.datetime(2026, 10, 2, 8, 0), stamp_fmt)\nws.write(3, 0, dt.datetime(2026, 10, 2, 8, 0))                # no format\nws.set_column(0, 0, 18)\nwb.close()\nprint(displayed(\"dates.xlsx\"))\n",[19,245,246,259,266,270,285,295,317,335,371,398,435,472,491,497],{"__ignoreMap":59},[63,247,248,250,253,256],{"class":65,"line":66},[63,249,100],{"class":99},[63,251,252],{"class":103}," datetime ",[63,254,255],{"class":99},"as",[63,257,258],{"class":103}," dt\n",[63,260,261,263],{"class":65,"line":107},[63,262,100],{"class":99},[63,264,265],{"class":103}," xlsxwriter\n",[63,267,268],{"class":65,"line":121},[63,269,125],{"emptyLinePlaceholder":124},[63,271,272,275,277,280,283],{"class":65,"line":128},[63,273,274],{"class":103},"wb ",[63,276,186],{"class":99},[63,278,279],{"class":103}," xlsxwriter.Workbook(",[63,281,282],{"class":73},"\"dates.xlsx\"",[63,284,202],{"class":103},[63,286,287,290,292],{"class":65,"line":141},[63,288,289],{"class":103},"ws ",[63,291,186],{"class":99},[63,293,294],{"class":103}," wb.add_worksheet()\n",[63,296,297,300,302,305,308,311,314],{"class":65,"line":168},[63,298,299],{"class":103},"date_fmt ",[63,301,186],{"class":99},[63,303,304],{"class":103}," wb.add_format({",[63,306,307],{"class":73},"\"num_format\"",[63,309,310],{"class":103},": ",[63,312,313],{"class":73},"\"dd mmm yyyy\"",[63,315,316],{"class":103},"})\n",[63,318,319,322,324,326,328,330,333],{"class":65,"line":205},[63,320,321],{"class":103},"stamp_fmt ",[63,323,186],{"class":99},[63,325,304],{"class":103},[63,327,307],{"class":73},[63,329,310],{"class":103},[63,331,332],{"class":73},"\"yyyy-mm-dd hh:mm\"",[63,334,316],{"class":103},[63,336,338,341,344,346,348,351,354,356,359,361,364,367],{"class":65,"line":337},8,[63,339,340],{"class":103},"ws.write(",[63,342,343],{"class":189},"0",[63,345,22],{"class":103},[63,347,343],{"class":189},[63,349,350],{"class":103},", dt.date(",[63,352,353],{"class":189},"2026",[63,355,22],{"class":103},[63,357,358],{"class":189},"10",[63,360,22],{"class":103},[63,362,363],{"class":189},"2",[63,365,366],{"class":103},"))                          ",[63,368,370],{"class":369},"s-wDw","# no format\n",[63,372,374,376,379,381,383,385,387,389,391,393,395],{"class":65,"line":373},9,[63,375,340],{"class":103},[63,377,378],{"class":189},"1",[63,380,22],{"class":103},[63,382,343],{"class":189},[63,384,350],{"class":103},[63,386,353],{"class":189},[63,388,22],{"class":103},[63,390,358],{"class":189},[63,392,22],{"class":103},[63,394,363],{"class":189},[63,396,397],{"class":103},"), date_fmt)\n",[63,399,401,404,406,408,410,413,415,417,419,421,423,425,428,430,432],{"class":65,"line":400},10,[63,402,403],{"class":103},"ws.write_datetime(",[63,405,363],{"class":189},[63,407,22],{"class":103},[63,409,343],{"class":189},[63,411,412],{"class":103},", dt.datetime(",[63,414,353],{"class":189},[63,416,22],{"class":103},[63,418,358],{"class":189},[63,420,22],{"class":103},[63,422,363],{"class":189},[63,424,22],{"class":103},[63,426,427],{"class":189},"8",[63,429,22],{"class":103},[63,431,343],{"class":189},[63,433,434],{"class":103},"), stamp_fmt)\n",[63,436,438,440,443,445,447,449,451,453,455,457,459,461,463,465,467,470],{"class":65,"line":437},11,[63,439,340],{"class":103},[63,441,442],{"class":189},"3",[63,444,22],{"class":103},[63,446,343],{"class":189},[63,448,412],{"class":103},[63,450,353],{"class":189},[63,452,22],{"class":103},[63,454,358],{"class":189},[63,456,22],{"class":103},[63,458,363],{"class":189},[63,460,22],{"class":103},[63,462,427],{"class":189},[63,464,22],{"class":103},[63,466,343],{"class":189},[63,468,469],{"class":103},"))                ",[63,471,370],{"class":369},[63,473,475,478,480,482,484,486,489],{"class":65,"line":474},12,[63,476,477],{"class":103},"ws.set_column(",[63,479,343],{"class":189},[63,481,22],{"class":103},[63,483,343],{"class":189},[63,485,22],{"class":103},[63,487,488],{"class":189},"18",[63,490,202],{"class":103},[63,492,494],{"class":65,"line":493},13,[63,495,496],{"class":103},"wb.close()\n",[63,498,500,503,506,508],{"class":65,"line":499},14,[63,501,502],{"class":189},"print",[63,504,505],{"class":103},"(displayed(",[63,507,282],{"class":73},[63,509,510],{"class":103},"))\n",[10,512,513,514,516,517,520,521,29,523,525,526,529,530,533,534,537],{},"XlsxWriter turns the date into its serial number either way, but only the cells with a date format ",[14,515,16],{}," like dates: the unformatted ones show 46297 and 46297.3333 — the classic symptom. ",[19,518,519],{},"write()"," recognises ",[19,522,25],{},[19,524,21],{}," objects and hands them to ",[19,527,528],{},"write_datetime()",", so either call works; the format is what matters. Choosing an unambiguous display format such as ",[19,531,532],{},"dd mmm yyyy"," or ISO ",[19,535,536],{},"yyyy-mm-dd"," avoids the day\u002Fmonth confusion between US and European readers.",[10,539,540],{},"To avoid passing a format to every call, set a workbook default. It applies to dates written without an explicit format:",[54,542,544],{"className":90,"code":543,"language":92,"meta":59,"style":59},"wb = xlsxwriter.Workbook(\"default_fmt.xlsx\", {\"default_date_format\": \"dd mmm yyyy\"})\nws = wb.add_worksheet()\nws.write(0, 0, dt.date(2026, 10, 2))\nws.write(1, 0, dt.datetime(2026, 10, 2, 8, 0))\nwb.close()\nprint(displayed(\"default_fmt.xlsx\"))\n",[19,545,546,569,577,601,633,637],{"__ignoreMap":59},[63,547,548,550,552,554,557,560,563,565,567],{"class":65,"line":66},[63,549,274],{"class":103},[63,551,186],{"class":99},[63,553,279],{"class":103},[63,555,556],{"class":73},"\"default_fmt.xlsx\"",[63,558,559],{"class":103},", {",[63,561,562],{"class":73},"\"default_date_format\"",[63,564,310],{"class":103},[63,566,313],{"class":73},[63,568,316],{"class":103},[63,570,571,573,575],{"class":65,"line":107},[63,572,289],{"class":103},[63,574,186],{"class":99},[63,576,294],{"class":103},[63,578,579,581,583,585,587,589,591,593,595,597,599],{"class":65,"line":121},[63,580,340],{"class":103},[63,582,343],{"class":189},[63,584,22],{"class":103},[63,586,343],{"class":189},[63,588,350],{"class":103},[63,590,353],{"class":189},[63,592,22],{"class":103},[63,594,358],{"class":189},[63,596,22],{"class":103},[63,598,363],{"class":189},[63,600,510],{"class":103},[63,602,603,605,607,609,611,613,615,617,619,621,623,625,627,629,631],{"class":65,"line":128},[63,604,340],{"class":103},[63,606,378],{"class":189},[63,608,22],{"class":103},[63,610,343],{"class":189},[63,612,412],{"class":103},[63,614,353],{"class":189},[63,616,22],{"class":103},[63,618,358],{"class":189},[63,620,22],{"class":103},[63,622,363],{"class":189},[63,624,22],{"class":103},[63,626,427],{"class":189},[63,628,22],{"class":103},[63,630,343],{"class":189},[63,632,510],{"class":103},[63,634,635],{"class":65,"line":141},[63,636,496],{"class":103},[63,638,639,641,643,645],{"class":65,"line":168},[63,640,502],{"class":189},[63,642,505],{"class":103},[63,644,556],{"class":73},[63,646,510],{"class":103},[10,648,649],{},"Both cells now display as dates without any per-cell format, which keeps report code shorter when most dates share one style. The default applies to times too, so a timestamp written this way shows only its date — set an explicit format where the time matters.",[651,652,660,661,660,665,660,669,660,676,660,685,660,689,660,696,660,700,660,704,660,708,660,712,660,716,660,720,660,724,660,728,660,730,660,734,660,736,660,739,660,741,660,743,660,746,660,749,660,751,660,755,660,757,660,759,660,761,660,764,660,766,660,769,660,772,660,775,660,777,660,780,660,782,660,785,660,787,660,789,660,792,660,796,660,799,660,803,660,806,660,808,660,811,660,813,660,816,660,818,660,821,660,823,660,825,660,827,660,829,660,834,660,838,660,840,660,842,660,844,660,846,660,848,660,851,660,857,660,861,660,868,660,873,660,881],"svg",{"viewBox":653,"role":654,"ariaLabelledBy":655,"xmlns":658,"style":659},"4 0 753 164","img",[656,657],"xd-serial-t","xd-serial-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:753px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[662,663,664],"title",{"id":656},"What XlsxWriter writes, and what the format shows",[666,667,668],"desc",{"id":657},"The date 2 October 2026 is stored as 46297 and 08:00 the same day as 46297.3333. Without a number format the cell displays the serial number; with dd mmm yyyy it displays 02 Oct 2026.",[670,671],"rect",{"x":672,"y":343,"width":673,"height":674,"fill":675},"4","753","164","#ffffff",[670,677],{"x":678,"y":679,"width":680,"height":681,"rx":343,"fill":682,"stroke":683,"style":684},"20.0","40.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[670,686],{"x":687,"y":679,"width":688,"height":681,"rx":343,"fill":682,"stroke":683,"style":684},"52.0","107.5",[690,691,695],"text",{"x":692,"y":693,"style":694},"105.7","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[670,697],{"x":698,"y":679,"width":699,"height":681,"rx":343,"fill":682,"stroke":683,"style":684},"159.5","82.4",[690,701,703],{"x":702,"y":693,"style":694},"200.7","B",[670,705],{"x":706,"y":679,"width":707,"height":681,"rx":343,"fill":682,"stroke":683,"style":684},"241.8","35.9",[690,709,711],{"x":710,"y":693,"style":694},"259.8","C",[670,713],{"x":714,"y":679,"width":715,"height":681,"rx":343,"fill":682,"stroke":683,"style":684},"277.8","52.4",[690,717,719],{"x":718,"y":693,"style":694},"303.9","D",[670,721],{"x":678,"y":722,"width":680,"height":723,"rx":343,"fill":682,"stroke":683,"style":684},"64.0","28.0",[690,725,378],{"x":726,"y":727,"style":694},"36.0","83.0",[670,729],{"x":687,"y":722,"width":688,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[690,731,733],{"x":692,"y":727,"style":732},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Python value",[670,735],{"x":698,"y":722,"width":699,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[690,737,738],{"x":702,"y":727,"style":732},"Stored",[670,740],{"x":706,"y":722,"width":707,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[670,742],{"x":714,"y":722,"width":715,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[670,744],{"x":678,"y":745,"width":680,"height":723,"rx":343,"fill":682,"stroke":683,"style":684},"92.0",[690,747,363],{"x":726,"y":748,"style":694},"111.0",[670,750],{"x":687,"y":745,"width":688,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[690,752,754],{"x":692,"y":748,"style":753},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","date(2026",[670,756],{"x":698,"y":745,"width":699,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[690,758,358],{"x":702,"y":748,"style":753},[670,760],{"x":706,"y":745,"width":707,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[690,762,763],{"x":710,"y":748,"style":753},"2)",[670,765],{"x":714,"y":745,"width":715,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[690,767,768],{"x":718,"y":748,"style":753},"46297",[670,770],{"x":678,"y":771,"width":680,"height":723,"rx":343,"fill":682,"stroke":683,"style":684},"120.0",[690,773,442],{"x":726,"y":774,"style":694},"139.0",[670,776],{"x":687,"y":771,"width":688,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[690,778,779],{"x":692,"y":774,"style":753},"datetime(…, 8, 0)",[670,781],{"x":698,"y":771,"width":699,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[690,783,784],{"x":702,"y":774,"style":753},"46297.3333",[670,786],{"x":706,"y":771,"width":707,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[670,788],{"x":714,"y":771,"width":715,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[670,790],{"x":791,"y":679,"width":680,"height":681,"rx":343,"fill":682,"stroke":683,"style":684},"513.3",[670,793],{"x":794,"y":679,"width":795,"height":681,"rx":343,"fill":682,"stroke":683,"style":684},"545.3","81.7",[690,797,695],{"x":798,"y":693,"style":694},"586.1",[670,800],{"x":801,"y":679,"width":802,"height":681,"rx":343,"fill":682,"stroke":683,"style":684},"627.0","113.0",[690,804,703],{"x":805,"y":693,"style":694},"683.5",[670,807],{"x":791,"y":722,"width":680,"height":723,"rx":343,"fill":682,"stroke":683,"style":684},[690,809,378],{"x":810,"y":727,"style":694},"529.3",[670,812],{"x":794,"y":722,"width":795,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[690,814,815],{"x":798,"y":727,"style":732},"No format",[670,817],{"x":801,"y":722,"width":802,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[690,819,820],{"x":805,"y":727,"style":732},"With format",[670,822],{"x":791,"y":745,"width":680,"height":723,"rx":343,"fill":682,"stroke":683,"style":684},[690,824,363],{"x":810,"y":748,"style":694},[670,826],{"x":794,"y":745,"width":795,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[690,828,768],{"x":798,"y":748,"style":753},[670,830],{"x":801,"y":745,"width":802,"height":723,"rx":343,"fill":831,"stroke":832,"style":833},"#d9f4f1","var(--teal,#0f9488)","stroke-width:1.5px",[690,835,837],{"x":805,"y":748,"style":836},"font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","02 Oct 2026",[670,839],{"x":791,"y":771,"width":680,"height":723,"rx":343,"fill":682,"stroke":683,"style":684},[690,841,442],{"x":810,"y":774,"style":694},[670,843],{"x":794,"y":771,"width":795,"height":723,"rx":343,"fill":675,"stroke":683,"style":684},[690,845,784],{"x":798,"y":774,"style":753},[670,847],{"x":801,"y":771,"width":802,"height":723,"rx":343,"fill":831,"stroke":832,"style":833},[690,849,850],{"x":805,"y":774,"style":836},"2026-10-02 08:00",[690,852,856],{"x":853,"y":854,"style":855},"175.1","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","before",[690,858,860],{"x":859,"y":854,"style":855},"626.6","after",[65,862],{"x1":863,"y1":864,"x2":865,"y2":864,"stroke":866,"style":867},"340.1","94.0","499.3","var(--brand,#5b5cf0)","stroke-width:2px",[869,870],"polygon",{"points":871,"fill":872},"503.3,94.0 494.3,99.0 494.3,89.0","#5b5cf0",[670,874],{"x":875,"y":876,"width":877,"height":878,"rx":879,"fill":675,"stroke":683,"style":880},"364.4","61.0","114.5","22.0","11","stroke-width:1.2px",[690,882,886],{"x":883,"y":884,"style":885},"421.7","76.0","font-size:11.5px;font-weight:400;fill:var(--brand-strong,#4338ca);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace","number format",[49,888,890],{"id":889},"step-2-timezones-convert-then-strip","Step 2 — Timezones: convert, then strip",[10,892,893],{},"Excel cells have no timezone, so XlsxWriter refuses timezone-aware datetimes rather than guess:",[54,895,897],{"className":90,"code":896,"language":92,"meta":59,"style":59},"from zoneinfo import ZoneInfo\n\nutc_event = dt.datetime(2026, 10, 2, 7, 30, tzinfo=ZoneInfo(\"UTC\"))\nwb = xlsxwriter.Workbook(\"tz.xlsx\")\nws = wb.add_worksheet()\ntry:\n    ws.write_datetime(0, 0, utc_event, stamp_fmt)\nexcept TypeError as e:\n    print(\"TypeError:\", e)\n\nlocal = utc_event.astimezone(ZoneInfo(\"Europe\u002FLondon\")).replace(tzinfo=None)\nfmt = wb.add_format({\"num_format\": \"yyyy-mm-dd hh:mm\"})\nws.write_datetime(0, 0, local, fmt)\nws.write(0, 1, \"Europe\u002FLondon\")\nwb.close()\n\nwb = xlsxwriter.Workbook(\"tz_removed.xlsx\", {\"remove_timezone\": True})\nws = wb.add_worksheet()\nws.write_datetime(0, 0, utc_event, wb.add_format({\"num_format\": \"yyyy-mm-dd hh:mm\"}))\nwb.close()\nprint(\"converted:\", displayed(\"tz.xlsx\"), \"| remove_timezone:\", displayed(\"tz_removed.xlsx\"))\n",[19,898,899,911,915,960,973,981,989,1003,1017,1031,1035,1060,1077,1090,1106,1111,1116,1139,1148,1171,1176],{"__ignoreMap":59},[63,900,901,903,906,908],{"class":65,"line":66},[63,902,110],{"class":99},[63,904,905],{"class":103}," zoneinfo ",[63,907,100],{"class":99},[63,909,910],{"class":103}," ZoneInfo\n",[63,912,913],{"class":65,"line":107},[63,914,125],{"emptyLinePlaceholder":124},[63,916,917,920,922,925,927,929,931,933,935,937,940,942,945,947,950,952,955,958],{"class":65,"line":121},[63,918,919],{"class":103},"utc_event ",[63,921,186],{"class":99},[63,923,924],{"class":103}," dt.datetime(",[63,926,353],{"class":189},[63,928,22],{"class":103},[63,930,358],{"class":189},[63,932,22],{"class":103},[63,934,363],{"class":189},[63,936,22],{"class":103},[63,938,939],{"class":189},"7",[63,941,22],{"class":103},[63,943,944],{"class":189},"30",[63,946,22],{"class":103},[63,948,949],{"class":182},"tzinfo",[63,951,186],{"class":99},[63,953,954],{"class":103},"ZoneInfo(",[63,956,957],{"class":73},"\"UTC\"",[63,959,510],{"class":103},[63,961,962,964,966,968,971],{"class":65,"line":128},[63,963,274],{"class":103},[63,965,186],{"class":99},[63,967,279],{"class":103},[63,969,970],{"class":73},"\"tz.xlsx\"",[63,972,202],{"class":103},[63,974,975,977,979],{"class":65,"line":141},[63,976,289],{"class":103},[63,978,186],{"class":99},[63,980,294],{"class":103},[63,982,983,986],{"class":65,"line":168},[63,984,985],{"class":99},"try",[63,987,988],{"class":103},":\n",[63,990,991,994,996,998,1000],{"class":65,"line":205},[63,992,993],{"class":103},"    ws.write_datetime(",[63,995,343],{"class":189},[63,997,22],{"class":103},[63,999,343],{"class":189},[63,1001,1002],{"class":103},", utc_event, stamp_fmt)\n",[63,1004,1005,1008,1011,1014],{"class":65,"line":337},[63,1006,1007],{"class":99},"except",[63,1009,1010],{"class":189}," TypeError",[63,1012,1013],{"class":99}," as",[63,1015,1016],{"class":103}," e:\n",[63,1018,1019,1022,1025,1028],{"class":65,"line":373},[63,1020,1021],{"class":189},"    print",[63,1023,1024],{"class":103},"(",[63,1026,1027],{"class":73},"\"TypeError:\"",[63,1029,1030],{"class":103},", e)\n",[63,1032,1033],{"class":65,"line":400},[63,1034,125],{"emptyLinePlaceholder":124},[63,1036,1037,1040,1042,1045,1048,1051,1053,1055,1058],{"class":65,"line":437},[63,1038,1039],{"class":103},"local ",[63,1041,186],{"class":99},[63,1043,1044],{"class":103}," utc_event.astimezone(ZoneInfo(",[63,1046,1047],{"class":73},"\"Europe\u002FLondon\"",[63,1049,1050],{"class":103},")).replace(",[63,1052,949],{"class":182},[63,1054,186],{"class":99},[63,1056,1057],{"class":189},"None",[63,1059,202],{"class":103},[63,1061,1062,1065,1067,1069,1071,1073,1075],{"class":65,"line":474},[63,1063,1064],{"class":103},"fmt ",[63,1066,186],{"class":99},[63,1068,304],{"class":103},[63,1070,307],{"class":73},[63,1072,310],{"class":103},[63,1074,332],{"class":73},[63,1076,316],{"class":103},[63,1078,1079,1081,1083,1085,1087],{"class":65,"line":493},[63,1080,403],{"class":103},[63,1082,343],{"class":189},[63,1084,22],{"class":103},[63,1086,343],{"class":189},[63,1088,1089],{"class":103},", local, fmt)\n",[63,1091,1092,1094,1096,1098,1100,1102,1104],{"class":65,"line":499},[63,1093,340],{"class":103},[63,1095,343],{"class":189},[63,1097,22],{"class":103},[63,1099,378],{"class":189},[63,1101,22],{"class":103},[63,1103,1047],{"class":73},[63,1105,202],{"class":103},[63,1107,1109],{"class":65,"line":1108},15,[63,1110,496],{"class":103},[63,1112,1114],{"class":65,"line":1113},16,[63,1115,125],{"emptyLinePlaceholder":124},[63,1117,1119,1121,1123,1125,1128,1130,1133,1135,1137],{"class":65,"line":1118},17,[63,1120,274],{"class":103},[63,1122,186],{"class":99},[63,1124,279],{"class":103},[63,1126,1127],{"class":73},"\"tz_removed.xlsx\"",[63,1129,559],{"class":103},[63,1131,1132],{"class":73},"\"remove_timezone\"",[63,1134,310],{"class":103},[63,1136,190],{"class":189},[63,1138,316],{"class":103},[63,1140,1142,1144,1146],{"class":65,"line":1141},18,[63,1143,289],{"class":103},[63,1145,186],{"class":99},[63,1147,294],{"class":103},[63,1149,1151,1153,1155,1157,1159,1162,1164,1166,1168],{"class":65,"line":1150},19,[63,1152,403],{"class":103},[63,1154,343],{"class":189},[63,1156,22],{"class":103},[63,1158,343],{"class":189},[63,1160,1161],{"class":103},", utc_event, wb.add_format({",[63,1163,307],{"class":73},[63,1165,310],{"class":103},[63,1167,332],{"class":73},[63,1169,1170],{"class":103},"}))\n",[63,1172,1174],{"class":65,"line":1173},20,[63,1175,496],{"class":103},[63,1177,1179,1181,1183,1186,1189,1191,1194,1197,1199,1201],{"class":65,"line":1178},21,[63,1180,502],{"class":189},[63,1182,1024],{"class":103},[63,1184,1185],{"class":73},"\"converted:\"",[63,1187,1188],{"class":103},", displayed(",[63,1190,970],{"class":73},[63,1192,1193],{"class":103},"), ",[63,1195,1196],{"class":73},"\"| remove_timezone:\"",[63,1198,1188],{"class":103},[63,1200,1127],{"class":73},[63,1202,510],{"class":103},[10,1204,1205,1206,1209,1210,1213,1214,47],{},"The error message points at the ",[19,1207,1208],{},"remove_timezone"," workbook option, which simply drops the timezone and keeps the clock time — 07:30 UTC is written as 07:30. That is right only if your readers think in UTC. If they think in local time, convert first with ",[19,1211,1212],{},"astimezone()"," and then remove the timezone: the same event becomes 08:30, British Summer Time. Write the zone in a header or an adjacent column so nobody has to guess which clock the column uses. The same decision appears in pandas, covered in ",[43,1215,1217],{"href":1216},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-excel-does-not-support-timezones-in-datetimes\u002F","Fix \"Excel does not support datetimes with timezones\" in pandas",[49,1219,1221],{"id":1220},"step-3-durations-and-times-of-day","Step 3 — Durations and times of day",[54,1223,1225],{"className":90,"code":1224,"language":92,"meta":59,"style":59},"wb = xlsxwriter.Workbook(\"durations.xlsx\")\nws = wb.add_worksheet()\ndur_wrong = wb.add_format({\"num_format\": \"hh:mm\"})\ndur_right = wb.add_format({\"num_format\": \"[h]:mm\"})\ntod = wb.add_format({\"num_format\": \"hh:mm\"})\nshift = dt.timedelta(hours=37, minutes=5)\nws.write_datetime(0, 0, shift, dur_wrong)\nws.write_datetime(0, 1, shift, dur_right)\nws.write_datetime(0, 2, dt.time(14, 45), tod)\nws.write_number(0, 3, shift \u002F dt.timedelta(hours=1), wb.add_format({\"num_format\": \"0.00\"}))\nwb.close()\nprint(displayed(\"durations.xlsx\"))\n",[19,1226,1227,1240,1248,1266,1284,1301,1331,1344,1357,1381,1418,1422],{"__ignoreMap":59},[63,1228,1229,1231,1233,1235,1238],{"class":65,"line":66},[63,1230,274],{"class":103},[63,1232,186],{"class":99},[63,1234,279],{"class":103},[63,1236,1237],{"class":73},"\"durations.xlsx\"",[63,1239,202],{"class":103},[63,1241,1242,1244,1246],{"class":65,"line":107},[63,1243,289],{"class":103},[63,1245,186],{"class":99},[63,1247,294],{"class":103},[63,1249,1250,1253,1255,1257,1259,1261,1264],{"class":65,"line":121},[63,1251,1252],{"class":103},"dur_wrong ",[63,1254,186],{"class":99},[63,1256,304],{"class":103},[63,1258,307],{"class":73},[63,1260,310],{"class":103},[63,1262,1263],{"class":73},"\"hh:mm\"",[63,1265,316],{"class":103},[63,1267,1268,1271,1273,1275,1277,1279,1282],{"class":65,"line":128},[63,1269,1270],{"class":103},"dur_right ",[63,1272,186],{"class":99},[63,1274,304],{"class":103},[63,1276,307],{"class":73},[63,1278,310],{"class":103},[63,1280,1281],{"class":73},"\"[h]:mm\"",[63,1283,316],{"class":103},[63,1285,1286,1289,1291,1293,1295,1297,1299],{"class":65,"line":141},[63,1287,1288],{"class":103},"tod ",[63,1290,186],{"class":99},[63,1292,304],{"class":103},[63,1294,307],{"class":73},[63,1296,310],{"class":103},[63,1298,1263],{"class":73},[63,1300,316],{"class":103},[63,1302,1303,1306,1308,1311,1314,1316,1319,1321,1324,1326,1329],{"class":65,"line":168},[63,1304,1305],{"class":103},"shift ",[63,1307,186],{"class":99},[63,1309,1310],{"class":103}," dt.timedelta(",[63,1312,1313],{"class":182},"hours",[63,1315,186],{"class":99},[63,1317,1318],{"class":189},"37",[63,1320,22],{"class":103},[63,1322,1323],{"class":182},"minutes",[63,1325,186],{"class":99},[63,1327,1328],{"class":189},"5",[63,1330,202],{"class":103},[63,1332,1333,1335,1337,1339,1341],{"class":65,"line":205},[63,1334,403],{"class":103},[63,1336,343],{"class":189},[63,1338,22],{"class":103},[63,1340,343],{"class":189},[63,1342,1343],{"class":103},", shift, dur_wrong)\n",[63,1345,1346,1348,1350,1352,1354],{"class":65,"line":337},[63,1347,403],{"class":103},[63,1349,343],{"class":189},[63,1351,22],{"class":103},[63,1353,378],{"class":189},[63,1355,1356],{"class":103},", shift, dur_right)\n",[63,1358,1359,1361,1363,1365,1367,1370,1373,1375,1378],{"class":65,"line":373},[63,1360,403],{"class":103},[63,1362,343],{"class":189},[63,1364,22],{"class":103},[63,1366,363],{"class":189},[63,1368,1369],{"class":103},", dt.time(",[63,1371,1372],{"class":189},"14",[63,1374,22],{"class":103},[63,1376,1377],{"class":189},"45",[63,1379,1380],{"class":103},"), tod)\n",[63,1382,1383,1386,1388,1390,1392,1395,1398,1400,1402,1404,1406,1409,1411,1413,1416],{"class":65,"line":400},[63,1384,1385],{"class":103},"ws.write_number(",[63,1387,343],{"class":189},[63,1389,22],{"class":103},[63,1391,442],{"class":189},[63,1393,1394],{"class":103},", shift ",[63,1396,1397],{"class":99},"\u002F",[63,1399,1310],{"class":103},[63,1401,1313],{"class":182},[63,1403,186],{"class":99},[63,1405,378],{"class":189},[63,1407,1408],{"class":103},"), wb.add_format({",[63,1410,307],{"class":73},[63,1412,310],{"class":103},[63,1414,1415],{"class":73},"\"0.00\"",[63,1417,1170],{"class":103},[63,1419,1420],{"class":65,"line":437},[63,1421,496],{"class":103},[63,1423,1424,1426,1428,1430],{"class":65,"line":474},[63,1425,502],{"class":189},[63,1427,505],{"class":103},[63,1429,1237],{"class":73},[63,1431,510],{"class":103},[10,1433,1434,1435,1437,1438,1440,1441,1444,1445,1448,1449,1452,1453,1456,1457,47],{},"A ",[19,1436,32],{}," is written as a number of days — 37 hours 5 minutes is 1.545 — and a ",[19,1439,28],{}," as a fraction of a day. Formatted with ",[19,1442,1443],{},"hh:mm",", the duration shows 13:05: the hours wrap at 24 like a clock. The square brackets in ",[19,1446,1447],{},"[h]:mm"," make the hours ",[14,1450,1451],{},"elapsed"," and they keep counting, showing 37:05. For timesheets and SLA reports that difference is the whole point. When a duration is needed as decimal hours — for multiplying by an hourly rate — write it as hours, as column D does with ",[19,1454,1455],{},"shift \u002F timedelta(hours=1)",", giving 37.08; in a worksheet formula the equivalent is multiplying the duration cell by 24. Durations beyond the cell level are covered in ",[43,1458,1460],{"href":1459},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel\u002Fformat-durations-over-24-hours-in-excel\u002F","Format Durations Over 24 Hours in Excel",[651,1462,660,1468,660,1471,660,1474,660,1478,660,1485,660,1496,660,1502,660,1506,660,1509,660,1513,660,1517,660,1520,660,1527,660,1532,660,1536,660,1539,660,1542],{"viewBox":1463,"role":654,"ariaLabelledBy":1464,"xmlns":658,"style":1467},"4 0 752 207",[1465,1466],"xd-duration-t","xd-duration-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[662,1469,1470],{"id":1465},"hh:mm or [h]:mm for a duration",[666,1472,1473],{"id":1466},"A duration of 37 hours 5 minutes is stored as 1.545 days. With hh:mm the hours wrap at 24 and it shows 13:05. With [h]:mm the hours keep counting and it shows 37:05. Multiplying by 24 gives decimal hours, 37.08.",[670,1475],{"x":672,"y":343,"width":1476,"height":1477,"fill":675},"752","207",[670,1479],{"x":678,"y":1480,"width":1481,"height":1482,"rx":1372,"fill":1483,"stroke":1484,"style":867},"16.0","351.0","175.0","#fdefd8","var(--gold,#b4740a)",[1486,1487,1489],"g",{"transform":1488},"translate(182.5,29.0) scale(1.083)",[1490,1491],"path",{"d":1492,"fill":1493,"stroke":1494,"style":1495},"M12 3a9 9 0 1 0 .01 0z M12 7v5l3.5 2","none","var(--gold-ink,#7a4e06)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[690,1497,1501],{"x":1498,"y":1499,"style":1500},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","hh:mm (clock)",[65,1503],{"x1":726,"y1":1504,"x2":1505,"y2":1504,"stroke":1484,"style":684},"91.0","355.0",[690,1507,1508],{"x":1498,"y":748,"style":753},"37 h 5 min → 13:05",[690,1510,1512],{"x":1498,"y":1511,"style":753},"137.0","wraps at 24 hours",[690,1514,1516],{"x":1498,"y":1515,"style":753},"163.0","right for times of day",[670,1518],{"x":1519,"y":1480,"width":1481,"height":1482,"rx":1372,"fill":831,"stroke":832,"style":867},"389.0",[1486,1521,1523],{"transform":1522},"translate(551.5,29.0) scale(1.083)",[1490,1524],{"d":1525,"fill":1493,"stroke":1526,"style":1495},"M5 12.5l4.5 4.5L19 7","var(--teal-ink,#0b6157)",[690,1528,1531],{"x":1529,"y":1499,"style":1530},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","[h]:mm (elapsed)",[65,1533],{"x1":1534,"y1":1504,"x2":1535,"y2":1504,"stroke":832,"style":684},"405.0","724.0",[690,1537,1538],{"x":1529,"y":748,"style":753},"37 h 5 min → 37:05",[690,1540,1541],{"x":1529,"y":1511,"style":753},"keeps counting",[690,1543,1544],{"x":1529,"y":1515,"style":753},"right for durations",[49,1546,1548],{"id":1547},"step-4-dates-before-1900-and-dates-from-pandas","Step 4 — Dates before 1900 and dates from pandas",[10,1550,1551,1552,1554],{},"Excel's date system starts on 1 January 1900; it cannot represent earlier dates. XlsxWriter writes them anyway, as negative serial numbers, which Excel displays as ",[19,1553,40],{},":",[54,1556,1558],{"className":90,"code":1557,"language":92,"meta":59,"style":59},"wb = xlsxwriter.Workbook(\"old.xlsx\")\nws = wb.add_worksheet()\nws.write_datetime(0, 0, dt.datetime(1899, 12, 25), wb.add_format({\"num_format\": \"yyyy-mm-dd\"}))\nws.write_string(0, 1, \"1899-12-25\")\nwb.close()\n\nimport zipfile\nprint(zipfile.ZipFile(\"old.xlsx\").read(\"xl\u002Fworksheets\u002Fsheet1.xml\").decode().split('\u003Cc r=\"A1\"')[1][:30])\n",[19,1559,1560,1573,1581,1617,1635,1639,1643,1650],{"__ignoreMap":59},[63,1561,1562,1564,1566,1568,1571],{"class":65,"line":66},[63,1563,274],{"class":103},[63,1565,186],{"class":99},[63,1567,279],{"class":103},[63,1569,1570],{"class":73},"\"old.xlsx\"",[63,1572,202],{"class":103},[63,1574,1575,1577,1579],{"class":65,"line":107},[63,1576,289],{"class":103},[63,1578,186],{"class":99},[63,1580,294],{"class":103},[63,1582,1583,1585,1587,1589,1591,1593,1596,1598,1601,1603,1606,1608,1610,1612,1615],{"class":65,"line":121},[63,1584,403],{"class":103},[63,1586,343],{"class":189},[63,1588,22],{"class":103},[63,1590,343],{"class":189},[63,1592,412],{"class":103},[63,1594,1595],{"class":189},"1899",[63,1597,22],{"class":103},[63,1599,1600],{"class":189},"12",[63,1602,22],{"class":103},[63,1604,1605],{"class":189},"25",[63,1607,1408],{"class":103},[63,1609,307],{"class":73},[63,1611,310],{"class":103},[63,1613,1614],{"class":73},"\"yyyy-mm-dd\"",[63,1616,1170],{"class":103},[63,1618,1619,1622,1624,1626,1628,1630,1633],{"class":65,"line":128},[63,1620,1621],{"class":103},"ws.write_string(",[63,1623,343],{"class":189},[63,1625,22],{"class":103},[63,1627,378],{"class":189},[63,1629,22],{"class":103},[63,1631,1632],{"class":73},"\"1899-12-25\"",[63,1634,202],{"class":103},[63,1636,1637],{"class":65,"line":141},[63,1638,496],{"class":103},[63,1640,1641],{"class":65,"line":168},[63,1642,125],{"emptyLinePlaceholder":124},[63,1644,1645,1647],{"class":65,"line":205},[63,1646,100],{"class":99},[63,1648,1649],{"class":103}," zipfile\n",[63,1651,1652,1654,1657,1659,1662,1665,1668,1671,1674,1676,1679,1681],{"class":65,"line":337},[63,1653,502],{"class":189},[63,1655,1656],{"class":103},"(zipfile.ZipFile(",[63,1658,1570],{"class":73},[63,1660,1661],{"class":103},").read(",[63,1663,1664],{"class":73},"\"xl\u002Fworksheets\u002Fsheet1.xml\"",[63,1666,1667],{"class":103},").decode().split(",[63,1669,1670],{"class":73},"'\u003Cc r=\"A1\"'",[63,1672,1673],{"class":103},")[",[63,1675,378],{"class":189},[63,1677,1678],{"class":103},"][:",[63,1680,944],{"class":189},[63,1682,1683],{"class":103},"])\n",[10,1685,1686],{},"The stored value is -6 — six days before the start of Excel's calendar. Excel shows hashes, because it has no way to display a negative date; LibreOffice, whose own date system reaches further back, shows a date one day off because of the historical 1900 leap-year quirk. For genealogy, archive or historical data, write such dates as ISO text strings, as in column B, and note that they will not sort or filter as dates.",[10,1688,1689,1690,1554],{},"Through pandas, the same choices are made on the ",[19,1691,1692],{},"ExcelWriter",[54,1694,1696],{"className":90,"code":1695,"language":92,"meta":59,"style":59},"import pandas as pd\n\ndf = pd.DataFrame({\"start\": pd.to_datetime([\"2026-10-02 08:00\", \"2026-10-03 21:15\"]),\n                   \"day\": pd.to_datetime([\"2026-10-02\", \"2026-10-03\"]).date,\n                   \"duration\": pd.to_timedelta([\"37:05:00\", \"07:30:00\"])})\nwith pd.ExcelWriter(\"pandas_dates.xlsx\", engine=\"xlsxwriter\",\n                    datetime_format=\"yyyy-mm-dd hh:mm\", date_format=\"dd mmm yyyy\") as xw:\n    df.to_excel(xw, index=False)\nprint(\"timedelta as written by pandas:\", displayed(\"pandas_dates.xlsx\"))\n\ndf[\"duration\"] = df[\"duration\"] \u002F pd.Timedelta(days=1)            # fraction of a day, a plain float\nwith pd.ExcelWriter(\"pandas_dates.xlsx\", engine=\"xlsxwriter\",\n                    datetime_format=\"yyyy-mm-dd hh:mm\", date_format=\"dd mmm yyyy\") as xw:\n    df.to_excel(xw, index=False)\n    xw.sheets[\"Sheet1\"].set_column(2, 2, 10, xw.book.add_format({\"num_format\": \"[h]:mm\"}))\nprint(\"as days with a column format:\", displayed(\"pandas_dates.xlsx\"))\n",[19,1697,1698,1710,1714,1741,1759,1778,1801,1827,1842,1857,1861,1899,1917,1939,1951,1983],{"__ignoreMap":59},[63,1699,1700,1702,1705,1707],{"class":65,"line":66},[63,1701,100],{"class":99},[63,1703,1704],{"class":103}," pandas ",[63,1706,255],{"class":99},[63,1708,1709],{"class":103}," pd\n",[63,1711,1712],{"class":65,"line":107},[63,1713,125],{"emptyLinePlaceholder":124},[63,1715,1716,1719,1721,1724,1727,1730,1733,1735,1738],{"class":65,"line":121},[63,1717,1718],{"class":103},"df ",[63,1720,186],{"class":99},[63,1722,1723],{"class":103}," pd.DataFrame({",[63,1725,1726],{"class":73},"\"start\"",[63,1728,1729],{"class":103},": pd.to_datetime([",[63,1731,1732],{"class":73},"\"2026-10-02 08:00\"",[63,1734,22],{"class":103},[63,1736,1737],{"class":73},"\"2026-10-03 21:15\"",[63,1739,1740],{"class":103},"]),\n",[63,1742,1743,1746,1748,1751,1753,1756],{"class":65,"line":128},[63,1744,1745],{"class":73},"                   \"day\"",[63,1747,1729],{"class":103},[63,1749,1750],{"class":73},"\"2026-10-02\"",[63,1752,22],{"class":103},[63,1754,1755],{"class":73},"\"2026-10-03\"",[63,1757,1758],{"class":103},"]).date,\n",[63,1760,1761,1764,1767,1770,1772,1775],{"class":65,"line":141},[63,1762,1763],{"class":73},"                   \"duration\"",[63,1765,1766],{"class":103},": pd.to_timedelta([",[63,1768,1769],{"class":73},"\"37:05:00\"",[63,1771,22],{"class":103},[63,1773,1774],{"class":73},"\"07:30:00\"",[63,1776,1777],{"class":103},"])})\n",[63,1779,1780,1783,1786,1789,1791,1794,1796,1799],{"class":65,"line":168},[63,1781,1782],{"class":99},"with",[63,1784,1785],{"class":103}," pd.ExcelWriter(",[63,1787,1788],{"class":73},"\"pandas_dates.xlsx\"",[63,1790,22],{"class":103},[63,1792,1793],{"class":182},"engine",[63,1795,186],{"class":99},[63,1797,1798],{"class":73},"\"xlsxwriter\"",[63,1800,165],{"class":103},[63,1802,1803,1806,1808,1810,1812,1815,1817,1819,1822,1824],{"class":65,"line":205},[63,1804,1805],{"class":182},"                    datetime_format",[63,1807,186],{"class":99},[63,1809,332],{"class":73},[63,1811,22],{"class":103},[63,1813,1814],{"class":182},"date_format",[63,1816,186],{"class":99},[63,1818,313],{"class":73},[63,1820,1821],{"class":103},") ",[63,1823,255],{"class":99},[63,1825,1826],{"class":103}," xw:\n",[63,1828,1829,1832,1835,1837,1840],{"class":65,"line":337},[63,1830,1831],{"class":103},"    df.to_excel(xw, ",[63,1833,1834],{"class":182},"index",[63,1836,186],{"class":99},[63,1838,1839],{"class":189},"False",[63,1841,202],{"class":103},[63,1843,1844,1846,1848,1851,1853,1855],{"class":65,"line":373},[63,1845,502],{"class":189},[63,1847,1024],{"class":103},[63,1849,1850],{"class":73},"\"timedelta as written by pandas:\"",[63,1852,1188],{"class":103},[63,1854,1788],{"class":73},[63,1856,510],{"class":103},[63,1858,1859],{"class":65,"line":400},[63,1860,125],{"emptyLinePlaceholder":124},[63,1862,1863,1866,1869,1872,1874,1877,1879,1881,1883,1886,1889,1891,1893,1896],{"class":65,"line":437},[63,1864,1865],{"class":103},"df[",[63,1867,1868],{"class":73},"\"duration\"",[63,1870,1871],{"class":103},"] ",[63,1873,186],{"class":99},[63,1875,1876],{"class":103}," df[",[63,1878,1868],{"class":73},[63,1880,1871],{"class":103},[63,1882,1397],{"class":99},[63,1884,1885],{"class":103}," pd.Timedelta(",[63,1887,1888],{"class":182},"days",[63,1890,186],{"class":99},[63,1892,378],{"class":189},[63,1894,1895],{"class":103},")            ",[63,1897,1898],{"class":369},"# fraction of a day, a plain float\n",[63,1900,1901,1903,1905,1907,1909,1911,1913,1915],{"class":65,"line":474},[63,1902,1782],{"class":99},[63,1904,1785],{"class":103},[63,1906,1788],{"class":73},[63,1908,22],{"class":103},[63,1910,1793],{"class":182},[63,1912,186],{"class":99},[63,1914,1798],{"class":73},[63,1916,165],{"class":103},[63,1918,1919,1921,1923,1925,1927,1929,1931,1933,1935,1937],{"class":65,"line":493},[63,1920,1805],{"class":182},[63,1922,186],{"class":99},[63,1924,332],{"class":73},[63,1926,22],{"class":103},[63,1928,1814],{"class":182},[63,1930,186],{"class":99},[63,1932,313],{"class":73},[63,1934,1821],{"class":103},[63,1936,255],{"class":99},[63,1938,1826],{"class":103},[63,1940,1941,1943,1945,1947,1949],{"class":65,"line":499},[63,1942,1831],{"class":103},[63,1944,1834],{"class":182},[63,1946,186],{"class":99},[63,1948,1839],{"class":189},[63,1950,202],{"class":103},[63,1952,1953,1956,1959,1962,1964,1966,1968,1970,1972,1975,1977,1979,1981],{"class":65,"line":1108},[63,1954,1955],{"class":103},"    xw.sheets[",[63,1957,1958],{"class":73},"\"Sheet1\"",[63,1960,1961],{"class":103},"].set_column(",[63,1963,363],{"class":189},[63,1965,22],{"class":103},[63,1967,363],{"class":189},[63,1969,22],{"class":103},[63,1971,358],{"class":189},[63,1973,1974],{"class":103},", xw.book.add_format({",[63,1976,307],{"class":73},[63,1978,310],{"class":103},[63,1980,1281],{"class":73},[63,1982,1170],{"class":103},[63,1984,1985,1987,1989,1992,1994,1996],{"class":65,"line":1113},[63,1986,502],{"class":189},[63,1988,1024],{"class":103},[63,1990,1991],{"class":73},"\"as days with a column format:\"",[63,1993,1188],{"class":103},[63,1995,1788],{"class":73},[63,1997,510],{"class":103},[10,1999,2000,2003,2004,2006,2007,2009,2010,2012,2013,2015,2016,2019,2020,2022,2023,2026,2027,2029,2030,2033,2034,2037,2038,2041],{},[19,2001,2002],{},"datetime_format"," applies to datetime columns and ",[19,2005,1814],{}," to ",[19,2008,25],{}," objects. Durations are the trap: pandas writes a ",[19,2011,32],{}," column as a number of days with the cell format ",[19,2014,343],{},", so 37 hours 5 minutes appears as ",[2017,2018,363],"strong",{}," and 7½ hours as ",[2017,2021,343],{}," — and because the format is on each cell, a column format cannot override it. Converting the column to a plain fraction of a day first, by dividing by ",[19,2024,2025],{},"pd.Timedelta(days=1)",", leaves the cells unformatted, so a ",[19,2028,1447],{}," column format added through the underlying XlsxWriter workbook (",[19,2031,2032],{},"xw.book",") takes effect and the durations read 37:05 and 7:30. A timezone-aware pandas column raises its own error at this point — convert with ",[19,2035,2036],{},"dt.tz_convert(...)"," and then ",[19,2039,2040],{},"dt.tz_localize(None)"," first, the pandas equivalent of Step 2.",[651,2043,660,2048,660,2051,660,2054,660,2057,660,2061,660,2068,660,2074,660,2079,660,2084,660,2087,660,2090,660,2096,660,2101,660,2104,660,2107,660,2110,660,2114,660,2121,660,2127,660,2131,660,2135,660,2139,660,2142,660,2145,660,2150,660,2155,660,2158],{"viewBox":2044,"role":654,"ariaLabelledBy":2045,"xmlns":658,"style":1467},"4 0 752 142",[2046,2047],"xd-pandas-t","xd-pandas-d",[662,2049,2050],{"id":2046},"Getting durations from pandas into Excel",[666,2052,2053],{"id":2047},"pandas writes a timedelta column as days with the cell format 0, so 37 hours shows as 2. Dividing the column by one day turns it into plain floats without a cell format, and a [h]:mm column format added through the XlsxWriter workbook then displays 37:05.",[670,2055],{"x":672,"y":343,"width":1476,"height":2056,"fill":675},"142",[670,2058],{"x":678,"y":1480,"width":2059,"height":2060,"rx":1600,"fill":682,"stroke":683,"style":867},"153.0","110.5",[1486,2062,2064],{"transform":2063},"translate(84.5,37.8) scale(1.000)",[1490,2065],{"d":1492,"fill":1493,"stroke":2066,"style":2067},"var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[690,2069,2073],{"x":2070,"y":2071,"style":2072},"96.5","84.2","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","timedelta column",[690,2075,2078],{"x":2070,"y":2076,"style":2077},"103.8","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","37:05:00",[65,2080],{"x1":2081,"y1":2082,"x2":2083,"y2":2082,"stroke":866,"style":867},"178.0","71.2","200.0",[869,2085],{"points":2086,"fill":872},"204.0,71.2 195.0,76.2 195.0,66.2",[670,2088],{"x":2089,"y":1480,"width":2059,"height":2060,"rx":1600,"fill":1483,"stroke":1484,"style":867},"209.0",[1486,2091,2093],{"transform":2092},"translate(273.5,37.8) scale(1.000)",[1490,2094],{"d":2095,"fill":1493,"stroke":1494,"style":2067},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4",[690,2097,2100],{"x":2098,"y":2071,"style":2099},"285.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","to_excel as is",[690,2102,2103],{"x":2098,"y":2076,"style":2077},"cell format 0 → \"2\"",[65,2105],{"x1":2106,"y1":2082,"x2":1519,"y2":2082,"stroke":866,"style":867},"367.0",[869,2108],{"points":2109,"fill":872},"393.0,71.2 384.0,76.2 384.0,66.2",[670,2111],{"x":2112,"y":1480,"width":2059,"height":2060,"rx":1600,"fill":2113,"stroke":866,"style":867},"398.0","#f0f4ff",[1486,2115,2117],{"transform":2116},"translate(462.5,29.0) scale(1.000)",[1490,2118],{"d":2119,"fill":1493,"stroke":2120,"style":2067},"M5 9h14 M4 15h14 M10 4l-2 16 M16 4l-2 16","var(--brand-strong,#4338ca)",[690,2122,2126],{"x":2123,"y":2124,"style":2125},"474.5","75.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","÷",[690,2128,2130],{"x":2123,"y":2129,"style":2125},"93.0","Timedelta(days=1)",[690,2132,2134],{"x":2123,"y":2133,"style":2077},"112.5","plain float 1.545",[65,2136],{"x1":2137,"y1":2082,"x2":2138,"y2":2082,"stroke":866,"style":867},"556.0","578.0",[869,2140],{"points":2141,"fill":872},"582.0,71.2 573.0,76.2 573.0,66.2",[670,2143],{"x":2144,"y":1480,"width":2059,"height":2060,"rx":1600,"fill":831,"stroke":832,"style":867},"587.0",[1486,2146,2148],{"transform":2147},"translate(651.5,29.0) scale(1.000)",[1490,2149],{"d":1525,"fill":1493,"stroke":1526,"style":2067},[690,2151,2154],{"x":2152,"y":2124,"style":2153},"663.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","[h]:mm column",[690,2156,2157],{"x":2152,"y":2129,"style":2153},"format",[690,2159,2160],{"x":2152,"y":2133,"style":2077},"shows 37:05",[10,2162,2163,2164,2167,2168,2171,2172,2174,2175,47],{},"Whichever route writes the file, a quick test that reads the workbook back with openpyxl and checks ",[19,2165,2166],{},"cell.number_format"," on a date, a timestamp and a duration column catches all of these problems before a report goes out: an unformatted date shows up as the format ",[19,2169,2170],{},"General",", a wrapped duration as ",[19,2173,1443],{}," without brackets, and a pandas duration as ",[19,2176,343],{},[49,2178,2180],{"id":2179},"common-pitfalls","Common pitfalls",[2182,2183,2184,2194,2202,2213,2219],"ul",{},[2185,2186,2187,2190,2191,47],"li",{},[2017,2188,2189],{},"Dates showing as 46297."," Give the cell a date format, or set ",[19,2192,2193],{},"default_date_format",[2185,2195,2196,2201],{},[2017,2197,2198,2200],{},[19,2199,1208],{}," without converting."," It keeps the clock time; convert to the readers' zone first.",[2185,2203,2204,2209,2210,2212],{},[2017,2205,2206,2207,47],{},"Durations with ",[19,2208,1443],{}," Use ",[19,2211,1447],{}," so hours do not wrap at 24.",[2185,2214,2215,2218],{},[2017,2216,2217],{},"Dates before 1900."," Excel cannot show them; write ISO text.",[2185,2220,2221,2224,2225,2227,2228,47],{},[2017,2222,2223],{},"pandas durations as decimals."," Add a ",[19,2226,1447],{}," column format through ",[19,2229,2032],{},[49,2231,2233],{"id":2232},"conclusion","Conclusion",[10,2235,2236,2237,2239,2240,2242,2243,2245,2246,29,2248,2250,2251,2253],{},"XlsxWriter stores dates, times and durations as Excel serial numbers, and a number format makes them readable: pass a format to ",[19,2238,528],{}," or set ",[19,2241,2193],{},". Convert timezone-aware datetimes to the readers' zone before stripping the timezone, format durations with ",[19,2244,1447],{}," so they do not wrap, write dates before 1900 as text, and in pandas use ",[19,2247,2002],{},[19,2249,1814],{}," on the ",[19,2252,1692],{},", adding duration formats through the workbook object.",[49,2255,2257],{"id":2256},"frequently-asked-questions","Frequently asked questions",[10,2259,2260,2263],{},[2017,2261,2262],{},"Why do my dates appear as numbers like 46297 in Excel?","\nThe cell has no date number format. Pass a format to write_datetime or set the workbook's default_date_format option.",[10,2265,2266,2269],{},[2017,2267,2268],{},"How do I fix \"Excel doesn't support timezones in datetimes\" in XlsxWriter?","\nConvert the datetime to the timezone your readers use and remove tzinfo, or use the remove_timezone workbook option if the clock time can be kept as it is.",[10,2271,2272,2275,2276,2279,2280,2282],{},[2017,2273,2274],{},"How do I write a duration longer than 24 hours?","\nWrite a timedelta with write_datetime and format it with ",[63,2277,2278],{},"h",":mm or ",[63,2281,2278],{},":mm:ss so the hours do not wrap.",[10,2284,2285,2288],{},[2017,2286,2287],{},"Can Excel store dates before 1900?","\nNo. Excel's date system starts in 1900, so write earlier dates as text.",[49,2290,2292],{"id":2291},"related","Related",[2182,2294,2295,2301,2308,2315],{},[2185,2296,2297,2298,2300],{},"Up one level: ",[43,2299,46],{"href":45}," — reports with XlsxWriter.",[2185,2302,2303,2307],{},[43,2304,2306],{"href":2305},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel\u002Fformat-dates-in-excel-cells-with-python\u002F","Format Dates in Excel Cells with Python"," — date formats with openpyxl.",[2185,2309,2310,2314],{},[43,2311,2313],{"href":2312},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-dates-without-time-from-pandas-to-excel\u002F","Write Dates Without Time from pandas to Excel"," — the pandas side.",[2185,2316,2317,2321],{},[43,2318,2320],{"href":2319},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-excel-time-values-and-durations\u002F","Convert Excel Time Values and Durations"," — reading them back.",[2323,2324,2325],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}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 .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":59,"searchDepth":107,"depth":107,"links":2327},[2328,2329,2330,2331,2332,2333,2334,2335,2336],{"id":51,"depth":107,"text":52},{"id":239,"depth":107,"text":240},{"id":889,"depth":107,"text":890},{"id":1220,"depth":107,"text":1221},{"id":1547,"depth":107,"text":1548},{"id":2179,"depth":107,"text":2180},{"id":2232,"depth":107,"text":2233},{"id":2256,"depth":107,"text":2257},{"id":2291,"depth":107,"text":2292},"2026-10-02","Write dates, times and durations to Excel correctly with XlsxWriter: why a date written without a format appears as 46297, setting a default date format, handling the timezone error by converting before stripping, durations over 24 hours with [h]:mm, times of day, dates before 1900, and the same settings through pandas' ExcelWriter.","md",[2341,2343,2345,2347],{"q":2262,"a":2342},"The cell has no date number format. Pass a format to write_datetime or set the workbook's default_date_format option.",{"q":2268,"a":2344},"Convert the datetime to the timezone your readers use and remove tzinfo, or use the remove_timezone workbook option if the clock time can be kept as it is.",{"q":2274,"a":2346},"Write a timedelta with write_datetime and format it with [h]:mm or [h]:mm:ss so the hours do not wrap.",{"q":2287,"a":2348},"No. Excel's date system starts in 1900, so write earlier dates as text.","write dates times and durations with xlsxwriter",null,{"breadcrumb":2352},[2353,2355,2358],{"name":2354,"item":1397},"Home",{"name":2356,"item":2357},"Formatting and Charting Excel Reports with Python","\u002Fformatting-and-charting-excel-reports-with-python\u002F",{"name":46,"item":45},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-dates-times-and-durations-with-xlsxwriter",{"title":2361,"description":2362},"Write Dates, Times and Durations with XlsxWriter in Python","XlsxWriter date handling: write_datetime and formats, default_date_format, the \"Excel doesn't support timezones\" error and remove_timezone, timedelta durations with [h]:mm, pre-1900 dates and pandas datetime_format.","write-dates-times-and-durations-with-xlsxwriter","formatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-dates-times-and-durations-with-xlsxwriter\u002Findex",[2366,2367],"xlsxwriter","number-formats","how-to","3ke2A3oeW_PyoOLefQkJ_q_5NTGG6TWb-NSvOrEGi5E",[2371,2375],{"title":2372,"path":2373,"stem":2374,"children":-1},"Write an Excel Table with Formula Columns Using XlsxWriter","\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-an-excel-table-with-formula-columns-using-xlsxwriter","formatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-an-excel-table-with-formula-columns-using-xlsxwriter\u002Findex",{"title":2376,"path":2377,"stem":2378,"children":-1},"Write Rich Text with Mixed Formats in One Cell with xlsxwriter","\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-rich-text-in-a-cell-with-xlsxwriter","formatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-rich-text-in-a-cell-with-xlsxwriter\u002Findex",[2380,2382],{"path":2381,"title":46},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter",{"path":2383,"title":2356},"\u002Fformatting-and-charting-excel-reports-with-python",[],[2386,2390,2393,2396,2399,2402],{"path":2387,"title":2388,"kind":2389},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-budget-vs-actual-variance-report","Build a Budget vs Actual Variance Report in Excel with Python","compare",{"path":2391,"title":2392,"kind":2368},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fcombine-chart-types-and-chartsheets-with-xlsxwriter","Combine Chart Types and Chartsheets with XlsxWriter",{"path":2394,"title":2395,"kind":2368},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fdefine-names-and-protect-sheets-with-xlsxwriter","Define Names and Protect Sheets with XlsxWriter",{"path":2397,"title":2398,"kind":2368},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Ffreeze-panes-and-set-zoom-with-xlsxwriter","Freeze Panes and Set Zoom with XlsxWriter",{"path":2400,"title":2401,"kind":2368},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Finsert-checkboxes-with-xlsxwriter","Insert Checkboxes in Excel with xlsxwriter",{"path":2403,"title":2404,"kind":2368},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fset-print-options-headers-and-footers-with-xlsxwriter","Set Print Options, Headers and Footers with XlsxWriter",1790972108769]