Skip to main content

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.

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).

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).
note
  • 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, use astype('datetime64[ms]').
  • Pandas internally represents datetime64 with nanosecond precision ([ns]), so even if you specify [s] or [ms], the final dtype will be datetime64[ns] (or datetime64[ns, UTC] if converted via pd.to_datetime with 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 timezone datetime object by default.
  • If your epoch is in milliseconds, divide by 1000: lambda ms: datetime.fromtimestamp(ms / 1000.0).
  • The resulting column Datetime_apply will have object dtype because it holds Python datetime objects, not Pandas Timestamp (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

Choosing the Right Method

  • (Method 1) pd.to_datetime(series, unit='...'): Highly recommended. It's the most direct, idiomatic Pandas way, handles various input types (numeric, string), correctly specifies the epoch unit, and produces a datetime64[ns] column (often UTC-aware), which is ideal for further Pandas time series operations.

  • (Method 2) series.astype('int64').astype('datetime64[unit]'): A valid alternative, especially if you are certain of the numeric type of your epoch column. Less flexible with input types than pd.to_datetime.

  • (Method 3) series.apply(lambda x: datetime.fromtimestamp(float(x))): Works, but generally less efficient for large Series than the vectorized Pandas methods. It creates Python datetime objects (resulting in an object dtype column) and defaults to local timezone, which might require additional conversion steps if UTC or another timezone is needed.

Conclusion

Converting Epoch timestamps to datetime objects in Pandas is crucial for time-based analysis.

  • The preferred method is pd.to_datetime(your_epoch_series, unit='s') (for seconds) or unit='ms' (for milliseconds). This correctly handles the conversion to Pandas' native datetime64[ns] type.
  • Ensure your Epoch column is numeric before conversion; if it's strings, convert using pd.to_numeric() or astype(int) first.
  • Be mindful of the unit of your Epoch time (seconds, milliseconds, etc.) to avoid OutOfBoundsDatetime errors or incorrect conversions.
  • The astype('datetime64[unit]') method offers an alternative, while apply() with datetime.fromtimestamp is less optimal but functional.

By using pd.to_datetime with the correct unit, you can seamlessly integrate Epoch timestamps into your Pandas date and time workflows.