[{"data":1,"prerenderedAt":2077},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-dates-without-time-from-pandas-to-excel":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-dates-without-time-from-pandas-to-excel":2043,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-dates-without-time-from-pandas-to-excel":2052,"children:\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-dates-without-time-from-pandas-to-excel":2057,"related:\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-dates-without-time-from-pandas-to-excel":2058},{"id":4,"title":5,"body":6,"dateModified":2009,"datePublished":2009,"description":2010,"extension":2011,"faq":2012,"keyword":2021,"kind":2022,"meta":2023,"navigation":328,"path":2031,"seo":2032,"slug":2035,"stem":2036,"topics":2037,"type":2041,"__hash__":2042},"docs\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-dates-without-time-from-pandas-to-excel\u002Findex.md","Write Dates Without the Time Part from pandas to Excel",{"type":7,"value":8,"toc":1994},"minimark",[9,13,24,45,253,258,286,478,484,488,534,548,552,567,636,646,650,667,750,757,766,829,832,1039,1043,1050,1279,1293,1325,1329,1332,1589,1606,1610,1613,1693,1696,1824,1828,1840,1844,1886,1890,1901,1905,1929,1933,1939,1945,1951,1957,1961,1990],[10,11,12],"p",{},"A DataFrame of order dates goes to Excel and every cell comes out like this:",[14,15,21],"pre",{"className":16,"code":18,"language":19,"meta":20},[17],"language-text","2026-03-01 00:00:00\n","text","",[22,23,18],"code",{"__ignoreMap":20},[10,25,26,27,30,31,34,35,38,39,44],{},"The value is fine — it is a real Excel date at midnight — but the display shows a time nobody asked for. pandas holds dates in ",[22,28,29],{},"datetime64"," columns, which always include a time of day, and ",[22,32,33],{},"to_excel"," writes them with the format ",[22,36,37],{},"YYYY-MM-DD HH:MM:SS",". The fix is to change either what you write or how Excel is told to display it, and the right choice depends on whether the times carry information. This page belongs to ",[40,41,43],"a",{"href":42},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002F","Writing DataFrames to Excel with Pandas",".",[46,47,55,56,55,60,55,64,55,72,55,81,55,85,55,91,55,95,55,99,55,103,55,108,55,110,55,114,55,116,55,119,55,122,55,126,55,131,55,135,55,137,55,141,55,144,55,148,55,150,55,153,55,155,55,158,55,161,55,165,55,168,55,171,55,174,55,176,55,179,55,181,55,183,55,185,55,187,55,189,55,191,55,195,55,199,55,201,55,203,55,205,55,207,55,209,55,212,55,214,55,216,55,222,55,226,55,234,55,239,55,247],"svg",{"viewBox":48,"role":49,"ariaLabelledBy":50,"xmlns":53,"style":54},"23 0 714 164","img",[51,52],"wdt-before-t","wdt-before-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:714px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[57,58,59],"title",{"id":51},"The same dates with the default and a date-only format",[61,62,63],"desc",{"id":52},"Left: dates written from a datetime64 column show 2026-03-01 00:00:00 and 2026-03-02 00:00:00 because of the default date-time format. Right: written as dates, the same cells show 2026-03-01 and 2026-03-02 and remain real dates.",[65,66],"rect",{"x":67,"y":68,"width":69,"height":70,"fill":71},"23","0","714","164","#ffffff",[65,73],{"x":74,"y":75,"width":76,"height":77,"rx":68,"fill":78,"stroke":79,"style":80},"39.4","40.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[65,82],{"x":83,"y":75,"width":84,"height":77,"rx":68,"fill":78,"stroke":79,"style":80},"71.4","163.8",[19,86,90],{"x":87,"y":88,"style":89},"153.2","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[65,92],{"x":93,"y":75,"width":94,"height":77,"rx":68,"fill":78,"stroke":79,"style":80},"235.1","70.9",[19,96,98],{"x":97,"y":88,"style":89},"270.6","B",[65,100],{"x":74,"y":101,"width":76,"height":102,"rx":68,"fill":78,"stroke":79,"style":80},"64.0","28.0",[19,104,107],{"x":105,"y":106,"style":89},"55.4","83.0","1",[65,109],{"x":83,"y":101,"width":84,"height":102,"rx":68,"fill":71,"stroke":79,"style":80},[19,111,113],{"x":87,"y":106,"style":112},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","order_date",[65,115],{"x":93,"y":101,"width":94,"height":102,"rx":68,"fill":71,"stroke":79,"style":80},[19,117,118],{"x":97,"y":106,"style":112},"amount",[65,120],{"x":74,"y":121,"width":76,"height":102,"rx":68,"fill":78,"stroke":79,"style":80},"92.0",[19,123,125],{"x":105,"y":124,"style":89},"111.0","2",[65,127],{"x":83,"y":121,"width":84,"height":102,"rx":68,"fill":128,"stroke":129,"style":130},"#fee8f2","var(--accent,#f43f8f)","stroke-width:1.5px",[19,132,134],{"x":87,"y":124,"style":133},"font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","2026-03-01 00:00:00",[65,136],{"x":93,"y":121,"width":94,"height":102,"rx":68,"fill":71,"stroke":79,"style":80},[19,138,140],{"x":97,"y":124,"style":139},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","120",[65,142],{"x":74,"y":143,"width":76,"height":102,"rx":68,"fill":78,"stroke":79,"style":80},"120.0",[19,145,147],{"x":105,"y":146,"style":89},"139.0","3",[65,149],{"x":83,"y":143,"width":84,"height":102,"rx":68,"fill":128,"stroke":129,"style":130},[19,151,152],{"x":87,"y":146,"style":133},"2026-03-02 00:00:00",[65,154],{"x":93,"y":143,"width":94,"height":102,"rx":68,"fill":71,"stroke":79,"style":80},[19,156,157],{"x":97,"y":146,"style":139},"88",[65,159],{"x":160,"y":75,"width":76,"height":77,"rx":68,"fill":78,"stroke":79,"style":80},"516.4",[65,162],{"x":163,"y":75,"width":164,"height":77,"rx":68,"fill":78,"stroke":79,"style":80},"548.4","101.4",[19,166,90],{"x":167,"y":88,"style":89},"599.1",[65,169],{"x":170,"y":75,"width":94,"height":77,"rx":68,"fill":78,"stroke":79,"style":80},"649.8",[19,172,98],{"x":173,"y":88,"style":89},"685.2",[65,175],{"x":160,"y":101,"width":76,"height":102,"rx":68,"fill":78,"stroke":79,"style":80},[19,177,107],{"x":178,"y":106,"style":89},"532.4",[65,180],{"x":163,"y":101,"width":164,"height":102,"rx":68,"fill":71,"stroke":79,"style":80},[19,182,113],{"x":167,"y":106,"style":112},[65,184],{"x":170,"y":101,"width":94,"height":102,"rx":68,"fill":71,"stroke":79,"style":80},[19,186,118],{"x":173,"y":106,"style":112},[65,188],{"x":160,"y":121,"width":76,"height":102,"rx":68,"fill":78,"stroke":79,"style":80},[19,190,125],{"x":178,"y":124,"style":89},[65,192],{"x":163,"y":121,"width":164,"height":102,"rx":68,"fill":193,"stroke":194,"style":130},"#d9f4f1","var(--teal,#0f9488)",[19,196,198],{"x":167,"y":124,"style":197},"font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","2026-03-01",[65,200],{"x":170,"y":121,"width":94,"height":102,"rx":68,"fill":71,"stroke":79,"style":80},[19,202,140],{"x":173,"y":124,"style":139},[65,204],{"x":160,"y":143,"width":76,"height":102,"rx":68,"fill":78,"stroke":79,"style":80},[19,206,147],{"x":178,"y":146,"style":89},[65,208],{"x":163,"y":143,"width":164,"height":102,"rx":68,"fill":193,"stroke":194,"style":130},[19,210,211],{"x":167,"y":146,"style":197},"2026-03-02",[65,213],{"x":170,"y":143,"width":94,"height":102,"rx":68,"fill":71,"stroke":79,"style":80},[19,215,157],{"x":173,"y":146,"style":139},[19,217,221],{"x":218,"y":219,"style":220},"172.7","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","default to_excel",[19,223,225],{"x":224,"y":219,"style":220},"618.5","date-only display",[227,228],"line",{"x1":229,"y1":230,"x2":231,"y2":230,"stroke":232,"style":233},"316.0","94.0","502.4","var(--brand,#5b5cf0)","stroke-width:2px",[235,236],"polygon",{"points":237,"fill":238},"506.4,94.0 497.4,99.0 497.4,89.0","#5b5cf0",[65,240],{"x":241,"y":242,"width":243,"height":244,"rx":245,"fill":71,"stroke":79,"style":246},"343.0","61.0","136.3","22.0","11","stroke-width:1.2px",[19,248,252],{"x":249,"y":250,"style":251},"411.2","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","date-only format",[254,255,257],"h2",{"id":256},"prerequisites","Prerequisites",[14,259,263],{"className":260,"code":261,"language":262,"meta":20,"style":20},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl xlsxwriter\n","bash",[22,264,265],{"__ignoreMap":20},[266,267,269,273,277,280,283],"span",{"class":227,"line":268},1,[266,270,272],{"class":271},"sMTad","pip",[266,274,276],{"class":275},"srMev"," install",[266,278,279],{"class":275}," pandas",[266,281,282],{"class":275}," openpyxl",[266,284,285],{"class":275}," xlsxwriter\n",[14,287,291],{"className":288,"code":289,"language":290,"meta":20,"style":20},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\nfrom openpyxl import load_workbook\n\norders = pd.DataFrame({\n    \"order_date\": pd.to_datetime([\"2026-03-01\", \"2026-03-02\", \"2026-03-15\"]),\n    \"shipped_at\": pd.to_datetime([\"2026-03-02 09:15\", \"2026-03-03 14:30\", None]),\n    \"amount\": [120, 88, 240],\n})\n\ndef formats(path, row=2):\n    ws = load_workbook(path).active\n    return [(c.column_letter, c.number_format) for c in ws[row]]\n","python",[22,292,293,309,323,330,342,368,392,415,421,426,446,457],{"__ignoreMap":20},[266,294,295,299,303,306],{"class":227,"line":268},[266,296,298],{"class":297},"s-kum","import",[266,300,302],{"class":301},"skGVy"," pandas ",[266,304,305],{"class":297},"as",[266,307,308],{"class":301}," pd\n",[266,310,312,315,318,320],{"class":227,"line":311},2,[266,313,314],{"class":297},"from",[266,316,317],{"class":301}," openpyxl ",[266,319,298],{"class":297},[266,321,322],{"class":301}," load_workbook\n",[266,324,326],{"class":227,"line":325},3,[266,327,329],{"emptyLinePlaceholder":328},true,"\n",[266,331,333,336,339],{"class":227,"line":332},4,[266,334,335],{"class":301},"orders ",[266,337,338],{"class":297},"=",[266,340,341],{"class":301}," pd.DataFrame({\n",[266,343,345,348,351,354,357,360,362,365],{"class":227,"line":344},5,[266,346,347],{"class":275},"    \"order_date\"",[266,349,350],{"class":301},": pd.to_datetime([",[266,352,353],{"class":275},"\"2026-03-01\"",[266,355,356],{"class":301},", ",[266,358,359],{"class":275},"\"2026-03-02\"",[266,361,356],{"class":301},[266,363,364],{"class":275},"\"2026-03-15\"",[266,366,367],{"class":301},"]),\n",[266,369,371,374,376,379,381,384,386,390],{"class":227,"line":370},6,[266,372,373],{"class":275},"    \"shipped_at\"",[266,375,350],{"class":301},[266,377,378],{"class":275},"\"2026-03-02 09:15\"",[266,380,356],{"class":301},[266,382,383],{"class":275},"\"2026-03-03 14:30\"",[266,385,356],{"class":301},[266,387,389],{"class":388},"sP0c6","None",[266,391,367],{"class":301},[266,393,395,398,401,403,405,407,409,412],{"class":227,"line":394},7,[266,396,397],{"class":275},"    \"amount\"",[266,399,400],{"class":301},": [",[266,402,140],{"class":388},[266,404,356],{"class":301},[266,406,157],{"class":388},[266,408,356],{"class":301},[266,410,411],{"class":388},"240",[266,413,414],{"class":301},"],\n",[266,416,418],{"class":227,"line":417},8,[266,419,420],{"class":301},"})\n",[266,422,424],{"class":227,"line":423},9,[266,425,329],{"emptyLinePlaceholder":328},[266,427,429,432,436,439,441,443],{"class":227,"line":428},10,[266,430,431],{"class":297},"def",[266,433,435],{"class":434},"s_Opv"," formats",[266,437,438],{"class":301},"(path, row",[266,440,338],{"class":297},[266,442,125],{"class":388},[266,444,445],{"class":301},"):\n",[266,447,449,452,454],{"class":227,"line":448},11,[266,450,451],{"class":301},"    ws ",[266,453,338],{"class":297},[266,455,456],{"class":301}," load_workbook(path).active\n",[266,458,460,463,466,469,472,475],{"class":227,"line":459},12,[266,461,462],{"class":297},"    return",[266,464,465],{"class":301}," [(c.column_letter, c.number_format) ",[266,467,468],{"class":297},"for",[266,470,471],{"class":301}," c ",[266,473,474],{"class":297},"in",[266,476,477],{"class":301}," ws[row]]\n",[10,479,480,483],{},[22,481,482],{},"formats"," reads back the number format of each cell in a row, which is how the rest of this page checks what was written.",[254,485,487],{"id":486},"step-1-confirm-what-pandas-writes","Step 1 — Confirm what pandas writes",[14,489,491],{"className":288,"code":490,"language":290,"meta":20,"style":20},"orders.to_excel(\"default.xlsx\", index=False)\nprint(formats(\"default.xlsx\"))\n# [('A', 'YYYY-MM-DD HH:MM:SS'), ('B', 'YYYY-MM-DD HH:MM:SS'), ('C', 'General')]\n",[22,492,493,515,528],{"__ignoreMap":20},[266,494,495,498,501,503,507,509,512],{"class":227,"line":268},[266,496,497],{"class":301},"orders.to_excel(",[266,499,500],{"class":275},"\"default.xlsx\"",[266,502,356],{"class":301},[266,504,506],{"class":505},"sa561","index",[266,508,338],{"class":297},[266,510,511],{"class":388},"False",[266,513,514],{"class":301},")\n",[266,516,517,520,523,525],{"class":227,"line":311},[266,518,519],{"class":388},"print",[266,521,522],{"class":301},"(formats(",[266,524,500],{"class":275},[266,526,527],{"class":301},"))\n",[266,529,530],{"class":227,"line":325},[266,531,533],{"class":532},"s-wDw","# [('A', 'YYYY-MM-DD HH:MM:SS'), ('B', 'YYYY-MM-DD HH:MM:SS'), ('C', 'General')]\n",[10,535,536,537,540,541,543,544,547],{},"Both date columns get the date-and-time format. Normalising the times away with ",[22,538,539],{},"dt.normalize()"," does not change that: the column is still ",[22,542,29],{},", so the cells still get the date-time format and still show ",[22,545,546],{},"00:00:00",". What matters to pandas is the column's type, not whether the times happen to be midnight.",[254,549,551],{"id":550},"step-2-write-python-date-objects","Step 2 — Write Python date objects",[10,553,554,555,558,559,562,563,566],{},"The simplest fix works with either engine. Convert the column to Python ",[22,556,557],{},"date"," objects with ",[22,560,561],{},".dt.date",". pandas writes those with its date format, ",[22,564,565],{},"YYYY-MM-DD",", and they remain real dates in Excel:",[14,568,570],{"className":288,"code":569,"language":290,"meta":20,"style":20},"out = orders.copy()\nout[\"order_date\"] = out[\"order_date\"].dt.date\nout.to_excel(\"dates.xlsx\", index=False)\nprint(formats(\"dates.xlsx\"))\n# [('A', 'YYYY-MM-DD'), ('B', 'YYYY-MM-DD HH:MM:SS'), ('C', 'General')]\n",[22,571,572,582,603,621,631],{"__ignoreMap":20},[266,573,574,577,579],{"class":227,"line":268},[266,575,576],{"class":301},"out ",[266,578,338],{"class":297},[266,580,581],{"class":301}," orders.copy()\n",[266,583,584,587,590,593,595,598,600],{"class":227,"line":311},[266,585,586],{"class":301},"out[",[266,588,589],{"class":275},"\"order_date\"",[266,591,592],{"class":301},"] ",[266,594,338],{"class":297},[266,596,597],{"class":301}," out[",[266,599,589],{"class":275},[266,601,602],{"class":301},"].dt.date\n",[266,604,605,608,611,613,615,617,619],{"class":227,"line":325},[266,606,607],{"class":301},"out.to_excel(",[266,609,610],{"class":275},"\"dates.xlsx\"",[266,612,356],{"class":301},[266,614,506],{"class":505},[266,616,338],{"class":297},[266,618,511],{"class":388},[266,620,514],{"class":301},[266,622,623,625,627,629],{"class":227,"line":332},[266,624,519],{"class":388},[266,626,522],{"class":301},[266,628,610],{"class":275},[266,630,527],{"class":301},[266,632,633],{"class":227,"line":344},[266,634,635],{"class":532},"# [('A', 'YYYY-MM-DD'), ('B', 'YYYY-MM-DD HH:MM:SS'), ('C', 'General')]\n",[10,637,638,639,641,642,645],{},"Use this when the time genuinely does not exist — order dates, invoice dates, birthdays. ",[22,640,561],{}," drops the time, so apply it only to columns where losing the time is the intent. The column becomes ",[22,643,644],{},"object"," dtype in pandas, which is fine as the last step before writing but inconvenient if you keep calculating afterwards, so convert a copy.",[254,647,649],{"id":648},"step-3-set-the-formats-on-the-writer-xlsxwriter-engine","Step 3 — Set the formats on the writer (xlsxwriter engine)",[10,651,652,655,656,659,660,663,664,666],{},[22,653,654],{},"pd.ExcelWriter"," accepts ",[22,657,658],{},"date_format"," for date objects and ",[22,661,662],{},"datetime_format"," for ",[22,665,29],{}," values. With the xlsxwriter engine they are applied to every date cell the writer produces:",[14,668,670],{"className":288,"code":669,"language":290,"meta":20,"style":20},"with pd.ExcelWriter(\"writer_formats.xlsx\", engine=\"xlsxwriter\",\n                    datetime_format=\"DD\u002FMM\u002FYYYY\", date_format=\"DD\u002FMM\u002FYYYY\") as writer:\n    orders.to_excel(writer, index=False)\nprint(formats(\"writer_formats.xlsx\"))\n# [('A', 'DD\u002FMM\u002FYYYY'), ('B', 'DD\u002FMM\u002FYYYY'), ('C', 'General')]\n",[22,671,672,696,722,735,745],{"__ignoreMap":20},[266,673,674,677,680,683,685,688,690,693],{"class":227,"line":268},[266,675,676],{"class":297},"with",[266,678,679],{"class":301}," pd.ExcelWriter(",[266,681,682],{"class":275},"\"writer_formats.xlsx\"",[266,684,356],{"class":301},[266,686,687],{"class":505},"engine",[266,689,338],{"class":297},[266,691,692],{"class":275},"\"xlsxwriter\"",[266,694,695],{"class":301},",\n",[266,697,698,701,703,706,708,710,712,714,717,719],{"class":227,"line":311},[266,699,700],{"class":505},"                    datetime_format",[266,702,338],{"class":297},[266,704,705],{"class":275},"\"DD\u002FMM\u002FYYYY\"",[266,707,356],{"class":301},[266,709,658],{"class":505},[266,711,338],{"class":297},[266,713,705],{"class":275},[266,715,716],{"class":301},") ",[266,718,305],{"class":297},[266,720,721],{"class":301}," writer:\n",[266,723,724,727,729,731,733],{"class":227,"line":325},[266,725,726],{"class":301},"    orders.to_excel(writer, ",[266,728,506],{"class":505},[266,730,338],{"class":297},[266,732,511],{"class":388},[266,734,514],{"class":301},[266,736,737,739,741,743],{"class":227,"line":332},[266,738,519],{"class":388},[266,740,522],{"class":301},[266,742,682],{"class":275},[266,744,527],{"class":301},[266,746,747],{"class":227,"line":344},[266,748,749],{"class":532},"# [('A', 'DD\u002FMM\u002FYYYY'), ('B', 'DD\u002FMM\u002FYYYY'), ('C', 'General')]\n",[10,751,752,753,756],{},"This is the least code when every date in the workbook should look the same. It is also blunt: ",[22,754,755],{},"shipped_at",", which has real times, now hides them too. The values still contain 09:15 and 14:30 — only the display changed — which may or may not be what the report's readers expect.",[10,758,759,760,762,763,765],{},"Check the engine before relying on these arguments. In the pandas version tested here (3.0), the openpyxl writer accepts ",[22,761,658],{}," and ",[22,764,662],{}," without error and then does not apply them:",[14,767,769],{"className":288,"code":768,"language":290,"meta":20,"style":20},"with pd.ExcelWriter(\"ignored.xlsx\", engine=\"openpyxl\", datetime_format=\"DD\u002FMM\u002FYYYY\") as writer:\n    orders.to_excel(writer, index=False)\nprint(formats(\"ignored.xlsx\"))\n# [('A', 'YYYY-MM-DD HH:MM:SS'), ('B', 'YYYY-MM-DD HH:MM:SS'), ('C', 'General')]\n",[22,770,771,803,815,825],{"__ignoreMap":20},[266,772,773,775,777,780,782,784,786,789,791,793,795,797,799,801],{"class":227,"line":268},[266,774,676],{"class":297},[266,776,679],{"class":301},[266,778,779],{"class":275},"\"ignored.xlsx\"",[266,781,356],{"class":301},[266,783,687],{"class":505},[266,785,338],{"class":297},[266,787,788],{"class":275},"\"openpyxl\"",[266,790,356],{"class":301},[266,792,662],{"class":505},[266,794,338],{"class":297},[266,796,705],{"class":275},[266,798,716],{"class":301},[266,800,305],{"class":297},[266,802,721],{"class":301},[266,804,805,807,809,811,813],{"class":227,"line":311},[266,806,726],{"class":301},[266,808,506],{"class":505},[266,810,338],{"class":297},[266,812,511],{"class":388},[266,814,514],{"class":301},[266,816,817,819,821,823],{"class":227,"line":325},[266,818,519],{"class":388},[266,820,522],{"class":301},[266,822,779],{"class":275},[266,824,527],{"class":301},[266,826,827],{"class":227,"line":332},[266,828,533],{"class":532},[10,830,831],{},"No warning, no error, default formats. If your job uses the openpyxl engine — for example because it appends to an existing workbook — use Step 4 instead.",[46,833,55,839,55,842,55,845,55,850,55,855,55,860,55,866,55,870,55,873,55,878,55,881,55,885,55,888,55,892,55,895,55,899,55,901,55,911,55,913,55,918,55,920,55,927,55,929,55,934,55,937,55,941,55,943,55,948,55,950,55,955,55,957,55,962,55,964,55,969,55,972,55,976,55,978,55,983,55,985,55,990,55,992,55,997,55,999,55,1004,55,1007,55,1011,55,1013,55,1018,55,1020,55,1025,55,1027,55,1032,55,1034],{"viewBox":834,"role":49,"ariaLabelledBy":835,"xmlns":53,"style":838},"4 0 752 208",[836,837],"wdt-methods-t","wdt-methods-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[57,840,841],{"id":836},"Which method changes what",[61,843,844],{"id":837},"A comparison of four methods. .dt.date works with both engines, drops the time from the value, and applies to chosen columns. ExcelWriter datetime_format works with xlsxwriter only, keeps the time in the value, and applies to all date cells. Setting number_format with openpyxl works after writing with any engine, keeps the value, and applies to chosen columns. strftime produces text, which is not a real date.",[65,846],{"x":847,"y":68,"width":848,"height":849,"fill":71},"4","752","208",[65,851],{"x":852,"y":853,"width":854,"height":75,"rx":68,"fill":71,"stroke":79,"style":80},"20.0","16.0","212.2",[65,856],{"x":857,"y":853,"width":858,"height":75,"rx":68,"fill":859,"stroke":232,"style":246},"232.2","126.9","#f0f4ff",[19,861,865],{"x":862,"y":863,"style":864},"295.7","34.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Works with",[19,867,869],{"x":862,"y":868,"style":864},"49.0","openpyxl engine",[65,871],{"x":872,"y":853,"width":858,"height":75,"rx":68,"fill":859,"stroke":232,"style":246},"359.2",[19,874,877],{"x":875,"y":876,"style":864},"422.6","41.0","Keeps real dates",[65,879],{"x":880,"y":853,"width":858,"height":75,"rx":68,"fill":859,"stroke":232,"style":246},"486.1",[19,882,884],{"x":883,"y":876,"style":864},"549.6","Keeps the time",[65,886],{"x":887,"y":853,"width":858,"height":75,"rx":68,"fill":859,"stroke":232,"style":246},"613.1",[19,889,891],{"x":890,"y":876,"style":864},"676.5","Per column",[65,893],{"x":852,"y":894,"width":854,"height":863,"rx":68,"fill":78,"stroke":79,"style":80},"56.0",[19,896,561],{"x":76,"y":897,"style":898},"78.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start",[65,900],{"x":857,"y":894,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,903,905],"g",{"transform":904},"translate(286.7,64.0) scale(0.750)",[906,907],"path",{"d":908,"fill":909,"stroke":194,"style":910},"M5 12.5l4.5 4.5L19 7","none","stroke-width:2.40px;stroke-linecap:round;stroke-linejoin:round",[65,912],{"x":872,"y":894,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,914,916],{"transform":915},"translate(413.6,64.0) scale(0.750)",[906,917],{"d":908,"fill":909,"stroke":194,"style":910},[65,919],{"x":880,"y":894,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,921,923],{"transform":922},"translate(541.6,65.0) scale(0.667)",[906,924],{"d":925,"fill":909,"stroke":129,"style":926},"M6 6l12 12 M18 6L6 18","stroke-width:2.70px;stroke-linecap:round;stroke-linejoin:round",[65,928],{"x":887,"y":894,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,930,932],{"transform":931},"translate(667.5,64.0) scale(0.750)",[906,933],{"d":908,"fill":909,"stroke":194,"style":910},[65,935],{"x":852,"y":936,"width":854,"height":863,"rx":68,"fill":78,"stroke":79,"style":80},"90.0",[19,938,940],{"x":76,"y":939,"style":898},"112.0","ExcelWriter datetime_format",[65,942],{"x":857,"y":936,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,944,946],{"transform":945},"translate(287.7,99.0) scale(0.667)",[906,947],{"d":925,"fill":909,"stroke":129,"style":926},[65,949],{"x":872,"y":936,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,951,953],{"transform":952},"translate(413.6,98.0) scale(0.750)",[906,954],{"d":908,"fill":909,"stroke":194,"style":910},[65,956],{"x":880,"y":936,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,958,960],{"transform":959},"translate(540.6,98.0) scale(0.750)",[906,961],{"d":908,"fill":909,"stroke":194,"style":910},[65,963],{"x":887,"y":936,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,965,967],{"transform":966},"translate(668.5,99.0) scale(0.667)",[906,968],{"d":925,"fill":909,"stroke":129,"style":926},[65,970],{"x":852,"y":971,"width":854,"height":863,"rx":68,"fill":78,"stroke":79,"style":80},"124.0",[19,973,975],{"x":76,"y":974,"style":898},"146.0","number_format after writing",[65,977],{"x":857,"y":971,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,979,981],{"transform":980},"translate(286.7,132.0) scale(0.750)",[906,982],{"d":908,"fill":909,"stroke":194,"style":910},[65,984],{"x":872,"y":971,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,986,988],{"transform":987},"translate(413.6,132.0) scale(0.750)",[906,989],{"d":908,"fill":909,"stroke":194,"style":910},[65,991],{"x":880,"y":971,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,993,995],{"transform":994},"translate(540.6,132.0) scale(0.750)",[906,996],{"d":908,"fill":909,"stroke":194,"style":910},[65,998],{"x":887,"y":971,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,1000,1002],{"transform":1001},"translate(667.5,132.0) scale(0.750)",[906,1003],{"d":908,"fill":909,"stroke":194,"style":910},[65,1005],{"x":852,"y":1006,"width":854,"height":863,"rx":68,"fill":78,"stroke":79,"style":80},"158.0",[19,1008,1010],{"x":76,"y":1009,"style":898},"180.0","strftime to text",[65,1012],{"x":857,"y":1006,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,1014,1016],{"transform":1015},"translate(286.7,166.0) scale(0.750)",[906,1017],{"d":908,"fill":909,"stroke":194,"style":910},[65,1019],{"x":872,"y":1006,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,1021,1023],{"transform":1022},"translate(414.6,167.0) scale(0.667)",[906,1024],{"d":925,"fill":909,"stroke":129,"style":926},[65,1026],{"x":880,"y":1006,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,1028,1030],{"transform":1029},"translate(541.6,167.0) scale(0.667)",[906,1031],{"d":925,"fill":909,"stroke":129,"style":926},[65,1033],{"x":887,"y":1006,"width":858,"height":863,"rx":68,"fill":71,"stroke":79,"style":80},[902,1035,1037],{"transform":1036},"translate(667.5,166.0) scale(0.750)",[906,1038],{"d":908,"fill":909,"stroke":194,"style":910},[254,1040,1042],{"id":1041},"step-4-set-a-number-format-per-column-with-openpyxl","Step 4 — Set a number format per column with openpyxl",[10,1044,1045,1046,1049],{},"For full control — dates in one column, date-times in another, a month-only display in a third — set ",[22,1047,1048],{},"number_format"," on the cells after pandas has written them. It works whichever engine wrote the file:",[14,1051,1053],{"className":288,"code":1052,"language":290,"meta":20,"style":20},"orders.to_excel(\"per_column.xlsx\", index=False)\n\nwb = load_workbook(\"per_column.xlsx\")\nws = wb.active\ncolumn_formats = {\"order_date\": \"DD MMM YYYY\", \"shipped_at\": \"DD MMM YYYY HH:MM\"}\nheaders = {cell.value: cell.column for cell in ws[1]}\nfor name, fmt in column_formats.items():\n    col = headers[name]\n    for (cell,) in ws.iter_rows(min_row=2, min_col=col, max_col=col):\n        cell.number_format = fmt\n    ws.column_dimensions[ws.cell(row=1, column=col).column_letter].width = 20\nwb.save(\"per_column.xlsx\")\nprint(formats(\"per_column.xlsx\"))\n# [('A', 'DD MMM YYYY'), ('B', 'DD MMM YYYY HH:MM'), ('C', 'General')]\n",[22,1054,1055,1072,1076,1090,1100,1131,1156,1168,1178,1216,1226,1253,1262,1273],{"__ignoreMap":20},[266,1056,1057,1059,1062,1064,1066,1068,1070],{"class":227,"line":268},[266,1058,497],{"class":301},[266,1060,1061],{"class":275},"\"per_column.xlsx\"",[266,1063,356],{"class":301},[266,1065,506],{"class":505},[266,1067,338],{"class":297},[266,1069,511],{"class":388},[266,1071,514],{"class":301},[266,1073,1074],{"class":227,"line":311},[266,1075,329],{"emptyLinePlaceholder":328},[266,1077,1078,1081,1083,1086,1088],{"class":227,"line":325},[266,1079,1080],{"class":301},"wb ",[266,1082,338],{"class":297},[266,1084,1085],{"class":301}," load_workbook(",[266,1087,1061],{"class":275},[266,1089,514],{"class":301},[266,1091,1092,1095,1097],{"class":227,"line":332},[266,1093,1094],{"class":301},"ws ",[266,1096,338],{"class":297},[266,1098,1099],{"class":301}," wb.active\n",[266,1101,1102,1105,1107,1110,1112,1115,1118,1120,1123,1125,1128],{"class":227,"line":344},[266,1103,1104],{"class":301},"column_formats ",[266,1106,338],{"class":297},[266,1108,1109],{"class":301}," {",[266,1111,589],{"class":275},[266,1113,1114],{"class":301},": ",[266,1116,1117],{"class":275},"\"DD MMM YYYY\"",[266,1119,356],{"class":301},[266,1121,1122],{"class":275},"\"shipped_at\"",[266,1124,1114],{"class":301},[266,1126,1127],{"class":275},"\"DD MMM YYYY HH:MM\"",[266,1129,1130],{"class":301},"}\n",[266,1132,1133,1136,1138,1141,1143,1146,1148,1151,1153],{"class":227,"line":370},[266,1134,1135],{"class":301},"headers ",[266,1137,338],{"class":297},[266,1139,1140],{"class":301}," {cell.value: cell.column ",[266,1142,468],{"class":297},[266,1144,1145],{"class":301}," cell ",[266,1147,474],{"class":297},[266,1149,1150],{"class":301}," ws[",[266,1152,107],{"class":388},[266,1154,1155],{"class":301},"]}\n",[266,1157,1158,1160,1163,1165],{"class":227,"line":394},[266,1159,468],{"class":297},[266,1161,1162],{"class":301}," name, fmt ",[266,1164,474],{"class":297},[266,1166,1167],{"class":301}," column_formats.items():\n",[266,1169,1170,1173,1175],{"class":227,"line":417},[266,1171,1172],{"class":301},"    col ",[266,1174,338],{"class":297},[266,1176,1177],{"class":301}," headers[name]\n",[266,1179,1180,1183,1186,1188,1191,1194,1196,1198,1200,1203,1205,1208,1211,1213],{"class":227,"line":423},[266,1181,1182],{"class":297},"    for",[266,1184,1185],{"class":301}," (cell,) ",[266,1187,474],{"class":297},[266,1189,1190],{"class":301}," ws.iter_rows(",[266,1192,1193],{"class":505},"min_row",[266,1195,338],{"class":297},[266,1197,125],{"class":388},[266,1199,356],{"class":301},[266,1201,1202],{"class":505},"min_col",[266,1204,338],{"class":297},[266,1206,1207],{"class":301},"col, ",[266,1209,1210],{"class":505},"max_col",[266,1212,338],{"class":297},[266,1214,1215],{"class":301},"col):\n",[266,1217,1218,1221,1223],{"class":227,"line":428},[266,1219,1220],{"class":301},"        cell.number_format ",[266,1222,338],{"class":297},[266,1224,1225],{"class":301}," fmt\n",[266,1227,1228,1231,1234,1236,1238,1240,1243,1245,1248,1250],{"class":227,"line":448},[266,1229,1230],{"class":301},"    ws.column_dimensions[ws.cell(",[266,1232,1233],{"class":505},"row",[266,1235,338],{"class":297},[266,1237,107],{"class":388},[266,1239,356],{"class":301},[266,1241,1242],{"class":505},"column",[266,1244,338],{"class":297},[266,1246,1247],{"class":301},"col).column_letter].width ",[266,1249,338],{"class":297},[266,1251,1252],{"class":388}," 20\n",[266,1254,1255,1258,1260],{"class":227,"line":459},[266,1256,1257],{"class":301},"wb.save(",[266,1259,1061],{"class":275},[266,1261,514],{"class":301},[266,1263,1265,1267,1269,1271],{"class":227,"line":1264},13,[266,1266,519],{"class":388},[266,1268,522],{"class":301},[266,1270,1061],{"class":275},[266,1272,527],{"class":301},[266,1274,1276],{"class":227,"line":1275},14,[266,1277,1278],{"class":532},"# [('A', 'DD MMM YYYY'), ('B', 'DD MMM YYYY HH:MM'), ('C', 'General')]\n",[10,1280,1281,1282,1285,1286,1289,1290,1292],{},"Looking columns up by header name rather than letter keeps the code working when columns are added or reordered. Widening the columns matters more than it looks: a date formatted as ",[22,1283,1284],{},"DD MMM YYYY"," in a column too narrow for it shows as ",[22,1287,1288],{},"########",". The empty ",[22,1291,755],{}," cell — a missing value in pandas — is written as an empty cell, so formatting it does nothing visible.",[10,1294,1295,1296,1299,1300,1303,1304,1307,1308,1311,1312,1315,1316,1319,1320,1324],{},"Excel's format codes are not Python's ",[22,1297,1298],{},"strftime"," codes: ",[22,1301,1302],{},"MMM"," is the abbreviated month, ",[22,1305,1306],{},"MM"," after ",[22,1309,1310],{},"HH"," means minutes, and ",[22,1313,1314],{},"DD","\u002F",[22,1317,1318],{},"YYYY"," are day and year. ",[40,1321,1323],{"href":1322},"\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"," lists the codes and their pitfalls.",[254,1326,1328],{"id":1327},"make-it-one-call-for-every-report","Make it one call for every report",[10,1330,1331],{},"Jobs that write several workbooks benefit from wrapping Steps 2 and 4 in a function that takes a DataFrame and a mapping of column names to formats. Columns listed as date-only are converted to dates; every listed column gets its display format; everything else is left alone:",[14,1333,1335],{"className":288,"code":1334,"language":290,"meta":20,"style":20},"def to_excel_with_dates(frame, path, formats, date_only=(), sheet_name=\"Sheet1\"):\n    out = frame.copy()\n    for col in date_only:\n        out[col] = out[col].dt.date\n    out.to_excel(path, index=False, sheet_name=sheet_name)\n    wb = load_workbook(path)\n    ws = wb[sheet_name]\n    headers = {cell.value: cell.column for cell in ws[1]}\n    for name, fmt in formats.items():\n        col = headers[name]\n        for (cell,) in ws.iter_rows(min_row=2, min_col=col, max_col=col):\n            cell.number_format = fmt\n    wb.save(path)\n\nto_excel_with_dates(orders, \"report.xlsx\",\n                    formats={\"order_date\": \"YYYY-MM-DD\", \"shipped_at\": \"YYYY-MM-DD HH:MM\"},\n                    date_only=[\"order_date\"])\nprint(formats(\"report.xlsx\"))\n",[22,1336,1337,1359,1369,1381,1391,1412,1422,1431,1452,1463,1472,1503,1512,1517,1521,1532,1562,1578],{"__ignoreMap":20},[266,1338,1339,1341,1344,1347,1349,1352,1354,1357],{"class":227,"line":268},[266,1340,431],{"class":297},[266,1342,1343],{"class":434}," to_excel_with_dates",[266,1345,1346],{"class":301},"(frame, path, formats, date_only",[266,1348,338],{"class":297},[266,1350,1351],{"class":301},"(), sheet_name",[266,1353,338],{"class":297},[266,1355,1356],{"class":275},"\"Sheet1\"",[266,1358,445],{"class":301},[266,1360,1361,1364,1366],{"class":227,"line":311},[266,1362,1363],{"class":301},"    out ",[266,1365,338],{"class":297},[266,1367,1368],{"class":301}," frame.copy()\n",[266,1370,1371,1373,1376,1378],{"class":227,"line":325},[266,1372,1182],{"class":297},[266,1374,1375],{"class":301}," col ",[266,1377,474],{"class":297},[266,1379,1380],{"class":301}," date_only:\n",[266,1382,1383,1386,1388],{"class":227,"line":332},[266,1384,1385],{"class":301},"        out[col] ",[266,1387,338],{"class":297},[266,1389,1390],{"class":301}," out[col].dt.date\n",[266,1392,1393,1396,1398,1400,1402,1404,1407,1409],{"class":227,"line":344},[266,1394,1395],{"class":301},"    out.to_excel(path, ",[266,1397,506],{"class":505},[266,1399,338],{"class":297},[266,1401,511],{"class":388},[266,1403,356],{"class":301},[266,1405,1406],{"class":505},"sheet_name",[266,1408,338],{"class":297},[266,1410,1411],{"class":301},"sheet_name)\n",[266,1413,1414,1417,1419],{"class":227,"line":370},[266,1415,1416],{"class":301},"    wb ",[266,1418,338],{"class":297},[266,1420,1421],{"class":301}," load_workbook(path)\n",[266,1423,1424,1426,1428],{"class":227,"line":394},[266,1425,451],{"class":301},[266,1427,338],{"class":297},[266,1429,1430],{"class":301}," wb[sheet_name]\n",[266,1432,1433,1436,1438,1440,1442,1444,1446,1448,1450],{"class":227,"line":417},[266,1434,1435],{"class":301},"    headers ",[266,1437,338],{"class":297},[266,1439,1140],{"class":301},[266,1441,468],{"class":297},[266,1443,1145],{"class":301},[266,1445,474],{"class":297},[266,1447,1150],{"class":301},[266,1449,107],{"class":388},[266,1451,1155],{"class":301},[266,1453,1454,1456,1458,1460],{"class":227,"line":423},[266,1455,1182],{"class":297},[266,1457,1162],{"class":301},[266,1459,474],{"class":297},[266,1461,1462],{"class":301}," formats.items():\n",[266,1464,1465,1468,1470],{"class":227,"line":428},[266,1466,1467],{"class":301},"        col ",[266,1469,338],{"class":297},[266,1471,1177],{"class":301},[266,1473,1474,1477,1479,1481,1483,1485,1487,1489,1491,1493,1495,1497,1499,1501],{"class":227,"line":448},[266,1475,1476],{"class":297},"        for",[266,1478,1185],{"class":301},[266,1480,474],{"class":297},[266,1482,1190],{"class":301},[266,1484,1193],{"class":505},[266,1486,338],{"class":297},[266,1488,125],{"class":388},[266,1490,356],{"class":301},[266,1492,1202],{"class":505},[266,1494,338],{"class":297},[266,1496,1207],{"class":301},[266,1498,1210],{"class":505},[266,1500,338],{"class":297},[266,1502,1215],{"class":301},[266,1504,1505,1508,1510],{"class":227,"line":459},[266,1506,1507],{"class":301},"            cell.number_format ",[266,1509,338],{"class":297},[266,1511,1225],{"class":301},[266,1513,1514],{"class":227,"line":1264},[266,1515,1516],{"class":301},"    wb.save(path)\n",[266,1518,1519],{"class":227,"line":1275},[266,1520,329],{"emptyLinePlaceholder":328},[266,1522,1524,1527,1530],{"class":227,"line":1523},15,[266,1525,1526],{"class":301},"to_excel_with_dates(orders, ",[266,1528,1529],{"class":275},"\"report.xlsx\"",[266,1531,695],{"class":301},[266,1533,1535,1538,1540,1543,1545,1547,1550,1552,1554,1556,1559],{"class":227,"line":1534},16,[266,1536,1537],{"class":505},"                    formats",[266,1539,338],{"class":297},[266,1541,1542],{"class":301},"{",[266,1544,589],{"class":275},[266,1546,1114],{"class":301},[266,1548,1549],{"class":275},"\"YYYY-MM-DD\"",[266,1551,356],{"class":301},[266,1553,1122],{"class":275},[266,1555,1114],{"class":301},[266,1557,1558],{"class":275},"\"YYYY-MM-DD HH:MM\"",[266,1560,1561],{"class":301},"},\n",[266,1563,1565,1568,1570,1573,1575],{"class":227,"line":1564},17,[266,1566,1567],{"class":505},"                    date_only",[266,1569,338],{"class":297},[266,1571,1572],{"class":301},"[",[266,1574,589],{"class":275},[266,1576,1577],{"class":301},"])\n",[266,1579,1581,1583,1585,1587],{"class":227,"line":1580},18,[266,1582,519],{"class":388},[266,1584,522],{"class":301},[266,1586,1529],{"class":275},[266,1588,527],{"class":301},[10,1590,1591,1592,1594,1595,1598,1599,1602,1603,1605],{},"Choosing the format itself is a question about readers. ",[22,1593,565],{}," is unambiguous everywhere and sorts correctly even when copied out as text, which makes it a good default for workbooks that cross borders. ",[22,1596,1597],{},"DD\u002FMM\u002FYYYY"," or ",[22,1600,1601],{},"MM\u002FDD\u002FYYYY"," suit a single-country audience; ",[22,1604,1284],{}," is unambiguous and readable in any English-speaking locale. Whatever you pick, put it in the job's configuration rather than in code, so a change of audience does not need a change of program.",[254,1607,1609],{"id":1608},"step-5-do-not-convert-dates-to-strings","Step 5 — Do not convert dates to strings",[10,1611,1612],{},"It is tempting to format the column as text before writing:",[14,1614,1616],{"className":288,"code":1615,"language":290,"meta":20,"style":20},"as_text = orders.assign(order_date=orders[\"order_date\"].dt.strftime(\"%d\u002F%m\u002F%Y\"))\nas_text.to_excel(\"text_dates.xlsx\", index=False)\nprint(load_workbook(\"text_dates.xlsx\").active[\"A2\"].data_type)\n# 's' — a string, not a date\n",[22,1617,1618,1652,1670,1688],{"__ignoreMap":20},[266,1619,1620,1623,1625,1628,1630,1632,1635,1637,1640,1643,1647,1650],{"class":227,"line":268},[266,1621,1622],{"class":301},"as_text ",[266,1624,338],{"class":297},[266,1626,1627],{"class":301}," orders.assign(",[266,1629,113],{"class":505},[266,1631,338],{"class":297},[266,1633,1634],{"class":301},"orders[",[266,1636,589],{"class":275},[266,1638,1639],{"class":301},"].dt.strftime(",[266,1641,1642],{"class":275},"\"",[266,1644,1646],{"class":1645},"sSjpA","%d",[266,1648,1649],{"class":275},"\u002F%m\u002F%Y\"",[266,1651,527],{"class":301},[266,1653,1654,1657,1660,1662,1664,1666,1668],{"class":227,"line":311},[266,1655,1656],{"class":301},"as_text.to_excel(",[266,1658,1659],{"class":275},"\"text_dates.xlsx\"",[266,1661,356],{"class":301},[266,1663,506],{"class":505},[266,1665,338],{"class":297},[266,1667,511],{"class":388},[266,1669,514],{"class":301},[266,1671,1672,1674,1677,1679,1682,1685],{"class":227,"line":325},[266,1673,519],{"class":388},[266,1675,1676],{"class":301},"(load_workbook(",[266,1678,1659],{"class":275},[266,1680,1681],{"class":301},").active[",[266,1683,1684],{"class":275},"\"A2\"",[266,1686,1687],{"class":301},"].data_type)\n",[266,1689,1690],{"class":227,"line":332},[266,1691,1692],{"class":532},"# 's' — a string, not a date\n",[10,1694,1695],{},"The cell shows what you wanted and is no longer a date. Excel sorts it alphabetically (so 02\u002F04 comes before 15\u002F03), cannot group it by month in a pivot table, and cannot subtract it from another date. Readers in other locales cannot tell 03\u002F04 from 04\u002F03 either. Keep real dates and change the format; that is what number formats are for.",[46,1697,55,1702,55,1705,55,1708,55,1711,55,1716,55,1724,55,1729,55,1734,55,1739,55,1745,55,1749,55,1754,55,1758,55,1763,55,1767,55,1772,55,1775,55,1782,55,1787,55,1791,55,1795,55,1800,55,1803,55,1808,55,1811,55,1816,55,1819],{"viewBox":1698,"role":49,"ariaLabelledBy":1699,"xmlns":53,"style":838},"4 0 752 233",[1700,1701],"wdt-text-t","wdt-text-d",[57,1703,1704],{"id":1700},"A date cell versus a date-looking string",[61,1706,1707],{"id":1701},"Two panels. A real date with a date format sorts chronologically, filters and groups by month, works in date formulas and displays in the reader's preferred format. A strftime string looks the same but sorts alphabetically, cannot be grouped by month, breaks date formulas and is ambiguous across locales.",[65,1709],{"x":847,"y":68,"width":848,"height":1710,"fill":71},"233",[65,1712],{"x":852,"y":853,"width":1713,"height":1714,"rx":1715,"fill":193,"stroke":194,"style":233},"351.0","201.0","14",[902,1717,1719],{"transform":1718},"translate(182.5,29.0) scale(1.083)",[906,1720],{"d":1721,"fill":909,"stroke":1722,"style":1723},"M4 5h16v15H4z M4 10h16 M8 3v4 M16 3v4","var(--teal-ink,#0b6157)","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[19,1725,1728],{"x":1726,"y":897,"style":1727},"195.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Real date + number format",[227,1730],{"x1":1731,"y1":1732,"x2":1733,"y2":1732,"stroke":194,"style":80},"36.0","91.0","355.0",[19,1735,1738],{"x":1736,"y":124,"style":1737},"60.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","sorts chronologically",[902,1740,1742],{"transform":1741},"translate(38.5,99.5) scale(0.625)",[906,1743],{"d":908,"fill":909,"stroke":194,"style":1744},"stroke-width:2.88px;stroke-linecap:round;stroke-linejoin:round",[19,1746,1748],{"x":1736,"y":1747,"style":1737},"137.0","groups by month and year",[902,1750,1752],{"transform":1751},"translate(38.5,125.5) scale(0.625)",[906,1753],{"d":908,"fill":909,"stroke":194,"style":1744},[19,1755,1757],{"x":1736,"y":1756,"style":1737},"163.0","works in date formulas",[902,1759,1761],{"transform":1760},"translate(38.5,151.5) scale(0.625)",[906,1762],{"d":908,"fill":909,"stroke":194,"style":1744},[19,1764,1766],{"x":1736,"y":1765,"style":1737},"189.0","display can change later",[902,1768,1770],{"transform":1769},"translate(38.5,177.5) scale(0.625)",[906,1771],{"d":908,"fill":909,"stroke":194,"style":1744},[65,1773],{"x":1774,"y":853,"width":1713,"height":1714,"rx":1715,"fill":128,"stroke":129,"style":233},"389.0",[902,1776,1778],{"transform":1777},"translate(551.5,29.0) scale(1.083)",[906,1779],{"d":1780,"fill":909,"stroke":1781,"style":1723},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","var(--accent-ink,#be185d)",[19,1783,1786],{"x":1784,"y":897,"style":1785},"564.5","font-size:14px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","strftime() string",[227,1788],{"x1":1789,"y1":1732,"x2":1790,"y2":1732,"stroke":129,"style":80},"405.0","724.0",[19,1792,1794],{"x":1793,"y":124,"style":1737},"429.0","sorts alphabetically",[902,1796,1798],{"transform":1797},"translate(407.5,99.5) scale(0.625)",[906,1799],{"d":925,"fill":909,"stroke":129,"style":1744},[19,1801,1802],{"x":1793,"y":1747,"style":1737},"no date grouping",[902,1804,1806],{"transform":1805},"translate(407.5,125.5) scale(0.625)",[906,1807],{"d":925,"fill":909,"stroke":129,"style":1744},[19,1809,1810],{"x":1793,"y":1756,"style":1737},"breaks date formulas",[902,1812,1814],{"transform":1813},"translate(407.5,151.5) scale(0.625)",[906,1815],{"d":925,"fill":909,"stroke":129,"style":1744},[19,1817,1818],{"x":1793,"y":1765,"style":1737},"03\u002F04 or 04\u002F03?",[902,1820,1822],{"transform":1821},"translate(407.5,177.5) scale(0.625)",[906,1823],{"d":925,"fill":909,"stroke":129,"style":1744},[254,1825,1827],{"id":1826},"timezones-and-missing-values","Timezones and missing values",[10,1829,1830,1831,1835,1836,1839],{},"Two situations need attention before any of these steps. Timezone-aware columns cannot be written at all — Excel has no timezone concept — so convert them to local naive times first; ",[40,1832,1834],{"href":1833},"\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"," covers the conversion. Missing dates (",[22,1837,1838],{},"NaT",") are written as empty cells by every method on this page, which is usually what a report wants; if a placeholder such as \"not shipped\" is needed, fill it in a copy used only for output, because a text placeholder turns the column into text.",[254,1841,1843],{"id":1842},"common-pitfalls","Common pitfalls",[1845,1846,1847,1861,1872,1878],"ul",{},[1848,1849,1850,1854,1855,1857,1858,1860],"li",{},[1851,1852,1853],"strong",{},"Normalising and expecting the format to change."," ",[22,1856,539],{}," keeps the ",[22,1859,29],{}," type, so the date-time format is still used.",[1848,1862,1863,1869,1870,44],{},[1851,1864,1865,1866,1868],{},"Relying on ",[22,1867,662],{}," with the openpyxl engine."," It is accepted and ignored; verify the output's ",[22,1871,1048],{},[1848,1873,1874,1877],{},[1851,1875,1876],{},"Hiding real times with a date format."," The time is still in the value and still affects filters that compare with a date.",[1848,1879,1880,1883,1884,44],{},[1851,1881,1882],{},"Narrow columns."," Long date formats in default-width columns show ",[22,1885,1288],{},[254,1887,1889],{"id":1888},"performance-notes","Performance notes",[10,1891,1892,1894,1895,1897,1898,1900],{},[22,1893,561],{}," creates Python objects for every value, which is slower than working with ",[22,1896,29],{}," but insignificant next to writing the file. Setting ",[22,1899,1048],{}," cell by cell with openpyxl costs a few seconds per million cells; for very large exports, the xlsxwriter writer options (Step 3) apply formats while writing and add no time at all.",[254,1902,1904],{"id":1903},"conclusion","Conclusion",[10,1906,1907,1908,1910,1911,1913,1914,1916,1917,762,1919,1921,1922,1925,1926,1928],{},"The ",[22,1909,546],{}," comes from pandas writing ",[22,1912,29],{}," columns with a date-time format. Convert columns whose time is meaningless with ",[22,1915,561],{},", set ",[22,1918,662],{},[22,1920,658],{}," on an ",[22,1923,1924],{},"ExcelWriter"," when using the xlsxwriter engine, or apply ",[22,1927,1048],{}," per column with openpyxl after writing — which works everywhere and leaves times intact where they matter. Never convert dates to strings to change how they look.",[254,1930,1932],{"id":1931},"frequently-asked-questions","Frequently asked questions",[10,1934,1935,1938],{},[1851,1936,1937],{},"Why does to_excel add 00:00:00 to my dates?","\npandas stores dates in datetime64 columns, which always carry a time. It writes those cells with the format YYYY-MM-DD HH:MM:SS, so a midnight time is displayed as 00:00:00 even though nothing is wrong with the value.",[10,1940,1941,1944],{},[1851,1942,1943],{},"Does datetime_format work with the openpyxl engine?","\nNot in the pandas version tested here (3.0). OpenpyxlWriter accepts date_format and datetime_format but does not apply them, so the default formats are used. Use the xlsxwriter engine for these options, or set number formats with openpyxl after writing.",[10,1946,1947,1950],{},[1851,1948,1949],{},"Should I convert dates to strings with strftime?","\nNo. Strings look right but are text: Excel cannot sort them chronologically, filter them by month or use them in date formulas. Keep real dates and change the display format.",[10,1952,1953,1956],{},[1851,1954,1955],{},"Does hiding the time with a format remove it?","\nNo. A format changes only the display. If the values contain real times such as 14:30, the cell still holds them. Use dt.normalize() or dt.date first when the time must go.",[254,1958,1960],{"id":1959},"related","Related",[1845,1962,1963,1969,1976,1983],{},[1848,1964,1965,1966,1968],{},"Up one level: ",[40,1967,43],{"href":42}," — the writer options in depth.",[1848,1970,1971,1975],{},[40,1972,1974],{"href":1973},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel\u002F","Applying Number and Date Formats in Excel"," — every kind of display format.",[1848,1977,1978,1982],{},[40,1979,1981],{"href":1980},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fparse-excel-dates-into-python-datetimes-with-pandas\u002F","Parse Excel Dates into Python datetimes with pandas"," — the reading side.",[1848,1984,1985,1989],{},[40,1986,1988],{"href":1987},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fcontrol-how-nan-and-infinity-appear-in-excel-output\u002F","Control How NaN, None and Infinity Appear in Excel Output"," — what happens to missing values on write.",[1991,1992,1993],"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 .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}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 .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":20,"searchDepth":311,"depth":311,"links":1995},[1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008],{"id":256,"depth":311,"text":257},{"id":486,"depth":311,"text":487},{"id":550,"depth":311,"text":551},{"id":648,"depth":311,"text":649},{"id":1041,"depth":311,"text":1042},{"id":1327,"depth":311,"text":1328},{"id":1608,"depth":311,"text":1609},{"id":1826,"depth":311,"text":1827},{"id":1842,"depth":311,"text":1843},{"id":1888,"depth":311,"text":1889},{"id":1903,"depth":311,"text":1904},{"id":1931,"depth":311,"text":1932},{"id":1959,"depth":311,"text":1960},"2026-09-25","pandas writes datetime columns with a YYYY-MM-DD HH:MM:SS format, so every date shows 00:00:00. Write real dates that display as dates: convert to date objects, set datetime_format on an xlsxwriter ExcelWriter, or apply a number format per column — and avoid the openpyxl engine option that is silently ignored.","md",[2013,2015,2017,2019],{"q":1937,"a":2014},"pandas stores dates in datetime64 columns, which always carry a time. It writes those cells with the format YYYY-MM-DD HH:MM:SS, so a midnight time is displayed as 00:00:00 even though nothing is wrong with the value.",{"q":1943,"a":2016},"Not in the pandas version tested here (3.0). OpenpyxlWriter accepts date_format and datetime_format but does not apply them, so the default formats are used. Use the xlsxwriter engine for these options, or set number formats with openpyxl after writing.",{"q":1949,"a":2018},"No. Strings look right but are text: Excel cannot sort them chronologically, filter them by month or use them in date formulas. Keep real dates and change the display format.",{"q":1955,"a":2020},"No. A format changes only the display. If the values contain real times such as 14:30, the cell still holds them. Use dt.normalize() or dt.date first when the time must go.","write dates without the time when exporting to excel with pandas",null,{"breadcrumb":2024},[2025,2027,2030],{"name":2026,"item":1315},"Home",{"name":2028,"item":2029},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":43,"item":42},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-dates-without-time-from-pandas-to-excel",{"title":2033,"description":2034},"Remove 00:00:00 from Dates in pandas to_excel Output","Stop pandas writing 2026-03-01 00:00:00 to Excel. Use .dt.date, ExcelWriter datetime_format with xlsxwriter, or openpyxl number formats, and keep the cells as real, sortable dates.","write-dates-without-time-from-pandas-to-excel","getting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-dates-without-time-from-pandas-to-excel\u002Findex",[2038,2039,2040],"writing-excel","dates-and-times","number-formats","how-to","S_rDLn5Yn19hVdC9qFJU5S0V37VfgGnDu0U8IU2VXZY",[2044,2048],{"title":2045,"path":2046,"stem":2047,"children":-1},"Write Clickable Links from a DataFrame Column to Excel","\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-clickable-links-from-a-dataframe-to-excel","getting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-clickable-links-from-a-dataframe-to-excel\u002Findex",{"title":2049,"path":2050,"stem":2051,"children":-1},"Write Excel Formulas from a pandas DataFrame","\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-excel-formulas-from-a-pandas-dataframe","getting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas\u002Fwrite-excel-formulas-from-a-pandas-dataframe\u002Findex",[2053,2055],{"path":2054,"title":2028},"\u002Fgetting-started-with-python-excel-automation",{"path":2056,"title":43},"\u002Fgetting-started-with-python-excel-automation\u002Fwriting-dataframes-to-excel-with-pandas",[],[2059,2062,2065,2068,2071,2074],{"path":2060,"title":2061,"kind":2041},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fwrite-multiple-dataframes-to-one-excel-file","Write Multiple DataFrames to One Excel File",{"path":2063,"title":2064,"kind":2041},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fwrite-a-formatted-excel-report-with-xlsxwriter","Write a Formatted Excel Report with xlsxwriter",{"path":2066,"title":2067,"kind":2041},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Ffind-and-replace-text-in-excel-with-openpyxl","Find and Replace Text in Excel with openpyxl",{"path":2069,"title":2070,"kind":2041},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Finsert-and-delete-rows-and-columns-with-openpyxl","Insert and Delete Rows and Columns with openpyxl",{"path":2072,"title":2073,"kind":2041},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fopenpyxl-append-data-to-existing-excel-sheet","openpyxl: Append Data to an Existing Excel Sheet",{"path":2075,"title":2076,"kind":2041},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Freorder-columns-to-match-a-template-layout-with-pandas","Reorder Columns to Match a Template Layout with pandas",1790972077858]