
The One-Hour Bug
On Sunday night, March 8th 2026, every streak on Candle temporarily broke. This post covers how it happened, why it fixed itself, and the two bonus bugs we found hiding in the same code.
Intro
On Sunday, March 8th, 2026, at approximately 12:12 AM PST, I opened Candle to check on my answers for the past day (I was at the beach with my girlfriend and wanted to see the selfies) and noticed that my streak, which was at 360 days… said 0.
I refreshed. Still 0. I checked the database. The streak was right there, 360, sitting in the database perfectly intact. But the app said 0.
Within minutes, the emails started coming in. Over 30 of them in under an hour. Shoutout to our international couples using Candle! While most of our US users were asleep, couples across the world where it was the middle of the day were watching their streaks vanish in real time. And they were not happy about it.
"My streak is gone." "It says zero." "We haven't missed a single day."
I immediately started digging into the code. And what I found was one of the most annoying (but hilarious) bugs I've ever encountered.

Streaks on Candle
For context, Candle has a streak feature. Both you and your partner answer at least one question (or do any activity - a game, drawing, date idea, etc.) together every day, and you build a streak together. Some of our couples take this very seriously. We're talking 200, 300+ day streaks. These matter to people.
The way our streak logic works is simple: we store the date of your last streak activity. When you open the app, we check: is that date today, or yesterday? If yes, your streak is alive. If not, it's broken. This is mainly for performance reasons.
To figure out "yesterday," our code did something that probably looks familiar to anyone who's written date logic in JavaScript:
const yesterday = getDateString(new Date(Date.now() - 86400000));Take the current time, subtract 86,400,000 milliseconds. That's 24 hours.
Except on March 8th, 2026, a day was not 24 hours.
The clocks jumped
Daylight Saving Time spring-forward happened at 2:00 AM PST on March 8th. Clocks jumped to 3:00 AM PDT. That means March 8th was only 23 hours long.
So at 12:12 AM on March 9th, when our code subtracted 24 hours to find "yesterday," it didn't land on March 8th. It overshot by one hour and landed on March 7th, which was two days ago.
Our streak logic saw that the last activity was on March 8th, compared it to "yesterday" (which it thought was March 7th), and concluded: streak broken.
To be clear: no data was corrupted. The streak was completely fine in the database. But the logic that calculated how long your streak was for display on the mobile app was incorrect. This also (incorrectly) caused the “streak restore” button to pop up, and users freaked out.

The one-hour window
Here's the part that makes this bug a fun one.
It only happens for exactly one hour. From midnight to 1:00 AM.
At midnight, subtracting 24 hours from the current time lands on 11:00 PM on March 7th. Wrong. At 12:30, it lands on 11:30 PM March 7th. Still wrong. At 12:59, it lands on 11:59 PM March 7th. Still wrong.
At 1:00 AM? It lands on 12:00 AM March 8th. Correct.
After 1:00 AM, the 24-hour subtraction happens to land on the right date again, and everything goes back to normal. The bug fixes itself.
A one-hour window. Twice a year. That fixes itself before you can investigate it. If none of our international users had been awake and emailing us, we might not have noticed until November of this year.
The fix (and two bonus bugs)
The fix is conceptually straightforward: stop using timestamp arithmetic to answer calendar questions. "Yesterday" is a calendar concept. A day is not always 86,400,000 milliseconds. Instead of subtracting hours from a timestamp, we now get today's date in the correct timezone first, then subtract one calendar day:
function getDateStringDaysAgo(daysAgo) {
const today = getDateString(); // timezone-aware, always correct
const [month, day, year] = today.split("/").map(Number);
return formatDate(new Date(year, month - 1, day - daysAgo));
}The system already knows about DST; we just weren't letting it do its job.
While auditing the codebase, we found the same 24-hour subtraction pattern in 11 different places. Every single one was a potential DST bug waiting to happen.
We also found two bonus bugs hiding in the same code:
A function that checks if two dates are consecutive was comparing the hour difference between them using a rounding method that works fine for spring-forward (23 hours between midnight and midnight rounds correctly) but would break during fall-back in November, when consecutive days are 25 hours apart. Unlike the display bug from March, this one could have permanently broken streaks. We'd just never hit November with this code yet.
A function called getCurrentWeekStartPST had a comment in the code that said: "PST offset could be -7 or -8 depending on DST." The very next line was this:
const pstOffset = -8; // hoursThis comment literally describes the bug. This caused the weekly streak calendar to show a full week of progress on Monday mornings during PDT months, because the function thought it was still Sunday night. I probably wrote this at midnight and told myself I'd come back to it.
Lessons learned
A few things we're taking away from this:
A day is not always 24 hours. Every engineer "knows" this. But it's the kind of thing that lives in the back of your head until you're writing a quick date comparison and you reach for the easy constant. It works 363 days a year. That's a 99.5% success rate… just enough to never fail in testing.
DST bugs are invisible for 364 days a year. They appear for a tiny window, affect a subset of users, and fix themselves before you can debug them. The only reason we caught this one quickly was because of our international users who happened to be awake.
Comments that describe a bug are not the same as fixing it. We've all written "TODO: handle this edge case" and moved on. Sometimes that edge case comes back for you at midnight on a Sunday.
If this bug affected you and you saw your streak at 0, we're sorry. It was always there. We just couldn't see it for an hour.
Thank you for being a Candle user.
P.S. We’re taking summer engineering and design interns for Candle! If you’re interested, please email us with your portfolio and something cool you’ve built at parth[at] and alex[at] trycandle.app!