How to Count Events by Minute with a Tumbling Window in Python

Group timestamps into fixed 60-second tumbling windows and count events per bucket using a dict.

Medium Python 3.9+ Aug 9, 2026 Data pipelines & processing 13 views 0 copies

Python code

27 lines
Python 3.9+
from collections import defaultdict
from datetime import datetime, timedelta


def tumbling_window_count(events, window_seconds=60):
    buckets = defaultdict(int)
    for event in events:
        ts = datetime.fromisoformat(event["timestamp"])
        bucket_start = ts - timedelta(seconds=ts.second % window_seconds,
                                        microseconds=ts.microsecond)
        bucket_key = bucket_start.replace(second=0, microsecond=0)
        if window_seconds > 60:
            bucket_key = bucket_start.replace(minute=bucket_start.minute - bucket_start.minute % (window_seconds // 60),
                                              second=0, microsecond=0)
        buckets[bucket_key.strftime("%Y-%m-%d %H:%M:%S")] += 1
    return dict(sorted(buckets.items()))


if __name__ == "__main__":
    events = [
        {"timestamp": "2025-01-01T10:00:00", "event": "click"},
        {"timestamp": "2025-01-01T10:00:30", "event": "click"},
        {"timestamp": "2025-01-01T10:01:45", "event": "view"},
        {"timestamp": "2025-01-01T10:02:10", "event": "click"},
        {"timestamp": "2025-01-01T10:02:55", "event": "view"},
    ]
    print(tumbling_window_count(events))

Output

stdout
{'2025-01-01 10:00:00': 2, '2025-01-01 10:01:00': 1, '2025-01-01 10:02:00': 2}

How it works

The function uses datetime.fromisoformat to parse each event's timestamp into a datetime object. It then calculates the bucket start by subtracting the seconds and microseconds past the window boundary. For the default 60-second window, replace(second=0, microsecond=0) snaps to the minute. The key is formatted as a string for easy readability and sorted for deterministic output. The defaultdict(int) automatically initializes counts to zero, simplifying the increment logic.

Common mistakes

  • Forgetting to reset microseconds when computing bucket start, causing off-by-one boundaries
  • Using `window_seconds` values that don't divide evenly into 60 for minute-based grouping
  • Not sorting the final dict, leading to non-deterministic output order

Variations

  1. Use pandas `resample('T').count()` for large datasets with a DataFrame
  2. Implement a pure numeric bucket key (epoch seconds // window) for faster comparisons

Real-world use cases

  • Aggregating web analytics events into per-minute traffic counts for dashboards.
  • Batching sensor readings into fixed time windows for downstream anomaly detection.
  • Grouping payment transactions by minute to monitor fraud spikes in real time.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Data pipelines & processing

Related tutorials and quizzes for this topic.