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)
- Parse with an explicit format.
pd.to_datetime("12-11-2010 00:00", format="%d-%m-%Y %H:%M")reads day-month-year unambiguously. Passingformatis the most predictable option. - Decide what happens to bad values. The default
errors='raise'stops on the first invalid value.errors='coerce'turns invalid values intoNaT:pd.to_datetime(["2009/07/31", "asd"], errors="coerce")givesDatetimeIndex(['2009-07-31', 'NaT'], dtype='datetime64[us]'). Count the resultingNaTvalues before analysis, because they are silently introduced data loss. Missing-value handling is covered in dropna in pandas. - Resolve ambiguous day/month order.
dayfirst=Truereads “10/11/12” as 2012-11-10;yearfirst=Truereads it as 2010-11-12; if both are True,yearfirstwins. The documentation states thatdayfirstis “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 preferformatfor anything that matters. - Convert numbers. For numeric input, set
unit(for example"s","D","ms").pd.to_datetime(1490195805, unit="s")returnsTimestamp('2017-03-22 15:16:45'). Theoriginargument 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'requiresunit='D'. - Assemble from columns. Passing a DataFrame with
year,monthanddaycolumns (four-digit year) returns adatetime64Series. - Handle time zones.
utc=Truelocalises naive values as UTC and converts aware values to UTC. Withutc=False, naive values stay naive and aware values keep their offsets. Afterwards,tz_localizeattaches a zone to naive data andtz_convertchanges an aware series to another zone. - Select and aggregate. With a datetime index, partial string indexing works:
ts["2011"],ts["2011-6"],dft.loc["2013"], anddft["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 withpd.date_range(default frequency"D") orpd.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
- pandas.to_datetime, pandas documentation (read 2026-11-08)
- Time series / date functionality, pandas user guide (read 2026-11-08)
- datetime, Python documentation







