[{"data":1,"prerenderedAt":1728},["ShallowReactive",2],{"doc:\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel":3,"surround:\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel":1721},{"id":4,"title":5,"body":6,"dateModified":1698,"datePublished":1698,"description":1699,"extension":1700,"faq":1701,"meta":1712,"navigation":255,"path":1713,"seo":1714,"slug":1717,"stem":1718,"type":1719,"__hash__":1720},"docs\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel\u002Findex.md","Applying Number and Date Formats in Excel",{"type":7,"value":8,"toc":1679},"minimark",[9,33,163,168,192,205,209,227,374,387,391,406,550,558,562,587,731,741,745,752,902,918,922,935,1112,1115,1119,1133,1311,1322,1326,1545,1549,1554,1561,1565,1577,1581,1598,1602,1616,1620,1625,1629,1640,1644,1675],[10,11,12,13,17,18,22,23,28,29,32],"p",{},"When a report looks wrong, the value is usually fine and the ",[14,15,16],"em",{},"display"," is off. In Excel, every cell holds a raw value and a separate display format. ",[19,20,21],"code",{},"cell.number_format"," controls only the display — it never changes the number underneath. This guide, part of ",[24,25,27],"a",{"href":26},"\u002Fformatting-and-charting-excel-reports-with-python\u002F","Formatting and Charting Excel Reports with Python",", shows how to apply currency, separators, percentages, red negatives, and dates with ",[19,30,31],{},"openpyxl",". Every snippet builds its own sample workbook so you can run them in order.",[34,35,43,44,43,48,43,52,43,59,43,63,43,73,43,78,43,83,43,92,43,97,43,100,43,104,43,107,43,111,43,119,43,122,43,126,43,131,43,135,43,137,43,140,43,142,43,145,43,149,43,153,43,155,43,158,43,160],"svg",{"viewBox":36,"role":37,"ariaLabelledBy":38,"xmlns":41,"style":42},"0 0 760 250","img",[39,40],"num-t","num-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:760px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[45,46,47],"title",{"id":39},"The stored value stays the same while number_format changes the display",[49,50,51],"desc",{"id":40},"Three raw values pass through a number_format code that changes only how they appear: a fraction becomes a percentage, a float becomes currency, and a serial becomes a date.",[53,54,58],"text",{"x":55,"y":56,"style":57},"120","34","font-size:13px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","Stored value",[53,60,62],{"x":61,"y":56,"style":57},"640","Displayed",[64,65],"rect",{"x":66,"y":67,"width":68,"height":69,"rx":70,"fill":71,"stroke":72},"280","44","200","166","12","var(--brand,#5b5cf0)","var(--brand-strong,#4338ca)",[53,74,77],{"x":75,"y":55,"style":76},"380","font-size:15px;font-weight:700;fill:#ffffff;text-anchor:middle","number_format",[53,79,82],{"x":75,"y":80,"style":81},"142","font-size:11.5px;fill:rgba(255,255,255,0.85);text-anchor:middle","display only",[64,84],{"x":85,"y":86,"width":87,"height":88,"rx":89,"fill":90,"stroke":91},"30","50","180","42","8","var(--surface-muted,#eef2ff)","var(--line,#cdd5e6)",[53,93,96],{"x":55,"y":94,"style":95},"76","font-size:14px;font-weight:600;fill:var(--text,#172033);text-anchor:middle","0.4815",[64,98],{"x":85,"y":99,"width":87,"height":88,"rx":89,"fill":90,"stroke":91},"106",[53,101,103],{"x":55,"y":102,"style":95},"132","1234.5",[64,105],{"x":85,"y":106,"width":87,"height":88,"rx":89,"fill":90,"stroke":91},"162",[53,108,110],{"x":55,"y":109,"style":95},"188","45296",[112,113],"line",{"x1":114,"y1":115,"x2":116,"y2":117,"stroke":71,"style":118},"212","71","278","90","stroke-width:1.5px",[112,120],{"x1":114,"y1":121,"x2":116,"y2":121,"stroke":71,"style":118},"127",[112,123],{"x1":114,"y1":124,"x2":116,"y2":125,"stroke":71,"style":118},"183","164",[112,127],{"x1":128,"y1":117,"x2":129,"y2":115,"stroke":130,"style":118},"482","548","var(--teal,#0f9488)",[132,133],"polygon",{"points":134,"fill":130},"548,71 537,72 540,82",[112,136],{"x1":128,"y1":121,"x2":129,"y2":121,"stroke":130,"style":118},[132,138],{"points":139,"fill":130},"548,127 538,122 538,132",[112,141],{"x1":128,"y1":125,"x2":129,"y2":124,"stroke":130,"style":118},[132,143],{"points":144,"fill":130},"548,183 540,176 537,186",[64,146],{"x":147,"y":86,"width":87,"height":88,"rx":89,"fill":148,"stroke":130},"550","rgba(15,148,136,0.12)",[53,150,152],{"x":61,"y":94,"style":151},"font-size:14px;font-weight:700;fill:var(--teal,#0f9488);text-anchor:middle","48.15%",[64,154],{"x":147,"y":99,"width":87,"height":88,"rx":89,"fill":148,"stroke":130},[53,156,157],{"x":61,"y":102,"style":151},"$1,234.50",[64,159],{"x":147,"y":106,"width":87,"height":88,"rx":89,"fill":148,"stroke":130},[53,161,162],{"x":61,"y":109,"style":151},"2024-01-05",[164,165,167],"h2",{"id":166},"install-openpyxl","Install openpyxl",[169,170,175],"pre",{"className":171,"code":172,"language":173,"meta":174,"style":174},"language-bash shiki shiki-themes github-light github-dark","pip install openpyxl\n","bash","",[19,176,177],{"__ignoreMap":174},[178,179,181,185,189],"span",{"class":112,"line":180},1,[178,182,184],{"class":183},"sScJk","pip",[178,186,188],{"class":187},"sZZnC"," install",[178,190,191],{"class":187}," openpyxl\n",[10,193,194,196,197,200,201,204],{},[19,195,31],{}," writes ",[19,198,199],{},".xlsx","\u002F",[19,202,203],{},".xlsm"," without Excel installed and runs on Windows, macOS, and Linux.",[164,206,208],{"id":207},"number-format-is-display-only","Number format is display-only",[10,210,211,212,214,215,218,219,222,223,226],{},"Setting ",[19,213,77],{}," changes how a value ",[14,216,217],{},"looks",", not what it ",[14,220,221],{},"is",". A cell formatted as currency still holds the plain float, so formulas, sorts, and exports see the original number. Confirm it yourself: write a value, format it, then read ",[19,224,225],{},".value"," back — it is unchanged.",[169,228,232],{"className":229,"code":230,"language":231,"meta":174,"style":174},"language-python shiki shiki-themes github-light github-dark","from openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\nws[\"A1\"] = 1234.5\nws[\"A1\"].number_format = \"$#,##0.00\"   # displays as $1,234.50\n\nprint(\"Stored value:\", ws[\"A1\"].value)        # 1234.5\nprint(\"Display code: \", ws[\"A1\"].number_format)\nwb.save(\"number_format_basics.xlsx\")\n","python",[19,233,234,250,257,269,280,298,317,322,345,362],{"__ignoreMap":174},[178,235,236,240,244,247],{"class":112,"line":180},[178,237,239],{"class":238},"szBVR","from",[178,241,243],{"class":242},"sVt8B"," openpyxl ",[178,245,246],{"class":238},"import",[178,248,249],{"class":242}," Workbook\n",[178,251,253],{"class":112,"line":252},2,[178,254,256],{"emptyLinePlaceholder":255},true,"\n",[178,258,260,263,266],{"class":112,"line":259},3,[178,261,262],{"class":242},"wb ",[178,264,265],{"class":238},"=",[178,267,268],{"class":242}," Workbook()\n",[178,270,272,275,277],{"class":112,"line":271},4,[178,273,274],{"class":242},"ws ",[178,276,265],{"class":238},[178,278,279],{"class":242}," wb.active\n",[178,281,283,286,289,292,294],{"class":112,"line":282},5,[178,284,285],{"class":242},"ws[",[178,287,288],{"class":187},"\"A1\"",[178,290,291],{"class":242},"] ",[178,293,265],{"class":238},[178,295,297],{"class":296},"sj4cs"," 1234.5\n",[178,299,301,303,305,308,310,313],{"class":112,"line":300},6,[178,302,285],{"class":242},[178,304,288],{"class":187},[178,306,307],{"class":242},"].number_format ",[178,309,265],{"class":238},[178,311,312],{"class":187}," \"$#,##0.00\"",[178,314,316],{"class":315},"sJ8bj","   # displays as $1,234.50\n",[178,318,320],{"class":112,"line":319},7,[178,321,256],{"emptyLinePlaceholder":255},[178,323,325,328,331,334,337,339,342],{"class":112,"line":324},8,[178,326,327],{"class":296},"print",[178,329,330],{"class":242},"(",[178,332,333],{"class":187},"\"Stored value:\"",[178,335,336],{"class":242},", ws[",[178,338,288],{"class":187},[178,340,341],{"class":242},"].value)        ",[178,343,344],{"class":315},"# 1234.5\n",[178,346,348,350,352,355,357,359],{"class":112,"line":347},9,[178,349,327],{"class":296},[178,351,330],{"class":242},[178,353,354],{"class":187},"\"Display code: \"",[178,356,336],{"class":242},[178,358,288],{"class":187},[178,360,361],{"class":242},"].number_format)\n",[178,363,365,368,371],{"class":112,"line":364},10,[178,366,367],{"class":242},"wb.save(",[178,369,370],{"class":187},"\"number_format_basics.xlsx\"",[178,372,373],{"class":242},")\n",[10,375,376,377,379,380,382,383,386],{},"The stored value prints ",[19,378,103],{}," even though Excel will render ",[19,381,157],{},". Because the format is cosmetic, the cell must already contain a real number for the format to mean anything — a text string like ",[19,384,385],{},"\"1234.5\""," will not pick up a currency format.",[164,388,390],{"id":389},"currency-and-thousands-separators","Currency and thousands separators",[10,392,393,394,397,398,401,402,405],{},"The placeholder ",[19,395,396],{},"#"," shows a digit only when present; ",[19,399,400],{},"0"," forces a digit. Group thousands with a comma and fix two decimals with ",[19,403,404],{},"0.00",". Drop the currency symbol for a plain grouped integer.",[169,407,409],{"className":229,"code":408,"language":231,"meta":174,"style":174},"from openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\nws.append([\"Item\", \"Amount\"])\nws.append([\"Revenue\", 1234567.5])\nws.append([\"Units\", 42000])\n\nws[\"B2\"].number_format = \"$#,##0.00\"   # $1,234,567.50\nws[\"B3\"].number_format = \"#,##0\"       # 42,000\n\nwb.save(\"currency_and_separators.xlsx\")\nprint(\"Formatted currency and a grouped integer\")\n",[19,410,411,421,425,433,441,458,472,486,490,506,523,528,538],{"__ignoreMap":174},[178,412,413,415,417,419],{"class":112,"line":180},[178,414,239],{"class":238},[178,416,243],{"class":242},[178,418,246],{"class":238},[178,420,249],{"class":242},[178,422,423],{"class":112,"line":252},[178,424,256],{"emptyLinePlaceholder":255},[178,426,427,429,431],{"class":112,"line":259},[178,428,262],{"class":242},[178,430,265],{"class":238},[178,432,268],{"class":242},[178,434,435,437,439],{"class":112,"line":271},[178,436,274],{"class":242},[178,438,265],{"class":238},[178,440,279],{"class":242},[178,442,443,446,449,452,455],{"class":112,"line":282},[178,444,445],{"class":242},"ws.append([",[178,447,448],{"class":187},"\"Item\"",[178,450,451],{"class":242},", ",[178,453,454],{"class":187},"\"Amount\"",[178,456,457],{"class":242},"])\n",[178,459,460,462,465,467,470],{"class":112,"line":300},[178,461,445],{"class":242},[178,463,464],{"class":187},"\"Revenue\"",[178,466,451],{"class":242},[178,468,469],{"class":296},"1234567.5",[178,471,457],{"class":242},[178,473,474,476,479,481,484],{"class":112,"line":319},[178,475,445],{"class":242},[178,477,478],{"class":187},"\"Units\"",[178,480,451],{"class":242},[178,482,483],{"class":296},"42000",[178,485,457],{"class":242},[178,487,488],{"class":112,"line":324},[178,489,256],{"emptyLinePlaceholder":255},[178,491,492,494,497,499,501,503],{"class":112,"line":347},[178,493,285],{"class":242},[178,495,496],{"class":187},"\"B2\"",[178,498,307],{"class":242},[178,500,265],{"class":238},[178,502,312],{"class":187},[178,504,505],{"class":315},"   # $1,234,567.50\n",[178,507,508,510,513,515,517,520],{"class":112,"line":364},[178,509,285],{"class":242},[178,511,512],{"class":187},"\"B3\"",[178,514,307],{"class":242},[178,516,265],{"class":238},[178,518,519],{"class":187}," \"#,##0\"",[178,521,522],{"class":315},"       # 42,000\n",[178,524,526],{"class":112,"line":525},11,[178,527,256],{"emptyLinePlaceholder":255},[178,529,531,533,536],{"class":112,"line":530},12,[178,532,367],{"class":242},[178,534,535],{"class":187},"\"currency_and_separators.xlsx\"",[178,537,373],{"class":242},[178,539,541,543,545,548],{"class":112,"line":540},13,[178,542,327],{"class":296},[178,544,330],{"class":242},[178,546,547],{"class":187},"\"Formatted currency and a grouped integer\"",[178,549,373],{"class":242},[10,551,552,553,557],{},"For a deep dive on symbols, accounting parentheses, and whole-column currency, see ",[24,554,556],{"href":555},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel\u002Fformat-excel-cells-as-currency-with-python\u002F","Format Excel Cells as Currency with Python",".",[164,559,561],{"id":560},"percentages-store-the-ratio-not-the-integer","Percentages: store the ratio, not the integer",[10,563,564,565,568,569,572,573,576,577,580,581,583,584,557],{},"The ",[19,566,567],{},"%"," format code multiplies the stored value by 100 for display and appends a percent sign. So a cell showing ",[19,570,571],{},"25.0%"," must store ",[19,574,575],{},"0.25",", not ",[19,578,579],{},"25",". Store the raw ratio and let the format do the conversion — storing ",[19,582,579],{}," would render as ",[19,585,586],{},"2500.0%",[169,588,590],{"className":229,"code":589,"language":231,"meta":174,"style":174},"from openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\nws.append([\"Metric\", \"Rate\"])\nws.append([\"Conversion\", 0.25])\nws.append([\"Churn\", 0.073])\n\nws[\"B2\"].number_format = \"0.0%\"    # 25.0%\nws[\"B3\"].number_format = \"0.00%\"   # 7.30%\n\nprint(\"B2 stored value:\", ws[\"B2\"].value)   # 0.25, not 25\nwb.save(\"percentages.xlsx\")\n",[19,591,592,602,606,614,622,636,649,663,667,683,699,703,722],{"__ignoreMap":174},[178,593,594,596,598,600],{"class":112,"line":180},[178,595,239],{"class":238},[178,597,243],{"class":242},[178,599,246],{"class":238},[178,601,249],{"class":242},[178,603,604],{"class":112,"line":252},[178,605,256],{"emptyLinePlaceholder":255},[178,607,608,610,612],{"class":112,"line":259},[178,609,262],{"class":242},[178,611,265],{"class":238},[178,613,268],{"class":242},[178,615,616,618,620],{"class":112,"line":271},[178,617,274],{"class":242},[178,619,265],{"class":238},[178,621,279],{"class":242},[178,623,624,626,629,631,634],{"class":112,"line":282},[178,625,445],{"class":242},[178,627,628],{"class":187},"\"Metric\"",[178,630,451],{"class":242},[178,632,633],{"class":187},"\"Rate\"",[178,635,457],{"class":242},[178,637,638,640,643,645,647],{"class":112,"line":300},[178,639,445],{"class":242},[178,641,642],{"class":187},"\"Conversion\"",[178,644,451],{"class":242},[178,646,575],{"class":296},[178,648,457],{"class":242},[178,650,651,653,656,658,661],{"class":112,"line":319},[178,652,445],{"class":242},[178,654,655],{"class":187},"\"Churn\"",[178,657,451],{"class":242},[178,659,660],{"class":296},"0.073",[178,662,457],{"class":242},[178,664,665],{"class":112,"line":324},[178,666,256],{"emptyLinePlaceholder":255},[178,668,669,671,673,675,677,680],{"class":112,"line":347},[178,670,285],{"class":242},[178,672,496],{"class":187},[178,674,307],{"class":242},[178,676,265],{"class":238},[178,678,679],{"class":187}," \"0.0%\"",[178,681,682],{"class":315},"    # 25.0%\n",[178,684,685,687,689,691,693,696],{"class":112,"line":364},[178,686,285],{"class":242},[178,688,512],{"class":187},[178,690,307],{"class":242},[178,692,265],{"class":238},[178,694,695],{"class":187}," \"0.00%\"",[178,697,698],{"class":315},"   # 7.30%\n",[178,700,701],{"class":112,"line":525},[178,702,256],{"emptyLinePlaceholder":255},[178,704,705,707,709,712,714,716,719],{"class":112,"line":530},[178,706,327],{"class":296},[178,708,330],{"class":242},[178,710,711],{"class":187},"\"B2 stored value:\"",[178,713,336],{"class":242},[178,715,496],{"class":187},[178,717,718],{"class":242},"].value)   ",[178,720,721],{"class":315},"# 0.25, not 25\n",[178,723,724,726,729],{"class":112,"line":540},[178,725,367],{"class":242},[178,727,728],{"class":187},"\"percentages.xlsx\"",[178,730,373],{"class":242},[10,732,733,734,736,737,740],{},"The stored value stays ",[19,735,575],{},", so a ",[19,738,739],{},"=SUM()"," or a downstream pandas read gets the true ratio.",[164,742,744],{"id":743},"show-negatives-in-red","Show negatives in red",[10,746,747,748,751],{},"A format string can carry up to four sections separated by semicolons: positive; negative; zero; text. Supply a negative section to style losses. Wrap a section in ",[19,749,750],{},"[Red]"," to color it, and use parentheses instead of a minus sign for an accounting look.",[169,753,755],{"className":229,"code":754,"language":231,"meta":174,"style":174},"from openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\nws.append([\"Account\", \"Balance\"])\nws.append([\"Operating\", 8200.40])\nws.append([\"Overdraft\", -1530.75])\n\nred_neg = \"$#,##0.00;[Red]($#,##0.00)\"\nws[\"B2\"].number_format = red_neg     # $8,200.40\nws[\"B3\"].number_format = red_neg     # ($1,530.75) in red\n\nwb.save(\"red_negatives.xlsx\")\nprint(\"Applied positive\u002Fnegative two-section format\")\n",[19,756,757,767,771,779,787,801,815,832,836,846,862,877,881,890],{"__ignoreMap":174},[178,758,759,761,763,765],{"class":112,"line":180},[178,760,239],{"class":238},[178,762,243],{"class":242},[178,764,246],{"class":238},[178,766,249],{"class":242},[178,768,769],{"class":112,"line":252},[178,770,256],{"emptyLinePlaceholder":255},[178,772,773,775,777],{"class":112,"line":259},[178,774,262],{"class":242},[178,776,265],{"class":238},[178,778,268],{"class":242},[178,780,781,783,785],{"class":112,"line":271},[178,782,274],{"class":242},[178,784,265],{"class":238},[178,786,279],{"class":242},[178,788,789,791,794,796,799],{"class":112,"line":282},[178,790,445],{"class":242},[178,792,793],{"class":187},"\"Account\"",[178,795,451],{"class":242},[178,797,798],{"class":187},"\"Balance\"",[178,800,457],{"class":242},[178,802,803,805,808,810,813],{"class":112,"line":300},[178,804,445],{"class":242},[178,806,807],{"class":187},"\"Operating\"",[178,809,451],{"class":242},[178,811,812],{"class":296},"8200.40",[178,814,457],{"class":242},[178,816,817,819,822,824,827,830],{"class":112,"line":319},[178,818,445],{"class":242},[178,820,821],{"class":187},"\"Overdraft\"",[178,823,451],{"class":242},[178,825,826],{"class":238},"-",[178,828,829],{"class":296},"1530.75",[178,831,457],{"class":242},[178,833,834],{"class":112,"line":324},[178,835,256],{"emptyLinePlaceholder":255},[178,837,838,841,843],{"class":112,"line":347},[178,839,840],{"class":242},"red_neg ",[178,842,265],{"class":238},[178,844,845],{"class":187}," \"$#,##0.00;[Red]($#,##0.00)\"\n",[178,847,848,850,852,854,856,859],{"class":112,"line":364},[178,849,285],{"class":242},[178,851,496],{"class":187},[178,853,307],{"class":242},[178,855,265],{"class":238},[178,857,858],{"class":242}," red_neg     ",[178,860,861],{"class":315},"# $8,200.40\n",[178,863,864,866,868,870,872,874],{"class":112,"line":525},[178,865,285],{"class":242},[178,867,512],{"class":187},[178,869,307],{"class":242},[178,871,265],{"class":238},[178,873,858],{"class":242},[178,875,876],{"class":315},"# ($1,530.75) in red\n",[178,878,879],{"class":112,"line":530},[178,880,256],{"emptyLinePlaceholder":255},[178,882,883,885,888],{"class":112,"line":540},[178,884,367],{"class":242},[178,886,887],{"class":187},"\"red_negatives.xlsx\"",[178,889,373],{"class":242},[178,891,893,895,897,900],{"class":112,"line":892},14,[178,894,327],{"class":296},[178,896,330],{"class":242},[178,898,899],{"class":187},"\"Applied positive\u002Fnegative two-section format\"",[178,901,373],{"class":242},[10,903,904,905,907,908,911,912,915,916,557],{},"The positive ",[19,906,812],{}," shows normally; the negative ",[19,909,910],{},"-1530.75"," displays as a red ",[19,913,914],{},"($1,530.75)",". The underlying value remains ",[19,917,910],{},[164,919,921],{"id":920},"apply-a-format-down-a-whole-column","Apply a format down a whole column",[10,923,924,925,927,928,931,932,557],{},"Reports format an entire column, not single cells. Iterate the column and set ",[19,926,77],{}," on each data cell, skipping the header. ",[19,929,930],{},"ws[\"B\"]"," yields every cell in column B top to bottom; slice off the header with ",[19,933,934],{},"[1:]",[169,936,938],{"className":229,"code":937,"language":231,"meta":174,"style":174},"from openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\nws.append([\"Region\", \"Revenue\"])\nfor region, value in [(\"North\", 23990.5), (\"South\", 12475.0), (\"West\", 15992.2)]:\n    ws.append([region, value])\n\nfor cell in ws[\"B\"][1:]:           # column B, skip the header\n    cell.number_format = \"$#,##0.00\"\n\nwb.save(\"format_column.xlsx\")\nprint(\"Formatted\", ws.max_row - 1, \"revenue cells\")\n",[19,939,940,950,954,962,970,983,1029,1034,1038,1065,1075,1079,1088],{"__ignoreMap":174},[178,941,942,944,946,948],{"class":112,"line":180},[178,943,239],{"class":238},[178,945,243],{"class":242},[178,947,246],{"class":238},[178,949,249],{"class":242},[178,951,952],{"class":112,"line":252},[178,953,256],{"emptyLinePlaceholder":255},[178,955,956,958,960],{"class":112,"line":259},[178,957,262],{"class":242},[178,959,265],{"class":238},[178,961,268],{"class":242},[178,963,964,966,968],{"class":112,"line":271},[178,965,274],{"class":242},[178,967,265],{"class":238},[178,969,279],{"class":242},[178,971,972,974,977,979,981],{"class":112,"line":282},[178,973,445],{"class":242},[178,975,976],{"class":187},"\"Region\"",[178,978,451],{"class":242},[178,980,464],{"class":187},[178,982,457],{"class":242},[178,984,985,988,991,994,997,1000,1002,1005,1008,1011,1013,1016,1018,1021,1023,1026],{"class":112,"line":300},[178,986,987],{"class":238},"for",[178,989,990],{"class":242}," region, value ",[178,992,993],{"class":238},"in",[178,995,996],{"class":242}," [(",[178,998,999],{"class":187},"\"North\"",[178,1001,451],{"class":242},[178,1003,1004],{"class":296},"23990.5",[178,1006,1007],{"class":242},"), (",[178,1009,1010],{"class":187},"\"South\"",[178,1012,451],{"class":242},[178,1014,1015],{"class":296},"12475.0",[178,1017,1007],{"class":242},[178,1019,1020],{"class":187},"\"West\"",[178,1022,451],{"class":242},[178,1024,1025],{"class":296},"15992.2",[178,1027,1028],{"class":242},")]:\n",[178,1030,1031],{"class":112,"line":319},[178,1032,1033],{"class":242},"    ws.append([region, value])\n",[178,1035,1036],{"class":112,"line":324},[178,1037,256],{"emptyLinePlaceholder":255},[178,1039,1040,1042,1045,1047,1050,1053,1056,1059,1062],{"class":112,"line":347},[178,1041,987],{"class":238},[178,1043,1044],{"class":242}," cell ",[178,1046,993],{"class":238},[178,1048,1049],{"class":242}," ws[",[178,1051,1052],{"class":187},"\"B\"",[178,1054,1055],{"class":242},"][",[178,1057,1058],{"class":296},"1",[178,1060,1061],{"class":242},":]:           ",[178,1063,1064],{"class":315},"# column B, skip the header\n",[178,1066,1067,1070,1072],{"class":112,"line":364},[178,1068,1069],{"class":242},"    cell.number_format ",[178,1071,265],{"class":238},[178,1073,1074],{"class":187}," \"$#,##0.00\"\n",[178,1076,1077],{"class":112,"line":525},[178,1078,256],{"emptyLinePlaceholder":255},[178,1080,1081,1083,1086],{"class":112,"line":530},[178,1082,367],{"class":242},[178,1084,1085],{"class":187},"\"format_column.xlsx\"",[178,1087,373],{"class":242},[178,1089,1090,1092,1094,1097,1100,1102,1105,1107,1110],{"class":112,"line":540},[178,1091,327],{"class":296},[178,1093,330],{"class":242},[178,1095,1096],{"class":187},"\"Formatted\"",[178,1098,1099],{"class":242},", ws.max_row ",[178,1101,826],{"class":238},[178,1103,1104],{"class":296}," 1",[178,1106,451],{"class":242},[178,1108,1109],{"class":187},"\"revenue cells\"",[178,1111,373],{"class":242},[10,1113,1114],{},"Formatting an empty cell is harmless — the format simply applies once a value lands there — so you can format a few rows past the current data if more is coming.",[164,1116,1118],{"id":1117},"date-and-time-formats","Date and time formats",[10,1120,1121,1122,1125,1126,1129,1130,1132],{},"Dates need a real Python ",[19,1123,1124],{},"datetime.date"," or ",[19,1127,1128],{},"datetime.datetime"," so Excel stores a true date serial number. Then ",[19,1131,77],{}," controls the rendered layout. Write the object directly; do not pre-format it into a string, or Excel treats it as text and cannot reformat it.",[169,1134,1136],{"className":229,"code":1135,"language":231,"meta":174,"style":174},"from datetime import date, datetime\nfrom openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\nws.append([\"Event\", \"When\"])\nws.append([\"Invoice\", date(2024, 3, 9)])\nws.append([\"Logged\", datetime(2024, 3, 9, 14, 30)])\n\nws[\"B2\"].number_format = \"yyyy-mm-dd\"          # 2024-03-09\nws[\"B3\"].number_format = \"mmm d, yyyy h:mm\"    # Mar 9, 2024 14:30\n\nwb.save(\"date_formats.xlsx\")\nprint(\"Wrote real date serials with display formats\")\n",[19,1137,1138,1150,1160,1164,1172,1180,1194,1220,1251,1255,1271,1287,1291,1300],{"__ignoreMap":174},[178,1139,1140,1142,1145,1147],{"class":112,"line":180},[178,1141,239],{"class":238},[178,1143,1144],{"class":242}," datetime ",[178,1146,246],{"class":238},[178,1148,1149],{"class":242}," date, datetime\n",[178,1151,1152,1154,1156,1158],{"class":112,"line":252},[178,1153,239],{"class":238},[178,1155,243],{"class":242},[178,1157,246],{"class":238},[178,1159,249],{"class":242},[178,1161,1162],{"class":112,"line":259},[178,1163,256],{"emptyLinePlaceholder":255},[178,1165,1166,1168,1170],{"class":112,"line":271},[178,1167,262],{"class":242},[178,1169,265],{"class":238},[178,1171,268],{"class":242},[178,1173,1174,1176,1178],{"class":112,"line":282},[178,1175,274],{"class":242},[178,1177,265],{"class":238},[178,1179,279],{"class":242},[178,1181,1182,1184,1187,1189,1192],{"class":112,"line":300},[178,1183,445],{"class":242},[178,1185,1186],{"class":187},"\"Event\"",[178,1188,451],{"class":242},[178,1190,1191],{"class":187},"\"When\"",[178,1193,457],{"class":242},[178,1195,1196,1198,1201,1204,1207,1209,1212,1214,1217],{"class":112,"line":319},[178,1197,445],{"class":242},[178,1199,1200],{"class":187},"\"Invoice\"",[178,1202,1203],{"class":242},", date(",[178,1205,1206],{"class":296},"2024",[178,1208,451],{"class":242},[178,1210,1211],{"class":296},"3",[178,1213,451],{"class":242},[178,1215,1216],{"class":296},"9",[178,1218,1219],{"class":242},")])\n",[178,1221,1222,1224,1227,1230,1232,1234,1236,1238,1240,1242,1245,1247,1249],{"class":112,"line":324},[178,1223,445],{"class":242},[178,1225,1226],{"class":187},"\"Logged\"",[178,1228,1229],{"class":242},", datetime(",[178,1231,1206],{"class":296},[178,1233,451],{"class":242},[178,1235,1211],{"class":296},[178,1237,451],{"class":242},[178,1239,1216],{"class":296},[178,1241,451],{"class":242},[178,1243,1244],{"class":296},"14",[178,1246,451],{"class":242},[178,1248,85],{"class":296},[178,1250,1219],{"class":242},[178,1252,1253],{"class":112,"line":347},[178,1254,256],{"emptyLinePlaceholder":255},[178,1256,1257,1259,1261,1263,1265,1268],{"class":112,"line":364},[178,1258,285],{"class":242},[178,1260,496],{"class":187},[178,1262,307],{"class":242},[178,1264,265],{"class":238},[178,1266,1267],{"class":187}," \"yyyy-mm-dd\"",[178,1269,1270],{"class":315},"          # 2024-03-09\n",[178,1272,1273,1275,1277,1279,1281,1284],{"class":112,"line":525},[178,1274,285],{"class":242},[178,1276,512],{"class":187},[178,1278,307],{"class":242},[178,1280,265],{"class":238},[178,1282,1283],{"class":187}," \"mmm d, yyyy h:mm\"",[178,1285,1286],{"class":315},"    # Mar 9, 2024 14:30\n",[178,1288,1289],{"class":112,"line":530},[178,1290,256],{"emptyLinePlaceholder":255},[178,1292,1293,1295,1298],{"class":112,"line":540},[178,1294,367],{"class":242},[178,1296,1297],{"class":187},"\"date_formats.xlsx\"",[178,1299,373],{"class":242},[178,1301,1302,1304,1306,1309],{"class":112,"line":892},[178,1303,327],{"class":296},[178,1305,330],{"class":242},[178,1307,1308],{"class":187},"\"Wrote real date serials with display formats\"",[178,1310,373],{"class":242},[10,1312,1313,1314,1317,1318,557],{},"For string-to-date pitfalls, locale layouts like ",[19,1315,1316],{},"dd\u002Fmm\u002Fyyyy",", and pandas datetime columns, read ",[24,1319,1321],{"href":1320},"\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",[164,1323,1325],{"id":1324},"common-number-format-codes","Common number-format codes",[1327,1328,1329,1348],"table",{},[1330,1331,1332],"thead",{},[1333,1334,1335,1339,1345],"tr",{},[1336,1337,1338],"th",{},"Code",[1336,1340,1341,1342,1344],{},"Displays ",[19,1343,103],{}," as",[1336,1346,1347],{},"Use for",[1349,1350,1351,1367,1382,1396,1411,1428,1446,1461,1479,1496,1512,1530],"tbody",{},[1333,1352,1353,1359,1364],{},[1354,1355,1356],"td",{},[19,1357,1358],{},"#,##0",[1354,1360,1361],{},[19,1362,1363],{},"1,235",[1354,1365,1366],{},"Grouped integers, counts",[1333,1368,1369,1374,1379],{},[1354,1370,1371],{},[19,1372,1373],{},"#,##0.00",[1354,1375,1376],{},[19,1377,1378],{},"1,234.50",[1354,1380,1381],{},"Fixed two-decimal numbers",[1333,1383,1384,1389,1393],{},[1354,1385,1386],{},[19,1387,1388],{},"$#,##0.00",[1354,1390,1391],{},[19,1392,157],{},[1354,1394,1395],{},"US-dollar currency",[1333,1397,1398,1403,1408],{},[1354,1399,1400],{},[19,1401,1402],{},"€#,##0.00",[1354,1404,1405],{},[19,1406,1407],{},"€1,234.50",[1354,1409,1410],{},"Euro currency",[1333,1412,1413,1418,1425],{},[1354,1414,1415],{},[19,1416,1417],{},"0.0%",[1354,1419,330,1420,1422,1423],{},[19,1421,575],{}," →) ",[19,1424,571],{},[1354,1426,1427],{},"Percentages from a ratio",[1333,1429,1430,1435,1443],{},[1354,1431,1432],{},[19,1433,1434],{},"#,##0.00;[Red](#,##0.00)",[1354,1436,1437,1439,1440],{},[19,1438,1378],{}," \u002F red ",[19,1441,1442],{},"(…)",[1354,1444,1445],{},"Red, parenthesized negatives",[1333,1447,1448,1453,1458],{},[1354,1449,1450],{},[19,1451,1452],{},"0.00E+00",[1354,1454,1455],{},[19,1456,1457],{},"1.23E+03",[1354,1459,1460],{},"Scientific notation",[1333,1462,1463,1468,1476],{},[1354,1464,1465],{},[19,1466,1467],{},"yyyy-mm-dd",[1354,1469,330,1470,1422,1473],{},[19,1471,1472],{},"date",[19,1474,1475],{},"2024-03-09",[1354,1477,1478],{},"ISO dates",[1333,1480,1481,1486,1493],{},[1354,1482,1483],{},[19,1484,1485],{},"mmm d, yyyy",[1354,1487,330,1488,1422,1490],{},[19,1489,1472],{},[19,1491,1492],{},"Mar 9, 2024",[1354,1494,1495],{},"Readable dates",[1333,1497,1498,1502,1509],{},[1354,1499,1500],{},[19,1501,1316],{},[1354,1503,330,1504,1422,1506],{},[19,1505,1472],{},[19,1507,1508],{},"09\u002F03\u002F2024",[1354,1510,1511],{},"Day-first dates",[1333,1513,1514,1519,1527],{},[1354,1515,1516],{},[19,1517,1518],{},"h:mm:ss",[1354,1520,330,1521,1422,1524],{},[19,1522,1523],{},"time",[19,1525,1526],{},"14:30:00",[1354,1528,1529],{},"Times",[1333,1531,1532,1537,1542],{},[1354,1533,1534],{},[19,1535,1536],{},"@",[1354,1538,1539,1541],{},[19,1540,103],{}," (as text)",[1354,1543,1544],{},"Force text display",[164,1546,1548],{"id":1547},"frequently-asked-questions","Frequently asked questions",[1550,1551,1553],"h3",{"id":1552},"does-number_format-change-the-cells-value","Does number_format change the cell's value?",[10,1555,1556,1557,1560],{},"No. It only changes the display. ",[19,1558,1559],{},"cell.value"," returns the same number you stored, and formulas operate on that raw value. This is the single most important rule when debugging a \"wrong\" report.",[1550,1562,1564],{"id":1563},"why-does-my-percentage-show-as-2500","Why does my percentage show as 2500%?",[10,1566,1567,1568,1570,1571,1573,1574,1576],{},"You stored ",[19,1569,579],{}," instead of ",[19,1572,575],{},". The ",[19,1575,567],{}," code multiplies by 100 for display, so store the ratio. Divide integer percentages by 100 before writing.",[1550,1578,1580],{"id":1579},"why-is-my-currency-format-being-ignored","Why is my currency format being ignored?",[10,1582,1583,1584,1586,1587,1125,1590,1593,1594,1597],{},"The cell almost certainly holds text, not a number. A value like ",[19,1585,385],{}," (a string) will not format as currency. Write a real ",[19,1588,1589],{},"int",[19,1591,1592],{},"float",", or convert with ",[19,1595,1596],{},"float(value)"," before assigning.",[1550,1599,1601],{"id":1600},"can-i-reuse-one-format-across-many-cells","Can I reuse one format across many cells?",[10,1603,1604,1605,1607,1608,1611,1612,557],{},"Yes — assigning the same string to many cells' ",[19,1606,77],{}," is cheap. For richer reuse, wrap a format in a ",[19,1609,1610],{},"NamedStyle"," and apply the style by name; see ",[24,1613,1615],{"href":1614},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002F","Styling Excel Cells with openpyxl",[1550,1617,1619],{"id":1618},"do-these-codes-match-excels-format-cells-dialog","Do these codes match Excel's Format Cells dialog?",[10,1621,1622,1623,557],{},"Yes. The strings are the same custom format codes Excel shows under Format Cells → Custom. Anything you can type there, you can assign to ",[19,1624,77],{},[164,1626,1628],{"id":1627},"conclusion","Conclusion",[10,1630,1631,1633,1634,200,1636,1639],{},[19,1632,77],{}," is a display layer over an unchanged value. Store real numbers and real ",[19,1635,1472],{},[19,1637,1638],{},"datetime"," objects, then choose a format code for presentation. Keep ratios as ratios for percentages, supply a negative section for red losses, and loop a column to format a report in one pass. Because formatting never mutates the value, your formulas and exports stay correct no matter how the cells look.",[164,1641,1643],{"id":1642},"where-to-go-next","Where to go next",[1645,1646,1647,1653,1658,1663,1668],"ul",{},[1648,1649,1650,1652],"li",{},[24,1651,27],{"href":26}," — the parent pillar covering visual report polish end to end.",[1648,1654,1655,1657],{},[24,1656,556],{"href":555}," — symbols, accounting parentheses, and whole-column currency.",[1648,1659,1660,1662],{},[24,1661,1321],{"href":1320}," — real date serials and pandas datetime export.",[1648,1664,1665,1667],{},[24,1666,1615],{"href":1614}," — fonts, fills, borders, and reusable named styles.",[1648,1669,1670,1674],{},[24,1671,1673],{"href":1672},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-charts-in-excel-with-openpyxl\u002F","Creating Charts in Excel with openpyxl"," — turn formatted tables into native Excel charts.",[1676,1677,1678],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":174,"searchDepth":252,"depth":252,"links":1680},[1681,1682,1683,1684,1685,1686,1687,1688,1689,1696,1697],{"id":166,"depth":252,"text":167},{"id":207,"depth":252,"text":208},{"id":389,"depth":252,"text":390},{"id":560,"depth":252,"text":561},{"id":743,"depth":252,"text":744},{"id":920,"depth":252,"text":921},{"id":1117,"depth":252,"text":1118},{"id":1324,"depth":252,"text":1325},{"id":1547,"depth":252,"text":1548,"children":1690},[1691,1692,1693,1694,1695],{"id":1552,"depth":259,"text":1553},{"id":1563,"depth":259,"text":1564},{"id":1579,"depth":259,"text":1580},{"id":1600,"depth":259,"text":1601},{"id":1618,"depth":259,"text":1619},{"id":1627,"depth":252,"text":1628},{"id":1642,"depth":252,"text":1643},"2026-06-18","Format numbers, currency, percentages, and dates in Excel from Python with openpyxl number_format codes — display-only formatting that never alters the stored value.","md",[1702,1704,1706,1708,1710],{"q":1553,"a":1703},"No. It only changes the display. cell.value returns the same number you stored, and formulas operate on that raw value. This is the single most important rule when debugging a \"wrong\" report.",{"q":1564,"a":1705},"You stored 25 instead of 0.25. The % code multiplies by 100 for display, so store the ratio. Divide integer percentages by 100 before writing.",{"q":1580,"a":1707},"The cell almost certainly holds text, not a number. A value like \"1234.5\" (a string) will not format as currency. Write a real int or float, or convert with float(value) before assigning.",{"q":1601,"a":1709},"Yes — assigning the same string to many cells' number_format is cheap. For richer reuse, wrap a format in a NamedStyle and apply the style by name; see Styling Excel Cells with openpyxl.",{"q":1619,"a":1711},"Yes. The strings are the same custom format codes Excel shows under Format Cells → Custom. Anything you can type there, you can assign to number_format.",{},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel",{"title":1715,"description":1716},"Number and Date Formats in Excel with Python","Use openpyxl number_format codes to show currency, thousands separators, percentages, negatives in red, and dates — without touching the underlying cell value.","applying-number-and-date-formats-in-excel","formatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel\u002Findex","cluster","WHo4zhZZzHwByayBewdwHdv_fijmQ69S42SEtVLlSKw",[1722,1725],{"title":27,"path":1723,"stem":1724,"children":-1},"\u002Fformatting-and-charting-excel-reports-with-python","formatting-and-charting-excel-reports-with-python\u002Findex",{"title":1321,"path":1726,"stem":1727,"children":-1},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel\u002Fformat-dates-in-excel-cells-with-python","formatting-and-charting-excel-reports-with-python\u002Fapplying-number-and-date-formats-in-excel\u002Fformat-dates-in-excel-cells-with-python\u002Findex",1781795518492]