0Pricing
Pandas & NumPy Academy · Lesson

DatetimeIndex and Period Ranges

Create a DatetimeIndex with pd.date_range, parse string dates, and set a time column as the index for time-based access.

DatetimeIndex and Period Ranges is a free Pandas & NumPy Academy lesson on CoddyKit — lesson 1 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 Pandas Has Special Time Tools

Time series data requires more than just storing dates as strings. You need to sort by time, select date ranges, resample to different frequencies, and extract components like month and weekday. Pandas addresses this with the DatetimeIndex — an index made of datetime64 values — which unlocks specialised time-aware operations not available on ordinary integer or string indices.

Creating a DatetimeIndex with pd.date_range()

pd.date_range(start, end, freq) generates a sequence of evenly-spaced dates. The freq parameter specifies the interval using offset aliases: 'D' for day, 'h' for hour, 'ME' for month end, 'W' for week, 'YE' for year end. You can pass either end or periods (number of timestamps) — not both.

import pandas as pd

# Daily dates for January 2024
dates = pd.date_range(start='2024-01-01', end='2024-01-07', freq='D')
print(dates)
# DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03',
#                '2024-01-04', '2024-01-05', '2024-01-06', '2024-01-07'],
#               dtype='datetime64[ns]', freq='D')

# 12 month-end dates
months = pd.date_range(start='2024-01-31', periods=12, freq='ME')
print(months[:3])

Setting a DatetimeIndex on a DataFrame

To enable time-based operations, set your date column as the DataFrame's index using set_index() after converting it to datetime64 with pd.to_datetime(). Once the index is a DatetimeIndex, you can use partial string indexing (df['2024-01']), date-range slicing, and all time-aware methods.

df = pd.DataFrame({
    'date':  ['2024-01-01', '2024-01-02', '2024-01-03'],
    'value': [10, 15, 12]
})

df['date'] = pd.to_datetime(df['date'])
df = df.set_index('date')
print(df)
#             value
# date
# 2024-01-01     10
# 2024-01-02     15
# 2024-01-03     12
print(type(df.index))  # DatetimeIndex

Partial String Indexing

One of the most convenient features of a DatetimeIndex is partial string indexing. You can select rows by year, month, or date by passing a partial date string to .loc[]. For example, df.loc['2024-01'] returns all rows from January 2024, and df.loc['2024'] returns all rows from 2024. No need to compare column values explicitly.

# Create a larger date-indexed Series
s = pd.Series(
    range(365),
    index=pd.date_range('2024-01-01', periods=365, freq='D')
)

# Select all of January 2024
print(s.loc['2024-01'].shape)  # (31,)

# Select a specific date range
print(s.loc['2024-03-01':'2024-03-07'])

pd.to_datetime() for Parsing

pd.to_datetime() converts strings, integers (Unix timestamps), or mixed-format date columns into datetime64. Pass format to specify the exact pattern if dates are in a non-standard format (e.g., '%d/%m/%Y'). Use errors='coerce' to convert unparseable values to NaT (Not a Time) instead of raising an error.

# Parse standard ISO format
print(pd.to_datetime('2024-06-15'))

# Parse non-standard format
print(pd.to_datetime('15/06/2024', format='%d/%m/%Y'))

# Handle mixed/bad data gracefully
mixed = pd.to_datetime(['2024-01-01', 'bad_date', '2024-06-15'],
                       errors='coerce')
print(mixed)  # NaT for 'bad_date'

The .dt Accessor for Datetime Components

When a DataFrame column (not the index) contains datetime64 values, the .dt accessor exposes all datetime properties and methods on that column vectorially. Use it to extract .dt.year, .dt.month, .dt.day, .dt.day_of_week, .dt.hour, etc. without loops. If the datetime is the index, use df.index.year directly.

df_col = pd.DataFrame({'date': pd.date_range('2024-01-01', periods=5, freq='D'),
                       'value': [10, 15, 12, 18, 14]})

df_col['year']  = df_col['date'].dt.year
df_col['month'] = df_col['date'].dt.month
df_col['dow']   = df_col['date'].dt.day_of_week  # 0=Monday
df_col['week']  = df_col['date'].dt.isocalendar().week
print(df_col.head())

Period Ranges with pd.period_range()

A PeriodIndex represents intervals of time rather than specific timestamps. pd.period_range(start, periods, freq) creates monthly, quarterly, or yearly periods. A period like Period('2024-01', 'M') represents the entire month of January 2024, not just its start date. PeriodIndex is useful for fiscal reporting where you think in terms of quarters or months.

# Monthly periods
periods = pd.period_range('2024-01', periods=6, freq='M')
print(periods)
# PeriodIndex(['2024-01', '2024-02', '2024-03',
#              '2024-04', '2024-05', '2024-06'],
#             dtype='period[M]')

# Quarterly periods
quarters = pd.period_range('2024Q1', periods=4, freq='Q')
print(quarters)  # [2024Q1, 2024Q2, 2024Q3, 2024Q4]

Converting Between Timestamp and Period

You can convert a DatetimeIndex to a PeriodIndex with to_period(freq) and back with to_timestamp(). Converting to periods is useful when you want to label rows by month or quarter rather than by a specific day, which makes grouping and aggregation more intuitive for calendar-based analysis.

daily_idx = pd.date_range('2024-01-15', periods=5, freq='D')
print('DatetimeIndex:', daily_idx[:3])

# Convert to monthly periods
monthly_idx = daily_idx.to_period('M')
print('PeriodIndex:', monthly_idx[:3])
# PeriodIndex(['2024-01', '2024-01', ...], dtype='period[M]')

# Convert back to timestamps (start of period)
print(monthly_idx.to_timestamp()[:3])

Time Zone Handling

Real-world time series often come with timezone information. Pandas supports timezone-aware DatetimeIndex through tz_localize() (attach a timezone to naive timestamps) and tz_convert() (convert between timezones). Always work in UTC internally and convert to local time only for display, to avoid daylight-saving ambiguity bugs.

naive = pd.date_range('2024-01-01', periods=3, freq='D')
print('Naive:', naive.tz)

# Attach timezone (localize)
utc = naive.tz_localize('UTC')
print('UTC:', utc)

# Convert to New York time
ny = utc.tz_convert('America/New_York')
print('NY:', ny[:2])

Checking and Sorting the DatetimeIndex

Time series operations like resampling and slicing require the DatetimeIndex to be sorted (monotonically increasing). Check with df.index.is_monotonic_increasing and sort with df.sort_index() if needed. An unsorted DatetimeIndex can cause silent errors or unexpected results in resampling and window functions.

import numpy as np

df_unsorted = pd.DataFrame(
    {'value': [10, 15, 12]},
    index=pd.to_datetime(['2024-01-03', '2024-01-01', '2024-01-02'])
)
print('Sorted:', df_unsorted.index.is_monotonic_increasing)  # False

df_sorted = df_unsorted.sort_index()
print('After sort:', df_sorted.index.is_monotonic_increasing)  # True
print(df_sorted)

Practical Pattern: Building a Time Series DataFrame

Here is a complete pattern for building a time-indexed DataFrame from raw data: parse dates, set the index, sort, and verify the index frequency. This setup is the foundation for all time series analysis in subsequent lessons — resampling, rolling averages, and lag features all rely on a clean, sorted DatetimeIndex.

import numpy as np

# Simulate loading raw data
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=30, freq='D')
df_ts = pd.DataFrame({'sales': np.random.randint(100, 500, 30)}, index=dates)

df_ts.index.name = 'date'
print('Shape:', df_ts.shape)
print('Freq:', df_ts.index.freq)
print('Sorted:', df_ts.index.is_monotonic_increasing)
print(df_ts.head())

Quick Check

Test your understanding of DatetimeIndex and period ranges from this lesson.

Lesson Recap

In this lesson you learned: how to create a DatetimeIndex with pd.date_range() and parse dates with pd.to_datetime(), how to use partial string indexing for intuitive date selection, the difference between Timestamp and Period types, and how to handle time zones. Next up we explore resampling to change the frequency of a time series.

Frequently asked questions

Is the “DatetimeIndex and Period Ranges” lesson free?

Yes — the full text of “DatetimeIndex and Period Ranges” 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 “DatetimeIndex and Period Ranges”?

Create a DatetimeIndex with pd.date_range, parse string dates, and set a time column as the index for time-based access. 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 1 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “DatetimeIndex and Period Ranges” 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

  1. DatetimeIndex and Period Ranges
  2. Resampling Time Series
  3. Shifting and Lag Features
  4. Extracting Temporal Features
← Back to Pandas & NumPy Academy