{
  "slug": "time-series-resample",
  "name": "gizza-ai/time-series-resample",
  "version": "0.1.0",
  "title": "Time-Series Resample — Aggregate CSV to Hourly, Daily, Weekly or Monthly — gizza.ai",
  "description": "Resample timestamped CSVs to hourly, daily, weekly, monthly or yearly buckets with mean, sum, count, median, std or OHLC. Runs in your browser.",
  "tags": [
    "time series resample",
    "csv resample",
    "aggregate by hour",
    "daily to weekly csv",
    "time bucket",
    "ohlc resample",
    "downsample time series csv"
  ],
  "category": "time",
  "urls": {
    "page": "https://gizza.ai/tools/time-series-resample/",
    "markdown": "https://gizza.ai/tools/time-series-resample/index.md",
    "descriptor": "https://gizza.ai/tools/time-series-resample/tool.json",
    "deep_link_example": "https://gizza.ai/tools/time-series-resample/?data=time%2Ctemp%0A2024-05-01T10%3A00%3A00Z%2C10%0A2024-05-01T10%3A30%3A00Z%2C20%0A2024-05-01T11%3A15%3A00Z%2C30&interval=1h&aggregate=mean&time_column=blank%20%3D%20first%20column&value_columns=blank%20%3D%20every%20numeric%20column&label=start&closed=left&fill=skip&origin=epoch&offset=blank%20%3D%20no%20shift&time_format=iso&output=csv"
  },
  "cli": "gizza tool time-series-resample \"time,temp\n2024-05-01T10:00:00Z,10\n2024-05-01T10:30:00Z,20\n2024-05-01T11:15:00Z,30\"",
  "tool": {
    "description": "Resample a timestamped CSV/TSV series to a different interval — minute to hour, day to week, tick to OHLC candles. `interval` is a number plus a unit (15m, 1h, 1d, 1w, 1mo, 1q, 1y) and `aggregate` combines each bucket's rows (mean, sum, min, max, count, median, first, last, std, var, or ohlc, which expands each value column into open/high/low/close). Every numeric column is aggregated at once unless `value_columns` names some; `time_column` picks the timestamp column (ISO-8601, 'YYYY-MM-DD HH:MM', plain dates, or epoch numbers, in any row order). `fill` decides what happens to empty buckets (skip, empty, zero, previous, linear) — which also makes upsampling to a finer interval work. `label`/`closed` set which edge is printed and which side is inclusive, `origin` and `offset` move the bucket grid (e.g. offset '-5h' for a non-UTC day boundary), and `output` returns CSV or JSON. All timestamps are handled in UTC.",
    "parameters": {
      "additionalProperties": false,
      "properties": {
        "aggregate": {
          "default": "mean",
          "description": "How to combine the values inside each bucket: mean, sum, min, max, count (rows with a number), median, first/last (chronological), std/var (sample, n-1 denominator; blank for a single-value bucket), or ohlc, which expands every value column into <col>_open, <col>_high, <col>_low and <col>_close. Default mean.",
          "enum": [
            "mean",
            "sum",
            "min",
            "max",
            "count",
            "median",
            "first",
            "last",
            "std",
            "var",
            "ohlc"
          ],
          "type": "string"
        },
        "closed": {
          "default": "left",
          "description": "Which side of a bucket is inclusive. left = [start, end), the common convention, so a row landing exactly on an edge opens the new bucket; right = (start, end], so an exact-edge row closes the previous bucket. Default left.",
          "enum": [
            "left",
            "right"
          ],
          "type": "string"
        },
        "data": {
          "description": "The series to resample: CSV/TSV text with one timestamp column and one or more numeric value columns, e.g. 'time,temp\\n2024-05-01T10:00:00Z,10\\n2024-05-01T10:30:00Z,20'. The delimiter (comma, tab, semicolon, pipe) is auto-detected and reused in the output; a header row is optional; rows need not be sorted. Max 2,000,000 bytes and 200,000 rows.",
          "type": "string"
        },
        "fill": {
          "default": "skip",
          "description": "What to do with buckets that contain no rows: skip omits them entirely (the only mode that never invents rows), empty emits the bucket with blank values, zero emits 0, previous carries the last known value forward, linear interpolates between the surrounding values. Anything but skip also creates the intermediate buckets when `interval` is finer than the data. Default skip.",
          "enum": [
            "skip",
            "empty",
            "zero",
            "previous",
            "linear"
          ],
          "type": "string"
        },
        "interval": {
          "default": "1h",
          "description": "Bucket width as a number plus a unit: ms, s, m (minute), h, d, w, mo (month), q (quarter) or y (year) — e.g. 15m, 1h, 1d, 1w, 1mo, 1q, 1y. A bare unit means 1. A width FINER than the data upsamples: the empty buckets in between are created and then filled per `fill`. Default 1h.",
          "type": "string"
        },
        "label": {
          "default": "start",
          "description": "Which edge of the bucket to print in the timestamp column: start (the bucket's opening instant) or end (the next bucket's opening instant). Default start.",
          "enum": [
            "start",
            "end"
          ],
          "type": "string"
        },
        "offset": {
          "default": "",
          "description": "Shift every bucket edge by a fixed duration, e.g. '30m', '-5h', '-3d'. This is how you bucket by a local day instead of a UTC one (offset '-5h' gives days starting at 05:00 UTC = midnight UTC-5). Must be a fixed duration (ms, s, m, h, d, w) — calendar units are rejected. Blank = no shift.",
          "type": "string"
        },
        "origin": {
          "default": "epoch",
          "description": "Which instant the bucket grid is anchored to: epoch = the Unix epoch, so edges land on round clock times (weeks start Monday, months/quarters/years on the 1st); start = the first row's exact timestamp; start_day = UTC midnight of the first row's day. Only applies to fixed widths (ms/s/m/h/d/w) — month, quarter and year buckets always start on the 1st. Default epoch.",
          "enum": [
            "epoch",
            "start",
            "start_day"
          ],
          "type": "string"
        },
        "output": {
          "default": "csv",
          "description": "Result format: csv reuses the input's delimiter and header names, json returns a pretty-printed array of one object per bucket with null for blank values. Default csv.",
          "enum": [
            "csv",
            "json"
          ],
          "type": "string"
        },
        "time_column": {
          "default": "",
          "description": "Which column holds the timestamp: a header name, a case-insensitive header name, or a 1-based column number. Blank = the first column. Values may be ISO-8601/RFC-3339 (2024-05-01T13:20:00Z, with or without an offset), 'YYYY-MM-DD HH:MM', plain 'YYYY-MM-DD', or a bare epoch number (>= 1e11 is read as milliseconds, otherwise seconds).",
          "type": "string"
        },
        "time_format": {
          "default": "iso",
          "description": "How to print each bucket's timestamp: iso (2024-05-01T10:00:00Z), date (2024-05-01), datetime (2024-05-01 10:00:00), epoch_seconds, or epoch_millis. Default iso.",
          "enum": [
            "iso",
            "date",
            "datetime",
            "epoch_seconds",
            "epoch_millis"
          ],
          "type": "string"
        },
        "value_columns": {
          "default": "",
          "description": "Comma-separated list of the value columns to aggregate — header names or 1-based column numbers, e.g. 'temp,humidity' or '2,3'. Blank = every column other than the timestamp whose cells are all numeric or blank. Non-numeric columns are rejected with the offending line and cell.",
          "type": "string"
        }
      },
      "required": [
        "data"
      ],
      "type": "object"
    }
  }
}