Skip to main content
v2026.11,858 entries · CC-BY 4.0

pandas datetime: to_datetime, .dt and time zones

How pandas datetime works: to_datetime arguments, errors, time zones, pandas 3.0 microsecond default, and resampling, with documented outputs.

Written and maintained by CASRAI Editorial Board

Last updated

Who this is for: researchers and analysts who have dates stored as text, numbers or separate year/month/day columns in a pandas DataFrame and need real datetime values they can slice, convert across time zones and resample. Everything below follows the pandas 3.x documentation (read 2026-11-08).

What pandas datetime is used for in research

In pandas, “datetime” means the datetime64 dtype, the Timestamp scalar and the DatetimeIndex. The function that creates them is pandas.to_datetime. It returns a Timestamp for a single string, a DatetimeIndex for a list-like, and a datetime64 Series for a Series. Once a column is datetime, the .dt accessor exposes parts such as year, month, day_of_week, quarter and is_month_end, and .dt.isocalendar() returns ISO year, week and day. Typical research uses are visit dates in clinical or survey data, sensor logs, and publication or grant dates. Rolling statistics on such data are covered in pandas rolling; the R equivalent is covered in lubridate.

Install or access

pandas is free, open-source software distributed through its official site, pandas.pydata.org. The usual route is pip install pandas, then import pandas as pd. The Python standard-library datetime module (documented at docs.python.org) defines the strftime format codes that pandas uses in its format argument.

Step-by-step: turn a column into datetimes

The signature in the current documentation is:

pandas.to_datetime(arg, errors='raise', dayfirst=False, yearfirst=False, utc=False, format=None, exact=<no_default>, unit=None, origin='unix', cache=True)
  1. Parse with an explicit format. pd.to_datetime("12-11-2010 00:00", format="%d-%m-%Y %H:%M") reads day-month-year unambiguously. Passing format is the most predictable option.
  2. Decide what happens to bad values. The default errors='raise' stops on the first invalid value. errors='coerce' turns invalid values into NaT: pd.to_datetime(["2009/07/31", "asd"], errors="coerce") gives DatetimeIndex(['2009-07-31', 'NaT'], dtype='datetime64[us]'). Count the resulting NaT values before analysis, because they are silently introduced data loss. Missing-value handling is covered in dropna in pandas.
  3. Resolve ambiguous day/month order. dayfirst=True reads “10/11/12” as 2012-11-10; yearfirst=True reads it as 2010-11-12; if both are True, yearfirst wins. The documentation states that dayfirst is “not strict, but will prefer to parse with day first”, and a value that cannot be read day-first falls back with a warning, so prefer format for anything that matters.
  4. Convert numbers. For numeric input, set unit (for example "s", "D", "ms"). pd.to_datetime(1490195805, unit="s") returns Timestamp('2017-03-22 15:16:45'). The origin argument shifts the zero point: pd.to_datetime([1, 2, 3], unit="D", origin=pd.Timestamp("1960-01-01")) returns 1960-01-02, 1960-01-03 and 1960-01-04. origin='julian' requires unit='D'.
  5. Assemble from columns. Passing a DataFrame with year, month and day columns (four-digit year) returns a datetime64 Series.
  6. Handle time zones. utc=True localises naive values as UTC and converts aware values to UTC. With utc=False, naive values stay naive and aware values keep their offsets. Afterwards, tz_localize attaches a zone to naive data and tz_convert changes an aware series to another zone.
  7. Select and aggregate. With a datetime index, partial string indexing works: ts["2011"], ts["2011-6"], dft.loc["2013"], and dft["2013-1":"2013-2-28"], which includes all of 28 February. ts.resample("2h").mean() on an hourly series with values 0 to 4 gives 0.5, 2.5 and 4.0. Build regular indexes with pd.date_range (default frequency "D") or pd.bdate_range (business days); freq="ME" is month-end.

Which argument fixes which data problem

Data problem Argument Documented behaviour
Unparseable entries in a column errors='coerce' Invalid values become NaT; default 'raise' stops instead
Ambiguous dd/mm vs mm/dd dayfirst, yearfirst, or better format “10/11/12” gives 2012-11-10 with dayfirst, 2010-11-12 with yearfirst; dayfirst is not strict
Known text layout format="%d/%m/%Y" strftime pattern; "ISO8601" accepts any ISO 8601 layout; "mixed" infers per element and the docs call it risky
Epoch numbers unit, origin Numeric input only; origin='unix' is 1970-01-01
Offsets in strings utc=True Aware values converted to UTC, e.g. 12:00 -0530 and 12:00 -0500 become 17:30 and 17:00 UTC

Output and how to read it

Check df["col"].dtype: datetime64[us] (or [ns]) means the parse worked, while object means pandas fell back to Python datetime.datetime objects or never parsed. The documentation lists the fallback cases: values outside the Timestamp range, mixed naive and aware values, and mixed offsets with utc=False. Since pandas 3.0, strings parse to microsecond resolution unless nanosecond precision is present (earlier versions always used nanoseconds). Nanosecond resolution spans about 584 years, with Timestamp.min of 1677-09-21 00:12:43.145224193 and Timestamp.max of 2262-04-11 23:47:16.854775807; pd.Timestamp("3000-06-10") has unit 'us' and does not raise. as_unit() converts between units. Check which resolution your pandas version produced before comparing or merging datetime columns from different sources (see pandas concat).

Troubleshooting

“Mixed timezones detected”

Parsing ["2020-10-25 02:00 +0200", "2020-10-25 04:00 +0100"] with utc=False raises ValueError: Mixed timezones detected. Pass utc=True in to_datetime or tz='UTC' in DatetimeIndex to convert to a common timezone. Pass utc=True.

Dates come out as 1900-01-01

When format omits components, the missing ones default to 1900-01-01 00:00:00; pd.to_datetime(["1", "2"], format="%d") yields January 1900. Include year and month in the format, or fill them in from other columns.

Numbers with format

Integers and floats combined with format are deprecated since pandas 3.1.0; cast to string first.

Epoch values with a time zone

Constructing a Timestamp from an epoch value with a tz argument raises ValueError; read it as naive and call tz_localize.

Single-string lookup on a DataFrame

Selecting rows with frame[dtstring] is no longer supported; use .loc.

Free alternatives

Tool Language Relevant to this task
Python datetime module Python (standard library) Defines the strftime format codes pandas reuses
lubridate R Date-time parsing and manipulation in R

For wider cleaning steps around dates, see data wrangling.

FAQ

What does pandas.to_datetime return?

A Timestamp for a scalar string, a DatetimeIndex for a list-like, and a datetime64 Series for a Series or a year/month/day DataFrame.

How do I turn invalid dates into missing values?

Use errors='coerce'; invalid entries become NaT.

Why does my parsed series have object dtype?

pandas falls back to datetime.datetime objects for out-of-bounds dates, mixed naive and aware values, or mixed offsets without utc=True.

Sources

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about pandas datetime: to_datetime, .dt and time zones

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →