Python Pandas: How to Convert Epoch Time to Datetime (Seconds/Milliseconds)
Epoch time, also known as Unix time or POSIX time, represents a point in time as the number of seconds (or milliseconds, microseconds, etc.) that have elapsed since 00:00:00 Coordinated Universal Time (UTC) on Thursday, 1 January 1970. When working with datasets that store timestamps in Epoch format, you'll often need to convert these numerical timestamps into human-readable datetime objects in Pandas for easier analysis and manipulation.
This guide explains how to effectively convert Epoch timestamps (in seconds or milliseconds) to Pandas datetime objects using pd.to_datetime(), astype(), and apply() with datetime.fromtimestamp().
Understanding Epoch Time
- Definition: The number of seconds (or other units) that have passed since January 1, 1970, at 00:00:00 UTC.
- Units: Epoch time can be represented in various units:
- Seconds (
s): Most common. - Milliseconds (
ms): 1 second = 1000 milliseconds. - Microseconds (
us): 1 second = 1,000,000 microseconds. - Nanoseconds (
ns): 1 second = 1,000,000,000 nanoseconds. It's crucial to know the unit of your Epoch timestamps for correct conversion.
- Seconds (
Example DataFrame with Epoch Timestamps
import pandas as pd
# Epoch timestamps (assume these are seconds since epoch)
data_seconds = {
'EventID': ['A01', 'B02', 'C03'],
'Timestamp_Epoch_Sec': [1747579311, 1757579311, 1767579311], # Example seconds
'Value': [10, 20, 15]
}
df_sec = pd.DataFrame(data_seconds)
print("DataFrame with Epoch in Seconds:")
print(df_sec)
print(df_sec.dtypes)
print()
# Epoch timestamps (assume these are milliseconds since epoch)
data_ms = {
'LogID': ['L1', 'L2', 'L3'],
'Timestamp_Epoch_MS': [1747579311, 1757579311, 1767579311], # Example milliseconds
'Metric': [0.5, 0.7, 0.3]
}
df_ms = pd.DataFrame(data_ms)
print("DataFrame with Epoch in Milliseconds:")
print(df_ms)
print(df_ms.dtypes)
Output:
DataFrame with Epoch in Seconds:
EventID Timestamp_Epoch_Sec Value
0 A01 1747579311 10
1 B02 1757579311 20
2 C03 1767579311 15
EventID object
Timestamp_Epoch_Sec int64
Value int64
dtype: object
DataFrame with Epoch in Milliseconds:
LogID Timestamp_Epoch_MS Metric
0 L1 1747579311 0.5
1 L2 1757579311 0.7
2 L3 1767579311 0.3
LogID object
Timestamp_Epoch_MS int64
Metric float64
dtype: object
The 'Timestamp_Epoch_Sec' and 'Timestamp_Epoch_MS' columns are initially integers (or could be strings representing these numbers).
Method 1: Using pd.to_datetime(series, unit='s' or 'ms') (Recommended)
The pandas.to_datetime() function is the most direct and idiomatic way to perform this conversion. The key is the unit parameter.
Epoch in Seconds
If your Epoch timestamps are in seconds:
import pandas as pd
df_sec_example = pd.DataFrame({
'EventID': ['A01', 'B02'], 'Timestamp_Epoch_Sec': [1747579311, 1757579311]
})
# ✅ Convert Epoch (seconds) to datetime
# Ensure the column is numeric first if it's string:
# df_sec_example['Timestamp_Epoch_Sec'] = pd.to_numeric(df_sec_example['Timestamp_Epoch_Sec'])
df_sec_example['Datetime_UTC'] = pd.to_datetime(df_sec_example['Timestamp_Epoch_Sec'], unit='s')
print("DataFrame after converting Epoch (seconds) to Datetime (UTC):")
print(df_sec_example)
Output:
DataFrame after converting Epoch (seconds) to Datetime (UTC):
EventID Timestamp_Epoch_Sec Datetime_UTC
0 A01 1747579311 2025-05-18 14:41:51
1 B02 1757579311 2025-09-11 08:28:31
unit='s': Specifies that the input numbers are seconds since the epoch.- The resulting datetime objects are timezone-aware (UTC) by default when converting from an epoch unit. You can convert them to a specific timezone or make them timezone-naive using
.dt.tz_convert()or.dt.tz_localize(None).
-
By default, to_datetime from epoch creates UTC-aware datetimes.
-
To convert to local time (e.g., if your server's timezone is desired):
df_sec_example['Datetime_Local'] = df_sec_example['Datetime_UTC'].dt.tz_localize(None) # Naive -
Or if you know the source was UTC and want to convert:
df_sec_example['Datetime_Local'] = df_sec_example['Datetime_UTC'].dt.tz_convert('America/New_York')
Epoch in Milliseconds
If your Epoch timestamps are in milliseconds:
import pandas as pd
df_ms_example = pd.DataFrame({
'LogID': ['L1', 'L2'], 'Timestamp_Epoch_MS': [1747579311123, 1757579311123]
})
# ✅ Convert Epoch (milliseconds) to datetime
# Ensure numeric type if starting from strings:
# df_ms_example['Timestamp_Epoch_MS'] = pd.to_numeric(df_ms_example['Timestamp_Epoch_MS'])
df_ms_example['Datetime_UTC'] = pd.to_datetime(df_ms_example['Timestamp_Epoch_MS'], unit='ms')
print("DataFrame after converting Epoch (milliseconds) to Datetime (UTC):")
print(df_ms_example)
Output:
DataFrame after converting Epoch (milliseconds) to Datetime (UTC):
LogID Timestamp_Epoch_MS Datetime_UTC
0 L1 1747579311123 2025-05-18 14:41:51.123
1 L2 1757579311123 2025-09-11 08:28:31.123
unit='ms': Specifies that the input numbers are milliseconds.
Verifying the Data Type
After conversion, check the dtype of the new column. It should be datetime64[ns].
import pandas as pd
df_ms_example = pd.DataFrame({
'LogID': ['L1', 'L2'],
'Timestamp_Epoch_MS': [1747579311123, 1757579311123]
})
# Convert the milliseconds to datetime
df_ms_example['Timestamp'] = pd.to_datetime(df_ms_example['Timestamp_Epoch_MS'], unit='ms')
print("Dtypes after conversion:")
print(df_ms_example.dtypes)
Output:
Dtypes after conversion:
LogID object
Timestamp_Epoch_MS int64
Timestamp datetime64[ns]
dtype: object
Common Error: OutOfBoundsDatetime (Incorrect Unit)
If you specify the wrong unit (e.g., 's' for millisecond timestamps, or vice-versa), pd.to_datetime() might raise an OutOfBoundsDatetime error. This happens because interpreting a large millisecond value as seconds would result in a date far outside Pandas' representable datetime64[ns] range.
# Example of error
df_error = pd.DataFrame({'Epoch_MS': [1747579311123]})
try:
# ⛔️ Trying to interpret milliseconds as seconds
pd.to_datetime(df_error['Epoch_MS'], unit='s')
except pd.errors.OutOfBoundsDatetime as e:
print(f"Caught OutOfBoundsDatetime error: {e}")
print("This likely means the 'unit' parameter is incorrect for the magnitude of epoch values.")
Output:
Caught OutOfBoundsDatetime error: Out of bounds nanosecond timestamp: 57348-08-01 09:32:03
This likely means the 'unit' parameter is incorrect for the magnitude of epoch values.
Solution: Ensure the unit parameter matches the actual unit of your Epoch timestamps. If unsure, inspect the magnitude of your epoch numbers. Values around 1.6x10^9 are likely seconds, while values around 1.6x10^12 are likely milliseconds.
Method 2: Using Series.astype() (Chained Conversion)
You can first ensure your Epoch column is of an integer type, then cast it to datetime64 with the appropriate unit.
import pandas as pd
df_astype_example = pd.DataFrame({
'EventID': ['A01'], 'Timestamp_Epoch_Sec': ['1747579311'] # Epoch as string
})
# Ensure numeric first, then cast to datetime64 with unit
df_astype_example['Timestamp_Epoch_Sec'] = df_astype_example['Timestamp_Epoch_Sec'].astype('int64')
df_astype_example['Datetime_from_astype'] = df_astype_example['Timestamp_Epoch_Sec'].astype('datetime64[s]')
print("DataFrame after astype('datetime64[s]'):")
print(df_astype_example)
print(df_astype_example.dtypes)
Output:
DataFrame after astype('datetime64[s]'):
EventID Timestamp_Epoch_Sec Datetime_from_astype
0 A01 1747579311 2025-05-18 14:41:51
EventID object
Timestamp_Epoch_Sec int64
Datetime_from_astype datetime64[s]
dtype: object
astype('int64'): Converts string epoch values to integers first (important).astype('datetime64[s]'): Casts the integer epoch (in seconds) to datetime. For milliseconds, useastype('datetime64[ms]').- Pandas internally represents
datetime64with nanosecond precision ([ns]), so even if you specify[s]or[ms], the final dtype will bedatetime64[ns](ordatetime64[ns, UTC]if converted viapd.to_datetimewith a unit). - Pandas converts to ns, but interprets input as seconds!
Method 3: Using Series.apply() with datetime.fromtimestamp()
This method uses Python's standard library datetime.fromtimestamp() function, applied row-wise. This typically handles epoch seconds.
Converting to Datetime Objects
import pandas as pd
from datetime import datetime # Python's datetime
df_apply_example = pd.DataFrame({
'EventID': ['A01'], 'Timestamp_Epoch_Sec': ['1747579311'] # Epoch as string
})
# Ensure epoch column is integer before applying fromtimestamp
df_apply_example['Timestamp_Epoch_Sec'] = df_apply_example['Timestamp_Epoch_Sec'].astype(float) # fromtimestamp expects float
# ✅ Apply datetime.fromtimestamp to each epoch value
# This creates Python datetime objects, so the column becomes 'object' dtype
df_apply_example['Datetime_apply'] = df_apply_example['Timestamp_Epoch_Sec'].apply(
lambda epoch_seconds: datetime.fromtimestamp(epoch_seconds)
)
print("DataFrame after apply(datetime.fromtimestamp):")
print(df_apply_example)
print(df_apply_example.dtypes)
Output:
DataFrame after apply(datetime.fromtimestamp):
EventID Timestamp_Epoch_Sec Datetime_apply
0 A01 1.747579e+09 2025-05-18 16:41:51
EventID object
Timestamp_Epoch_Sec float64
Datetime_apply datetime64[ns]
dtype: object
datetime.fromtimestamp(epoch_seconds): Converts seconds since epoch to a local timezonedatetimeobject by default.- If your epoch is in milliseconds, divide by 1000:
lambda ms: datetime.fromtimestamp(ms / 1000.0). - The resulting column
Datetime_applywill haveobjectdtype because it holds Pythondatetimeobjects, not PandasTimestamp(datetime64[ns]) objects. You can convert it further if needed:pd.to_datetime(df_apply_example['Datetime_apply']).
Optional: Formatting to String
You can format the resulting datetime object to a string within the apply.
import pandas as pd
from datetime import datetime # Python's datetime
df_apply_example = pd.DataFrame({
'EventID': ['A01'], 'Timestamp_Epoch_Sec': ['1747579311'] # Epoch as string
})
df_apply_example['Datetime_apply_str'] = df_apply_example['Timestamp_Epoch_Sec'].apply(
lambda s: datetime.fromtimestamp(float(s)).strftime('%Y-%m-%d %H:%M:%S')
)
print("Formatted string dates using apply:")
print(df_apply_example['Datetime_apply_str'])
Output:
Formatted string dates using apply:
0 2025-05-18 16:41:51
Name: Datetime_apply_str, dtype: object