Extracting Temporal Features
Use the .dt accessor to pull year, month, day, day_of_week, and hour out of a datetime column for feature engineering.
Extracting Temporal Features is a free Pandas & NumPy Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Pandas & NumPy Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Why Extract Temporal Features?
A raw datetime64 column is opaque to most machine learning algorithms — they cannot understand that 2024-12-25 is a holiday or that Friday drives higher retail sales. Temporal feature engineering extracts meaningful components from datetime columns — year, month, day, weekday, hour — as separate numeric or categorical columns that models and analysis functions can act on directly.
The .dt Accessor
When a DataFrame column has datetime64 dtype, the .dt accessor exposes all datetime properties and methods vectorially. Instead of applying a Python function row by row, you write df['date'].dt.year and Pandas computes the year for every row in a single fast operation. The same accessor works on timedelta64 columns with different properties.
import pandas as pd
df = pd.DataFrame({
'event_date': pd.date_range('2024-01-01', periods=8, freq='D'),
'revenue': [200, 350, 280, 310, 420, 380, 190, 260]
})
# Access datetime properties with .dt
print(df['event_date'].dt.year) # 2024 for all
print(df['event_date'].dt.month) # 1 for all
print(df['event_date'].dt.day[:5]) # 1, 2, 3, 4, 5Extracting Date Components
The most commonly used .dt properties for date components are: .dt.year, .dt.month, .dt.day, .dt.day_of_week (0=Monday through 6=Sunday), .dt.day_of_year, .dt.week or .dt.isocalendar().week, .dt.quarter, and .dt.days_in_month. Each returns a Series of integers that can be used directly as features.
df['year'] = df['event_date'].dt.year
df['month'] = df['event_date'].dt.month
df['day'] = df['event_date'].dt.day
df['day_of_week'] = df['event_date'].dt.day_of_week # 0=Mon
df['quarter'] = df['event_date'].dt.quarter
df['day_of_year'] = df['event_date'].dt.day_of_year
print(df[['event_date', 'year', 'month', 'day',
'day_of_week', 'quarter']].head())Extracting Time Components
For datetime columns that include time information (not just date), use .dt.hour, .dt.minute, .dt.second, and .dt.microsecond. These are critical for intraday analysis, user behaviour modelling (morning vs evening patterns), and any system where the time of day drives the target variable.
df_ts = pd.DataFrame({
'timestamp': pd.date_range('2024-01-01', periods=6, freq='4h'),
'logins': [50, 200, 320, 280, 180, 90]
})
df_ts['hour'] = df_ts['timestamp'].dt.hour
df_ts['minute'] = df_ts['timestamp'].dt.minute
df_ts['date'] = df_ts['timestamp'].dt.date # Python date object
df_ts['time'] = df_ts['timestamp'].dt.time # Python time object
print(df_ts[['timestamp', 'hour', 'date']].head())Day Name and Month Name
For human-readable labels, use .dt.day_name() and .dt.month_name() to get string names like 'Monday' and 'January'. These are useful for display in reports and for creating categorical features that encode weekday/month effects. You can also pass a locale to get names in other languages.
df['day_name'] = df['event_date'].dt.day_name()
df['month_name'] = df['event_date'].dt.month_name()
print(df[['event_date', 'day_name', 'month_name']].head(5))
# event_date day_name month_name
# 2024-01-01 Monday January
# 2024-01-02 Tuesday January
# 2024-01-03 Wednesday JanuaryWeekend Flag and Business Day Flag
A very common feature is a boolean flag indicating whether a date falls on a weekend. day_of_week >= 5 gives True for Saturday (5) and Sunday (6). For more sophisticated business calendar features, numpy.busdaycalendar handles holidays, but for most cases the simple weekday/weekend split captures most of the effect.
df['is_weekend'] = df['event_date'].dt.day_of_week >= 5
df['is_weekday'] = ~df['is_weekend']
# Compare weekend vs weekday revenue
print(df.groupby('is_weekend')['revenue'].mean().round(1))
# is_weekend
# False 308.3 <- weekday average
# True 285.0 <- weekend averageStart/End of Period Flags
The .dt accessor also provides boolean properties that identify whether a date is at the start or end of a period: .dt.is_month_start, .dt.is_month_end, .dt.is_quarter_start, .dt.is_quarter_end, .dt.is_year_start, and .dt.is_year_end. These are useful for detecting reporting periods, billing cycles, and seasonal boundary effects.
dates_series = pd.Series(
pd.date_range('2024-01-28', periods=10, freq='D')
)
print(dates_series[dates_series.dt.is_month_start].values)
# ['2024-02-01']
print(dates_series[dates_series.dt.is_month_end].values)
# ['2024-01-31']Cyclical Encoding of Temporal Features
Month and hour are cyclical — December (12) is close to January (1), and 23:00 is close to 00:00. Treating them as linear integers (1-12 or 0-23) misleads most models. Encode cyclical features using sine and cosine transforms: sin(2π × value / max_value) and cos(2π × value / max_value). This embeds the circular structure in two numeric columns that models can use correctly.
import numpy as np
# Cyclical encoding for month (1-12)
df['month_sin'] = np.sin(2 * np.pi * df['month'] / 12)
df['month_cos'] = np.cos(2 * np.pi * df['month'] / 12)
# Cyclical encoding for day of week (0-6)
df['dow_sin'] = np.sin(2 * np.pi * df['day_of_week'] / 7)
df['dow_cos'] = np.cos(2 * np.pi * df['day_of_week'] / 7)
print(df[['month', 'month_sin', 'month_cos']].head().round(3))Timedelta Arithmetic
Subtracting two datetime columns produces a timedelta64 Series. The .dt accessor on timedelta Series exposes .dt.days, .dt.seconds, and .dt.total_seconds(). This lets you compute event durations, time since last purchase, and age in days — all as numeric columns ready for further analysis.
df_orders = pd.DataFrame({
'order_date': pd.to_datetime(['2024-01-01', '2024-02-10', '2024-03-05']),
'delivery_date': pd.to_datetime(['2024-01-04', '2024-02-13', '2024-03-12'])
})
# Compute delivery time in days
df_orders['delivery_days'] = (
df_orders['delivery_date'] - df_orders['order_date']
).dt.days
print(df_orders)Using Index .dt Properties
When the datetime is the DataFrame's index (a DatetimeIndex) rather than a column, access the same properties directly on the index without .dt: df.index.year, df.index.month, df.index.day_of_week, etc. You can add these as new columns directly: df['month'] = df.index.month.
df_indexed = df.set_index('event_date')
# Access components directly on the DatetimeIndex
print(df_indexed.index.month[:3]) # [1, 1, 1]
print(df_indexed.index.day_of_week[:3]) # [0, 1, 2]
# Add as new columns
df_indexed['month'] = df_indexed.index.month
df_indexed['weekday'] = df_indexed.index.day_of_week
print(df_indexed.head())Full Temporal Feature Engineering Pipeline
Here is a complete temporal feature engineering function that takes a DataFrame with a datetime column and returns it enriched with the most useful temporal features. This pattern is directly applicable at the start of any machine learning or analysis pipeline working with time-stamped event data.
def add_temporal_features(df, date_col):
dt = df[date_col].dt
df['year'] = dt.year
df['month'] = dt.month
df['day'] = dt.day
df['day_of_week'] = dt.day_of_week
df['quarter'] = dt.quarter
df['is_weekend'] = dt.day_of_week >= 5
df['month_sin'] = (2 * 3.14159 * dt.month / 12).__round__(4)
df['month_cos'] = (2 * 3.14159 * dt.month / 12).__round__(4)
return df
result = add_temporal_features(df.copy(), 'event_date')
print(result.columns.tolist())Quick Check
Test your understanding of extracting temporal features from datetime columns.
Lesson Recap
In this lesson you learned: the .dt accessor gives vectorised access to all datetime properties; common extracted features include year, month, day, day_of_week, hour, quarter; cyclical encoding with sine/cosine handles the circular nature of hours and months; and timedelta arithmetic lets you compute durations in days or seconds. Next up we explore Matplotlib's figure and axes architecture for creating publication-quality charts.
Frequently asked questions
Is the “Extracting Temporal Features” lesson free?
Yes — the full text of “Extracting Temporal Features” is free to read here on the web, and the Pandas & NumPy Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Pandas & NumPy Academy course, upgrade to CoddyKit PRO.
What will I learn in “Extracting Temporal Features”?
Use the .dt accessor to pull year, month, day, day_of_week, and hour out of a datetime column for feature engineering. You practise Pandas & NumPy Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Pandas & NumPy Academy?
No prior experience is required. Pandas & NumPy Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Extracting Temporal Features” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Pandas & NumPy Academy lesson?
Yes. Every Pandas & NumPy Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- DatetimeIndex and Period Ranges
- Resampling Time Series
- Shifting and Lag Features
- Extracting Temporal Features