Skip to content

Python Pandas: How to Convert Epoch Time to Datetime (Seconds/Milliseconds)

Learn how to convert Unix epoch timestamps (seconds or milliseconds) to Pandas datetime objects using pd.to_datetime(), astype(), and apply() methods with proper unit handling.

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

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

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]
})

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

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]
})

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]
})

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.

df_error = pd.DataFrame({'Epoch_MS': [1747579311123]})
try:
    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
})

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

df_apply_example['Timestamp_Epoch_Sec'] = df_apply_example['Timestamp_Epoch_Sec'].astype(float) # fromtimestamp expects float

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.

Navigation