The dates are not wrong. Stripe is stamping the moment the transaction happened in UTC, while your bank CSV is stamping the day cash posted in local time. When a payment lands near midnight, those become different calendar days. When Stripe also batches several transactions into one payout, the row-by-row comparison fails even faster.
That is why you can see a Stripe charge on May 31, a bank line on June 1, and still be looking at the same movement of money. The mismatch is usually not missing cash. It is a mix of timezone conversion, payout timing, and the fact that Stripe charge rows are not the same thing as bank statement rows.
The first check is what kind of date mismatch you actually have
Before you change formats in Excel, identify which case you have. The same-looking mismatch can come from several different causes, and only some of them are pure UTC problems.
| What you see on screen | How Stripe stores it | How the other file stores it | What the result actually means |
|---|---|---|---|
2026-05-31 23:47:18 UTC in Stripe and 2026-06-01 in the bank CSV | Charge created late in the UTC day | Local bank posting lands after midnight in the account timezone | Same event can appear one day later after timezone conversion |
2026-05-01 00:12:44 UTC in Stripe and 2026-04-30 in the bank CSV | Charge created just after midnight UTC | Local timezone west of UTC still shows the previous evening | Same event can appear one day earlier after conversion |
2026-05-15 in a Stripe payout export and 2026-05-17 in the bank CSV | Funds became available or payout was created on one date | Bank posted the deposit two business days later | This is payout timing, not a timezone error |
01/05/2026 in the bank CSV and 2026-05-01 09:14:02 UTC in Stripe | ISO-style timestamp with time | Text date with ambiguous day and month order | You cannot compare until the bank date is normalized |
| Twelve Stripe rows for sales, refunds, and fees versus one bank row for the net deposit | Charge-level activity | Deposit-level cash event | This is the wrong comparison level, even if the dates were identical |
Only the first two rows are true timezone shifts. The third is settlement timing. The fourth is a text-date import problem. The fifth is the one that wastes the most time because it looks like a date issue when it is really a file-structure issue.
Which Stripe date are you actually looking at
Stripe exports do not use one universal "transaction date." They expose several dates that describe different moments in the payout lifecycle. If you compare the wrong one to the bank statement, you create a mismatch before the spreadsheet does anything wrong.
| Stripe field | What it represents | What you should use it for |
|---|---|---|
created | When the balance transaction was created in Stripe | Matching transaction history, not final bank posting |
charge_created | When the original charge happened | Matching sales or order records, not bank deposits |
available_on | When the net funds become available in the Stripe balance | Explaining settlement timing inside Stripe |
automatic_payout_effective_at | When Stripe expects the payout to arrive in the bank | Matching a payout export to a bank deposit |
| Bank receipt date | When the bank says the cash actually posted | Final cash reconciliation |
This is the part many posts skip. A bank statement line is a cash event. A Stripe charge export is a transaction event. A payout reconciliation export sits between them. If you export a Stripe transactions CSV, take the created column, and compare it directly to the bank statement date, you are comparing the time the charge entered Stripe to the day cash reached the bank. Those are different events even before you account for UTC.
That is why the clean order is:
- Match the bank deposit to the Stripe payout.
- Match the payout contents to the underlying Stripe transactions.
- Match those transactions to orders, invoices, or ledger lines if you need transaction-level proof.
If you skip the middle layer, the timezone problem looks bigger than it is.
Convert the Stripe timestamp before you compare anything
Once you know you are looking at the correct Stripe-side date field, convert it into the same date logic as the bank file. Do not start with formatting. First find out whether Excel imported the value as a real date-time or as text.
Use =TYPE(A2) on the Stripe date cell.
1means Excel sees a numeric date-time serial.2means Excel sees text and you need to parse it before any comparison will work.
If the Stripe value in A2 is text in a pattern like 2026-05-01 23:47:18 UTC, build the UTC date-time explicitly:
=DATE(LEFT(A2,4),MID(A2,6,2),MID(A2,9,2))+TIME(MID(A2,12,2),MID(A2,15,2),MID(A2,18,2))That gives you the UTC timestamp as an Excel date-time value. Then convert it to local time by applying the account offset. If your accounting view is UTC-4, subtract four hours:
=DATE(LEFT(A2,4),MID(A2,6,2),MID(A2,9,2))+TIME(MID(A2,12,2),MID(A2,15,2),MID(A2,18,2))-TIME(4,0,0)If your local reporting timezone is UTC+2, add two hours instead:
=DATE(LEFT(A2,4),MID(A2,6,2),MID(A2,9,2))+TIME(MID(A2,12,2),MID(A2,15,2),MID(A2,18,2))+TIME(2,0,0)Once the local timestamp is correct, strip it down to the calendar date if the bank CSV only gives you a date:
=INT(B2)Format that result as a date. Now you are comparing the local day implied by the Stripe timestamp, not the raw UTC day.
If the Stripe date is already a real Excel date-time in A2, do not parse it again. Apply the offset directly:
=A2-TIME(4,0,0)The bank file needs the same level of care. If the bank CSV imported 01/05/2026 as text, you need to decide whether the source means day-month-year or month-day-year before you convert it.
If the bank uses dd/mm/yyyy:
=DATE(RIGHT(C2,4),MID(C2,4,2),LEFT(C2,2))If the bank uses mm/dd/yyyy:
=DATE(RIGHT(C2,4),LEFT(C2,2),MID(C2,4,2))Do not reach for DATEVALUE until you know which format the bank exported. A value like 01/05/2026 is not diagnostic by itself. It could be January 5 or May 1 depending on the source system and your Excel locale.
One warning matters more than most spreadsheet guides admit: a fixed -TIME(4,0,0) or -TIME(5,0,0) offset is only safe if the date range stays inside one daylight-saving period. If the export crosses the DST change, one offset can fix half the file and break the other half. In that case, split the file by period or use a Stripe report that already exposes the account-timezone column and keep the _utc version only for audit reference.
Match the payout to the bank before you touch individual charges
Once the timestamps are normalized, the next decision is matching level. If the bank CSV contains a single net deposit and the Stripe file contains individual charges, refunds, and fees, you still do not have a row-by-row match. You have a one-to-many relationship.
The bank line should be matched to a Stripe payout report first. Then the transactions inside that payout explain the amount.
| Step | File you use | What you are proving |
|---|---|---|
| 1 | Bank statement CSV | What amount hit the bank, on what posting date |
| 2 | Stripe payout or payout reconciliation export | Which payout produced that deposit |
| 3 | Itemized rows inside that payout | Which charges, refunds, disputes, and fees make up the net amount |
| 4 | Orders, invoices, or ledger export | Whether the underlying activity is recorded correctly elsewhere |
Suppose your bank CSV shows this line:
| Date | Description | Amount |
|---|---|---|
| 2026-06-01 | STRIPE PAYOUT | 4,820.25 |
Your Stripe charge export might show thirty-seven rows created across 2026-05-31 21:00:00 UTC through 2026-06-01 03:00:00 UTC. If you compare those charge dates directly to the June 1 bank line, you will conclude that many rows are "off by one day." Some are. But the more important truth is that none of those rows are supposed to match the bank line individually. They belong to a payout batch.
The right proof looks like this:
- The Stripe payout export shows a net payout of
4,820.25. - The payout field that represents expected bank arrival aligns with the bank posting window.
- The itemized transactions inside that payout add up to the same net amount after fees, refunds, and disputes.
At that point, the date issue shrinks to its real size. It is a normalization step, not the entire reconciliation.
If you need the payout side laid out in more depth, matching a Stripe payout CSV to your bank statement and matching a bank statement to Stripe payouts when dates differ cover the deposit workflow from the other direction.
The edge cases that still create false mismatches after conversion
Getting Stripe into local time solves the first layer. It does not solve every layer. Several cases still create apparent date breaks even after the timezone math is correct.
Month-end filtering
This one catches competent teams because the spreadsheet looks clean. You export the bank CSV for May. Then you export Stripe for May in UTC. Late-evening local transactions from May 31 can appear as June 1 in Stripe, which means they fall outside the Stripe filter even though they belong in your local May close. Pull a one-day buffer on both sides of the Stripe period, convert to local date, then filter the converted date column back to the month you are closing.
Weekend and holiday posting
A payout can be effective on Friday and still reach the bank on Monday. That is not a broken date field. It is bank processing. If the payout amount and reference pattern line up, treat the date gap as settlement timing unless the cash is still missing after the normal banking window.
Refunds and disputes arriving later
The original charge might sit in one payout, while the refund or dispute hits a later one. When someone tries to reconcile the bank against charge creation dates alone, those later reductions look like unexplained mismatches. They are not unexplained. They belong to a later payout batch and need to be traced there.
Mixed timezone columns
Some Stripe exports can show both local-time and _utc versions of the same field. If you build formulas against one column this month and the other column next month, the workbook will produce inconsistencies that look like source-data errors. Choose one standard and stick to it for the entire reconciliation.
Copy-paste damage
If someone pastes Stripe rows into a sheet instead of importing the CSV, Excel can silently strip the timezone context, convert timestamps to local display values, or store them as text. When the formula starts failing only after paste, the source file may be fine and the worksheet copy is what changed.
When the spreadsheet work becomes the real problem
This mismatch is manageable when you are tracing one payout. It becomes expensive when every month requires the same cleanup: parse the Stripe timestamp, convert it to local time, buffer the period, split payout dates from charge dates, then explain why one deposit contains dozens of underlying rows.
The standard you need is not "every Stripe date equals the bank date." The standard is that every bank deposit is tied to the right Stripe payout, every payout is explained by the transactions inside it, and every remaining date gap is classified as either timezone conversion, payout timing, or a real exception that needs correction.
