Resample a CSV time series
Point this page at a date column and it rolls your rows up to days, weeks, months, quarters or years. Several value columns in one pass, seven aggregates to pick from, and a period with no rows is filled or named rather than quietly dropped. Your file is read and totalled inside this tab, and nothing is uploaded to a server.
Want a smoothed line rather than a coarser one? Add a moving average instead
Resampling is a group-by with three decisions in it
Rolling daily rows up to months sounds like one operation. It is really three, and most free resamplers only let you make one of them. You decide which period the rows fall into, you decide how the values inside a period get combined, and you decide what a period with no rows should look like. Get the third one wrong and your chart lies to you without ever showing an error.
- The period. Daily, weekly starting Monday, weekly starting Sunday, monthly, quarterly or yearly. Monthly is where the page starts because it is the most common ask. Daily is useful more often than you would expect, because a file with several rows per day becomes one row per day and suddenly plots cleanly.
- The aggregate. Seven of them: Sum, Average, Count rows, Minimum, Maximum, First in period and Last in period. Sum is the default. First and Last are the two that get left out of simpler tools and they are the two you need for anything measured as a level rather than a flow: an account balance, a subscriber count, a closing price. Summing a balance across a month produces a number with no meaning at all.
- The empty period. Fill with 0, fill with blank, carry the last value forward, or leave it out. This is the setting that decides whether a quiet week shows up as a dip or vanishes.
There is a fourth thing, which is not a decision so much as an absence of friction: you can roll up several value columns at the same time. Tick revenue, units and refunds, and the output carries revenue_sum, units_sum and refunds_sum side by side on one period axis. When a tool takes a single value column you end up running it three times and joining three files back together on a text period label, which is exactly the kind of manual step that introduces an off-by-one week nobody catches.
Worked example: five rows, four months, one hole
Here is orders.csv, deliberately tiny so every number below can be checked in your head:
date,revenue,units
2024-01-05,120,3
2024-01-19,80,2
2024-02-02,60,1
2024-04-11,150,4
2024-04-27,50,1
Leave the aggregate on Sum, set the period to Monthly, and leave empty periods on the default of Fill with 0. January holds two rows, so revenue is 120 plus 80 and units are 3 plus 2. February holds one. March holds nothing at all. April holds two, so 150 plus 50 and 4 plus 1. The download is:
period,revenue_sum,units_sum
2024-01,200,5
2024-02,60,1
2024-03,0,0
2024-04,200,5
That 2024-03 row is the whole argument. Nothing in the input mentions March. A tool that groups by month and returns the groups it found gives you three rows, your line chart joins February to April, and the flat month reads as a gentle slope. Here March is present, it holds a zero, and the summary strip says 1 empty period filled so you know the zero was written rather than measured.
Change nothing but the empty-period setting and the same file gives you three other answers. Fill with blank writes 2024-03,,, which is the honest choice when a missing month means you have no data rather than no activity. Carry the last value forward writes 2024-03,60,1, repeating February, which is what you want for a level such as active subscribers. Leave them out drops the row entirely, and the summary changes to 1 empty period not shown, so even the option that hides the gap still tells you there was one.
Switch the aggregate to Average and January becomes 100 and 2.5, February stays at 60 and 1, and April becomes 100 and 2.5. Switch it to Count rows and the numbers become 2, 1, 0 and 2 in both columns, because Count counts records in the period and pays no attention to what the value cells held. Switch to Last in period and January returns 80 and 2, the values from the 19th, because rows are read in file order and the last one to land in the bucket wins.
The summary strip above the preview reads, for the monthly Sum run: 4 month periods, 5 of 5 rows placed, 2024-01-01 to 2024-04-01, 1 empty period filled. Two of those deserve a second look. The rows-placed line is the one to check first, because it is how you notice that 40 of your 5,000 rows had a date the parser could not read. And the date range names periods rather than rows, which is why it starts at the first of January when your earliest order was on the fifth.
A week has no agreed first day, so you pick one
Every other period on the list is unambiguous. A month starts on the first, a quarter starts in January, April, July or October, a year starts in January. A week starts wherever your organization decided it starts, and the two common answers are Monday and Sunday. That is why there are two weekly options here rather than one.
The difference is not cosmetic. Take a single order dated 2024-01-05, a Friday. Under Weekly (Monday start) it lands in the week labelled 2024-01-01. Under Weekly (Sunday start) it lands in the week labelled 2023-12-31, which is in the previous calendar year. Every Saturday and Sunday in your file moves between buckets when you change this setting, so a weekend-heavy business can see its weekly peaks shift by a whole row. If your weekly numbers have never quite matched the ones finance quotes, this is the first thing to check.
Week labels are the ISO date of the day the week starts, not a week number. 2024-01-08 sorts correctly as text, means the same thing to everyone, and does not require anyone to remember which week-numbering convention was in play. Week 1 of 2024 is a genuinely contested phrase; the eighth of January is not. Monthly labels come out as 2024-03, quarters as 2024-Q1 and years as 2024, all of which sort in the right order in a spreadsheet without any extra work.
Dates that will not read are counted out loud
A resampler will happily produce a beautiful monthly chart from a file where a tenth of the dates failed to parse. Nothing about the output looks wrong. The numbers are just low, and evenly low, so nobody notices for a quarter. This page treats that as the main risk of the operation and reports it in three separate ways.
- Rows placed against rows read. The summary always shows both numbers. If they differ, some rows did not make it into any period, and the warnings below say why.
- Impossible dates are refused, not rolled over.
2024-02-30is not the first of March, and31/02/2024is not a date at all. The parser checks that the parts it read come back out unchanged, so these are reported by count with up to five of the offending values quoted back to you rather than silently absorbed into the next month. - A column with two formats gets a warning. If half the column is
2024-01-05and half is05/01/2024, both are read, but you are told how many patterns were found. That mix almost always means two systems wrote to the same file, and it is worth knowing before you trust the totals. - Blank dates and plain text are separated. A row with an empty date cell is counted as a row with no date. A row whose date cell says
pendingis counted as text. They are different problems and they get different sentences. - Values that are not numbers are named per column. If
refundsholds thirty cells readingn/a, you get a warning naming the column and the count, and those cells are left out of the sum rather than treated as zero.
On ambiguous slash dates, where both parts are 12 or less, the parser reads month first. 05/06/2024 becomes the fifth of June. If your export is day-first, convert the column before you resample it: the CSV validator will tell you which rows are ambiguous.
Gotchas worth knowing
- Everything is UTC. A date with no time zone has no time zone, and reading it as local midnight is what makes the same report shift by a day when it runs in Sydney instead of London. Timestamps with an offset are read for their date part only, since a period is a date range.
- Sum on a level is meaningless. Summing an account balance, a headcount or a stock reading across a month gives you a number with no interpretation. Use Last in period for a closing figure, First in period for an opening one, or Average for a typical level.
- Filling is capped at 100,000 periods. One row with a mistyped year turns a two-month file into a two-century daily axis. Rather than generate 73,000 rows of zeros, filling stops at the cap and the warning tells you to check the earliest and latest dates for a typo.
- Carry forward has nothing to carry at the start. If the very first period in the axis is empty, there is no previous value, so the cell is blank. Only the default Fill with 0 puts a number in every cell no matter what.
- Count needs no value column. Switch the aggregate to Count rows and untick everything, and the output is two columns,
periodandcount. Every other aggregate needs at least one column to work on and will say so. - Resampling is one way. Once daily rows are monthly totals, the days are gone. Keep the original file. If you need both, run the tool twice at two periods rather than resampling a resampled file.
Frequently Asked Questions
Which periods can I roll a file up to?
Six: daily, weekly with a Monday start, weekly with a Sunday start, monthly, quarterly and yearly. Monthly is the default. The two weekly options exist because a week is the one period with no agreed starting day, and a Monday-start report and a Sunday-start report of the same file put different totals in different rows. Picking the wrong one is the quiet way a weekly number stops matching the number your finance team quotes.
Can I summarize more than one value column at once?
Yes. Value columns is a multi-select, and every column you tick gets its own output column named after it with the aggregate appended, such as revenue_sum and units_sum. When the page first reads your file it ticks the first three numeric columns that are not the date column, which is enough to show the shape of the result without producing a wall of numbers. Running the tool once per column is busywork the tool should absorb, and each pass would give you a separate file you then have to join back together on the period.
What happens to a period that has no rows?
You choose, and the default is not to drop it. Fill with 0 writes a zero, which is right when the column counts events that did not happen. Fill with blank writes an empty cell, which is right when the value is unknown rather than zero. Carry the last value forward repeats the previous period, which suits a stock level or a headcount. Leave them out reproduces the behavior of a plain group-by, and the summary still tells you how many periods went missing so a straight line on your chart is never a surprise.
Does Count count rows or non-blank values?
Rows. Every row whose date landed in the period is counted, whether the value cell held a number, a blank or the word unknown. That is deliberate: Count answers how many records fell in the period, and a blank revenue cell is still a record. If you want the number of rows that actually carried a value, use Sum or Average instead and read the warning line, which names how many values in that column were not numbers and were left out.
Which date formats does the date column accept?
ISO dates such as 2024-03-17, ISO dates with a time attached, compact 20240317, slash dates with a two-digit or four-digit year, dot-separated European dates such as 17.03.2024, and month names in either order, so both March 17, 2024 and 17 March 2024. Impossible dates such as 2024-02-30 are rejected rather than rolled into March, and they are reported by count with a few examples quoted back to you. If one column carries more than one format, you get a warning naming how many it found.
Why does the date range in the summary not match my first row?
Because the range names the first and last period, not the first and last row. Roll a file that starts on 2024-01-05 up to months and the summary reads from 2024-01-01, because January is the period your earliest row landed in. The same thing happens at the top end: a file ending on 2024-04-27 shows 2024-04-01 for a monthly rollup. It is the axis the output uses, so it is the axis the summary reports.
Is my file uploaded anywhere?
No. There is no upload endpoint behind this page. The CSV is parsed, the dates are bucketed and the totals are written by JavaScript running in your own tab, and the download is assembled from memory in the same tab. Close the page and nothing of your file remains, which is also why reloading gives you an empty drop zone rather than your last result.
Related
Turn daily rows into a period you can read
Free, no account, no upload. Pick the period, pick the aggregate, and see the empty weeks for what they are.
Back to the resampler