Articles
Pandas Time-Series Interview Questions: Resampling, Time Zones, and Missing Intervals
Prepare for Pandas time-series interview questions with tested resampling examples, DST boundaries, time zones, missing intervals, and validation checks.
Pandas time-series interview questions are about the meaning of time before they are about syntax. Preserve the instant, choose the reporting time zone, define the resampling bins, and decide what missing observations mean. A neat hourly table can still be wrong if it merges two daylight-saving hours or turns a telemetry outage into zero activity.
For data analysts and data scientists, a strong answer produces both the requested metric and evidence that its time contract survived the transformation.
The examples are original practice, executed locally with pandas 3.0.5 and NumPy 2.5.3. Official documentation checked September 21, 2026 identifies its current version as 3.0.6. The code's results are local observations, not a claim that every older pandas release behaves identically.
What should you clarify before resampling?
Ask what one row represents. A purchase amount is a flow that can be summed across transactions. An account balance is a state observation; summing repeated balances generally answers the wrong question. A temperature reading may call for a mean, but an irregularly sampled mean is not automatically a time-weighted mean.
Next define the output grain: one entity per hour, one market per local day, or one global UTC interval. Specify the reporting horizon independently of the observed minimum and maximum timestamps. Otherwise an entity with no recent records disappears just when the missing period matters most.
Finally, separate three choices: which timestamps enter a bin, how the bin is labeled, and when its aggregate becomes available. A bin labeled 10:00 can contain observations through 10:59:59. That label does not mean its final total was known at 10:00.
Write these decisions before choosing resample, asfreq, or a rolling window. The official resample API exposes closed, label, origin, and offset because grouping and labeling are separate operations, not cosmetic output settings. pandas resample reference
What is the difference between tz_localize and tz_convert?
tz_localize assigns a time zone to a naive wall-clock timestamp. It answers, “Which place's clock produced this value?” tz_convert changes the display zone of an already aware timestamp while preserving the instant. Localizing a New York wall time as UTC is not a shortcut for conversion; it changes the interpretation.
If the input includes UTC offsets, parse it with pd.to_datetime(..., utc=True) and retain an aware UTC column. If the input is naive local time, first establish its source zone, localize with an explicit ambiguity policy, and only then convert to UTC. Do not assume the machine's local zone describes the data.
During New York's November 2, 2025 fallback, 01:30 -04:00 and 01:30 -05:00 are one hour apart: 05:30 and 06:30 UTC. Removing the offsets before grouping collapses distinct instants into the same wall-clock label. The correct display can legitimately contain two rows that both say 01:00, distinguished by their offsets.
pandas exposes separate controls for ambiguous fall-back times and nonexistent spring-forward times. Raising an error is often a useful interview default: it surfaces missing information instead of silently choosing an instant. An inference policy needs an ordered sequence with enough evidence; it cannot recover facts absent from a single ambiguous timestamp. pandas tz_localize reference
Worked example: repeated hours, zero values, and missing intervals
Suppose one sensor reports interval amounts in arbitrary units. We need six elapsed hourly bins from 04:00 through 10:00 UTC, with the end excluded, on November 2, 2025. We display those bins in New York time. This is an elapsed-hour report, not a claim that every local calendar day contains 24 hours.
There are four observations: 10 units at 04:10 UTC, zero at 05:10, a row with a missing value at 06:10, and 30 units at 08:10. No row arrives during the 07:00 UTC hour, and the requested 09:00 UTC hour is also empty. The distinction between an absent row and a present row with no usable value must survive.
import pandas as pd
frame = pd.DataFrame({
"ts": ["2025-11-02T04:10:00Z", "2025-11-02T05:10:00Z",
"2025-11-02T06:10:00Z", "2025-11-02T08:10:00Z"],
"value": [10.0, 0.0, float("nan"), 30.0],
})
frame["ts"] = pd.to_datetime(frame["ts"], utc=True)
s = frame.set_index("ts")["value"].sort_index()
bins = s.resample("1h", closed="left", label="left",
origin="epoch")
grid = pd.date_range("2025-11-02T04:00:00Z",
"2025-11-02T10:00:00Z",
freq="1h", inclusive="left")
out = pd.DataFrame({
"total": bins.sum(min_count=1),
"rows": bins.size(),
"valid": bins.count(),
}).reindex(grid)
out[["rows", "valid"]] = out[["rows", "valid"]].fillna(0).astype("int64")
out["state"] = "observed"
out.loc[out["valid"].eq(0), "state"] = "unknown value"
out.loc[out["rows"].eq(0), "state"] = "missing interval"
out.index = out.index.tz_convert("America/New_York")
print(out)
The essential output is:
| Local hour | Total | Rows / valid | State |
|---|---|---|---|
| 00:00 -04:00 | 10 | 1 / 1 | Observed |
| 01:00 -04:00 | 0 | 1 / 1 | Observed |
| 01:00 -05:00 | NaN | 1 / 0 | Unknown value |
| 02:00 -05:00 | NaN | 0 / 0 | Missing interval |
| 03:00 -05:00 | 30 | 1 / 1 | Observed |
| 04:00 -05:00 | NaN | 0 / 0 | Missing interval |
The observed zero remains zero. The missing value remains unknown. The absent intervals appear because the grid comes from the reporting contract rather than only the observed timestamps. Filling the count columns with zero is appropriate: zero rows were observed. Filling the amount column would make an additional, unsupported claim.
min_count=1 requires a valid value before returning a sum. Without a deliberate missingness policy, an empty or all-missing bucket can look like a meaningful zero. The sum API documents this parameter; the local fixture verifies the three-way distinction above. pandas Resampler.sum
How do closed, label, and origin change the answer?
With closed="left", an event exactly at 06:00 UTC belongs to the bin starting at 06:00, not the one ending there. label="left" names that bin using its start. Changing the label alone does not change which observations are grouped; changing the closed edge can.
origin="epoch" anchors our fixed hourly grid consistently across slices. With a less convenient frequency such as 17 minutes, choosing the first observed timestamp as the origin can make independently processed chunks disagree about bin boundaries. Establish one origin and offset for the whole job instead of deriving them separately per file.
Calendar aggregation needs its own contract. If the requested output is revenue by New York calendar day, convert to that zone before daily resampling. Grouping by UTC date and converting the resulting labels afterward does not recover local-day membership. Around daylight-saving transitions, local days can have different elapsed durations. pandas time-series guide
Do not overgeneralize this fixture to monthly or quarterly offsets. Fixed-duration bins and calendar boundaries serve different purposes. For rates, report the denominator explicitly: events per observed hour differs from events per local business day, especially when coverage is incomplete.
When should you use asfreq instead of resample?
Use asfreq when the operation is frequency alignment rather than aggregation. It reindexes to a frequency; it does not add together every event between adjacent output timestamps. The pandas documentation explicitly points to resampling when aggregation is required. pandas asfreq reference
In our irregular fixture, reindexing raw events directly onto hourly boundaries would miss observations at ten minutes past the hour. Those timestamps are not equal to the boundary labels. Resampling groups them first, and reindexing the aggregated result then supplies the full required horizon.
Upsampling introduces timestamps, not new measurements. Forward-filling a balance may be reasonable if the last observation remains valid, but forward-filling a purchase amount repeats the purchase. Backward-filling or interpolation can use future observations and therefore leak information in a prediction-time feature pipeline.
If carrying a state forward is appropriate, add a maximum age and an imputation indicator. A row-count limit is meaningful only with a known grid spacing; otherwise specify an elapsed-time freshness rule. Explain what happens before the first observation and after an extended outage instead of letting a fill operation make that decision accidentally.
How do you preserve entity boundaries and handle duplicates?
For multiple sensors or customers, resample within each entity. If you set a global timestamp index and immediately sum, you may produce a plausible overall total while destroying the requested per-entity result. Verify uniqueness of the final (entity_id, bucket_start) key.
A complete panel may require an entity inventory crossed with the reporting grid. Grouping only entities present in the event file cannot create a row for a sensor that emitted nothing at all. Build that panel only for active entity intervals; filling months before a sensor existed is another kind of invented missingness.
Duplicate timestamps are not necessarily duplicate events. Two purchases can legitimately occur at the same instant. Deduplicate by the prompt's event identity and correction rule before aggregation, not by timestamp alone. If versions are supplied, make the winning-version order deterministic and retain the cutoff used to select it.
This tutorial focuses on temporal semantics. The broader Pandas interview guide for data analysts covers joins and general cleaning. When a join adds metadata here, validate its cardinality so a duplicate sensor lookup cannot multiply the hourly totals.
Which assertions demonstrate that the result is correct?
Check both values and structure. The fixture should return six bins, four observed rows, three valid values, and an observed total of 40 units. The time-zone-aware index must be unique even though two formatted hour labels begin with 01:00. Converting it back to UTC should recover the original reporting grid.
assert len(out) == 6
assert out["rows"].sum() == 4
assert out["valid"].sum() == 3
assert out["total"].sum() == 40
assert out.index.is_unique
assert out.index.tz_convert("UTC").equals(grid)
assert out.iloc[1]["total"] == 0
assert out.iloc[2]["state"] == "unknown value"
assert out.iloc[3]["state"] == "missing interval"
Then test an event exactly on a bin boundary, an empty input with a declared horizon, and a naive timestamp inside a DST transition. In New York, March 9, 2025 at 02:30 is nonexistent; November 2 at 01:30 is ambiguous without an offset or disambiguating information. A policy that raises is a successful validation outcome, not necessarily a bug to suppress.
Also test an all-missing bin, two legitimate same-time events, and a completely absent entity. A conservation check on the grand total alone cannot catch every error: merging two DST bins can preserve the total while corrupting the hourly pattern. Pair numeric checks with key, index, coverage, and boundary assertions.
Practice time semantics before memorizing method names
The final two are SQL-oriented temporal practice, useful for translating the same contract across tools rather than implying they require pandas.
| Practice question | Practice focus |
|---|---|
| Manipulate time-series with Pandas groupby | Time grouping |
| Transform messy transactions with pandas | Zone parsing |
| Transform retail data with pandas groupby/merge/concat | Entity grain |
| Compute a Seven-Day Rolling Average | Missing dates |
| Write rolling-window SQL over weekly cohorts | Window units |
Begin with the time-series groupby exercise and explain each output row before checking the solution. The strongest answer is not “I used resample.” It is “I preserved distinct instants, defined the bins, retained unknown coverage, and tested the boundaries that could silently change the result.”