Skip to content

DataFrame export

df_to_xlsx writes a single pandas or polars DataFrame to one worksheet. It is the main entry point, and every formatting, table, chart, and validation option in the rest of these pages is a keyword argument to it.

DataFrame Export (pandas/polars)

import xlsxturbo
import pandas as pd

# Create a DataFrame
df = pd.DataFrame({
    'name': ['Alice', 'Bob'],
    'age': [30, 25],
    'salary': [50000.50, 60000.75],
    'active': [True, False]
})

# Export to XLSX (preserves types: int, float, bool, date, datetime)
rows, cols = xlsxturbo.df_to_xlsx(df, "output.xlsx")
print(f"Wrote {rows} rows and {cols} columns")

# Works with polars too!
import polars as pl
df_polars = pl.DataFrame({'x': [1, 2, 3], 'y': [4.0, 5.0, 6.0]})
xlsxturbo.df_to_xlsx(df_polars, "polars_output.xlsx", sheet_name="Data")

Type Detection Examples

CSV Value Excel Type Notes
123 Number Integer
3.14159 Number Float
true / FALSE Boolean Case insensitive
2024-01-15 Date Formatted as date
2024-01-15T10:30:00 DateTime ISO 8601 format
NaN / inf / Infinity Empty Any spelling of a non-finite number — see below
1899-12-30 … 1900-02-28 Text Excel numbers these a day out — see below
hello world Text Default

Supported date formats: YYYY-MM-DD, YYYY/MM/DD, DD-MM-YYYY, DD/MM/YYYY, MM-DD-YYYY, MM/DD/YYYY

Non-finite numbers, and a trap in text columns

Excel has no NaN or infinity, so a CSV field holding one becomes an empty cell. That covers every spelling the number parser accepts, in any case and with an optional sign: nan, NaN, +nan, inf, -Inf, infinity, INFINITY.

The trap is that some of those are also ordinary words. A text column whose values include NAN or Inf. loses them to empty cells, because nothing distinguishes the word from the number at that point. If a column is meant to be text, say so with a column_format — or check for the spellings above before exporting.

Dates before 1900-03-01

Excel's serial numbering assumes a 1900-02-29 that never existed, so every date before 1900-03-01 is numbered one day later than the real calendar. Rather than write a date that renders on the wrong day, xlsxturbo writes those as text, exactly as they appeared in the input. Dates from 1900-03-01 onward — serial 61 up to Excel's last day, 9999-12-31 — are unaffected.

Very large integers

An integer whose magnitude exceeds 2^53 (9,007,199,254,740,992) cannot be stored as an Excel number without changing value, because Excel stores every number as a double. Those are written as text so no digits are lost. Anything at or below that magnitude is a normal number.

DataFrame columns follow the same mapping, with one addition worth knowing: durations (pandas.Timedelta / numpy.timedelta64) are written as text, e.g. 86400 seconds. Excel has no duration type — convert to a number in the unit you want first (df["elapsed"].dt.total_seconds()) and apply a num_format such as [h]:mm:ss if you want it displayed as a duration.