Create a timezone-aware hourly activity report
In this article (6 sections)
Normalize timestamped events to aware instants, aggregate on a clearly defined time axis and convert labels to the reporting timezone. Preserve the UTC offset when local clock hours repeat during a daylight-saving transition.
A local label such as 01:00 may identify two different hourly intervals. Grouping only by that label can merge distinct periods and conceal the transition.
Demonstrate two different 01:00 hours
The following synthetic events occur one hour apart during the November 2026 clock change in America/New_York. The pandas quality lab records the pandas and timezone-data versions used for execution.
import pandas as pd
instants = pd.to_datetime(['2026-11-01T05:30:00Z', '2026-11-01T06:30:00Z'], utc=True)
events = pd.Series([1, 1], index=instants, name='events')
hourly = events.resample('h').sum()
local = hourly.tz_convert('America/New_York')
labels = local.index.strftime('%Y-%m-%d %H:%M %z').tolist()
assert labels == ['2026-11-01 01:00 -0400', '2026-11-01 01:00 -0500']
assert len(local) == 2 and int(local.sum()) == 2
assert local.index.strftime('%Y-%m-%d %H:00').nunique() == 1
assert (local.index[1] - local.index[0]) == pd.Timedelta('1h')
print(list(zip(labels, local.tolist())))The offset-aware labels retain two periods. Removing the offsets produces one repeated wall-clock label, which is unsuitable as a unique grouping key for this question.
Count the hours in the local reporting day
import pandas as pd
fall = pd.date_range('2026-11-01', '2026-11-02', freq='h',
tz='America/New_York', inclusive='left')
spring = pd.date_range('2026-03-08', '2026-03-09', freq='h',
tz='America/New_York', inclusive='left')
assert len(fall) == 25
assert len(spring) == 23
assert fall.is_unique and spring.is_unique
print({'fall_day_hours': len(fall), 'spring_day_hours': len(spring)})These are actual hourly instants spanning the two local dates under the installed timezone rules. Assuming every local day contains twenty-four hourly bins would misstate coverage for these dates.
The pandas time-series guide covers timezone handling. The tz_localize reference describes ambiguous and nonexistent local times.
Localize and convert for different purposes
Localization assigns timezone meaning to an unzoned wall-clock value. Conversion changes the displayed timezone of an already identified instant. Do not localize a timestamp to UTC merely because the source omitted its zone; first obtain the source contract.
For ambiguous local input during the repeated hour, require an offset, a sequence rule or other evidence that identifies the intended occurrence. For nonexistent local times during the spring transition, define whether to reject or apply an approved adjustment.
The executed examples start from explicit UTC instants, so they avoid that input ambiguity rather than claiming to solve every ambiguous source.
Make the reporting interval explicit
This workflow uses elapsed UTC-hour bins displayed in local time. If the business instead defines opening-hour slots or custom local intervals, construct that calendar explicitly and map events to it.
Keep the interval's start instant as the stable key and the local label as presentation. Include timezone and offset in exported data so another tool does not collapse repeated labels.
Separate empty bins from missing coverage
A zero event count is trustworthy only when ingestion coverage for that interval is complete. Build a coverage calendar for the intended window and retain incomplete intervals as unknown, just as with daily reporting.
Exercise: add a third event to the second repeated hour. Verify that the first hour remains one event and the second becomes two, then show how grouping by offset-free text incorrectly combines them into three.
NeuraPath's Data Analytics with Generative AI course connects pandas time handling with accurate operational reporting. A useful hourly chart preserves real intervals even when local clock labels repeat or skip.
Continue learning
This article is part of the Pandas wrangling and data checks sequence. Use the neighbouring tasks when you need the prerequisite or the next application.
- Review the prerequisite or neighbouring task in Pandas Copy-on-Write: avoid ambiguous chained assignment.
- Continue with Profile null patterns across customer segments.
Pankit Kumar has 10 years in Data Science & AI, building and shipping production systems in regulated pharma and clinical environments. He is a freelance trainer at Boston Institute of Analytics, AnalytixLabs and Scaler, and has taught this material to thousands of working professionals.
This article is part of our Data Analytics with Generative AI programme — 3–4 months. The full analyst stack — Excel, SQL, Power BI and Python pipelines — then a generative-AI layer you can prove is right.
Explore Data Analytics with Generative AI