Data PreparationJuly 13, 20269 min readDataViz Pro Team

    Time Series Data Preparation: Timezones, Granularity, and Gaps

    time seriestimezonesaggregationdata preparationmissing data
    Time is the most common axis in data visualization and the most error-prone. A category label is either right or wrong. A timestamp can be off by hours, aggregated at the wrong granularity, or silently interpolated across a gap, and the resulting chart looks entirely plausible.
    The failures below are the ones that survive review, because none of them produce an obviously broken chart. They produce a chart that is wrong in a way nobody notices.

    Timestamps Are Not Dates

    A timestamp identifies an instant. A date identifies a day in some calendar, which corresponds to different instants in different places. Conflating them is the root of most time series bugs.
    The practical consequence: a value recorded at eleven at night in one timezone belongs to a different day in another. Aggregate by day without deciding whose day you mean, and you will quietly move events across boundaries. On a monthly chart this is invisible. On a daily chart it shifts the shape. On an hourly chart it can move a peak by half a day.
    Parsing behaviour makes this worse. A string with explicit offset information parses unambiguously. A string without it is interpreted according to the runtime's local timezone, which means the same file produces different charts on a developer's machine and on a user's. Date-only strings are the worst case, because different runtimes have historically disagreed about whether to treat them as local midnight or as coordinated universal time.

    The Timezone Decisions You Must Make Explicitly

    There are only three reasonable policies, and the important thing is choosing one deliberately rather than inheriting whatever the runtime does.
    Store and aggregate in coordinated universal time, and display in it too. This is unambiguous and reproducible, and it is right for machine-generated data such as server metrics. It is confusing for business reporting, because a daily total will not match what a regional team counted.
    Store in universal time but aggregate and display in a fixed business timezone. This is usually correct for reporting, because it matches how the organization thinks about a day. Document which timezone, and keep it fixed regardless of who is viewing.
    Store in universal time and display in the viewer's local timezone. This is friendliest for event timestamps and worst for aggregates, because two colleagues comparing the same dashboard will see different daily totals.
    Whichever you choose, state it in the chart. An axis labelled with a timezone is a small addition that eliminates a large class of misunderstanding. And expect daylight saving transitions to produce one day with twenty-three hours and one with twenty-five; if your aggregation assumes eighty-six thousand four hundred seconds per day, those two days will be wrong every year.

    Choosing a Granularity

    Granularity should follow the question, then the pixel budget, in that order.
    If the question is about seasonal patterns, monthly buckets are right and daily data is noise. If the question is about an incident, per-minute resolution matters and daily buckets destroy the answer. Choosing granularity before knowing the question is how you end up with a chart that technically contains the answer but does not show it.
    Once the question sets a floor, the pixel budget sets a ceiling. A chart eight hundred pixels wide cannot usefully display more than a few hundred distinct buckets. Two years of daily data is over seven hundred points, which is already past comfortable; aggregate to weekly and the trend becomes clearer, not less accurate.
    Where users need both, offer granularity as an explicit control rather than guessing. Make the current selection visible, because a chart labelled only with a date range is ambiguous about whether the points are days or weeks.

    Aggregation Functions Change the Story

    Summing, averaging, taking a maximum, and taking a percentile of the same data produce four different charts, all correct, answering four different questions.
    Sums are right for counts and amounts, where the total is meaningful. Averages are right for rates and durations, where a total is meaningless, but they hide spikes. Maximums are right for capacity and monitoring, where the worst case drives decisions, but they misrepresent typical behaviour. Percentiles are usually the honest choice for latency, where the mean is dominated by a long tail.
    There is also a composition trap: an average of averages is not the average, unless every bucket has the same count. Aggregating pre-aggregated data requires carrying the weights forward. If your source is already daily averages and you roll up to weekly, you need the daily counts too, or your weekly number is subtly wrong in a way that no chart will reveal.

    Gaps: Missing, Zero, and Not Yet

    Three situations look identical in most data formats and mean completely different things. The measurement was taken and the value was zero. The measurement was not taken. The period has not finished yet.
    Charting libraries default to whatever is convenient. A line chart will often connect straight across a gap, drawing a confident straight segment through a period where nothing was recorded. A missing value coerced to zero turns an unknown into an assertion that produces a dramatic dip, and that dip will be investigated as if it were real.
    The fix is to keep the three cases distinct through the whole pipeline. Preserve missing as missing rather than converting it during parsing. Break the line across gaps instead of interpolating, or shade the gap region so it reads as absence. Exclude missing periods from averages rather than counting them as zero, since a zero drags the mean down while a genuine absence should not affect it.

    Irregular Sampling and Alignment

    Real time series are rarely evenly spaced. Events arrive when they arrive. Sensors miss readings. Two series from different systems have different sampling intervals and different clock offsets.
    Plotting irregular data on a time axis works correctly only if the axis is genuinely temporal rather than categorical. A categorical axis places points at even intervals regardless of their timestamps, which compresses busy periods and stretches quiet ones, distorting every slope in the chart. This is one of the most common silent distortions in dashboards.
    To compare two series with different intervals, resample both onto a common grid before plotting. Choose the coarser of the two intervals, and be explicit about how you fill: carrying the last known value forward is appropriate for state-like measurements, while interpolation is appropriate for continuous physical quantities and wrong for counts.

    Cumulative Versus Periodic Values

    A running total and a per-period value tell very different stories from the same data. Cumulative series always rise, which makes them look like unbroken success even during a decline in the underlying rate. Periodic series show the actual dynamics.
    Both are legitimate, but they must be labelled unambiguously, and mixing them in one chart without saying so is genuinely misleading. If a source provides cumulative values and you want periodic ones, differencing consecutive values works, provided you handle counter resets, which appear as a large negative difference and should be dropped rather than plotted.

    Partial Periods at the Edges

    The final bucket in a time series is almost always incomplete. Today is not over. This month has eleven days in it. Plotted alongside complete periods, that partial bucket appears as a collapse.
    Every time series chart with a live edge needs to handle this. The options are to exclude the incomplete period, to mark it visually with a dashed line or lighter fill, or to annualize it with an explicit note. Doing nothing produces a chart where the most recent point, the one everyone looks at first, is the only wrong one.

    A Preparation Checklist

    Before charting any time series: confirm every timestamp parsed rather than silently becoming an invalid value; confirm the range matches expectations at both ends; state the timezone policy and apply it consistently; choose granularity from the question and check it against the pixel budget; name the aggregation function in the chart; verify that missing values are still missing; confirm the axis is temporal rather than categorical; and decide what happens to the incomplete final period.
    None of these take long. Each of them, skipped, produces a chart that looks right and is not.