◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SONNET 4.5 — Retires on the Claude API on 11/30, 23 days left. If your app calls it, check the migration target●SDK 58 — Moves to React Native 0.88. R8 is now on by default in Android release builds, and iOS prebuild generates a SceneDelegate●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SONNET 4.5 — Retires on the Claude API on 11/30, 23 days left. If your app calls it, check the migration target●SDK 58 — Moves to React Native 0.88. R8 is now on by default in Android release builds, and iOS prebuild generates a SceneDelegate●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/Getting Started
◈ Getting Started/2026-11-07Beginner

Your Diary App's Streak Stays on Yesterday Until 9 a.m. — The Date Key Was Built in UTC

Why a Rork-built diary or habit app files entries from midnight to 9 a.m. under the previous day in Japan, and how to fix the streak count. Checked on Node 22 at several clock times, with a prompt you can hand straight to the AI.

Rork613beginner23datesstreakstroubleshooting80time zones

You write your diary at 7 a.m., and the app labels it "yesterday's entry." Your streak drops from 12 to 1. I hear this kind of report from people who had an AI build a diary or habit tracker.

It works, and then it is wrong only some of the time. Staring at the screen won't find it. The cause is usually one line about how a date gets turned into text.

First, confirm what is happening

On a phone set to Japan time, the bad window is midnight to 9 a.m. In that window the app decides it is still "yesterday." After 9 a.m. it looks fine again, which is why testing at night never reproduces it.

The line behind it is a form AI tends to write:

// Builds a date key such as "2026-11-07". A commonly generated form
const dateKey = (d) => d.toISOString().slice(0, 10);

toISOString() returns the time converted to UTC, not your device's clock. Japan is nine hours ahead of UTC, so 8:59 a.m. in Japan is still 11:59 p.m. of the previous day in UTC.

Three ways to turn the same moment into a key

With the device time zone set to Japan, I ran this script on Node 22.

// dk.mjs — three ways to turn one instant into a date key
const pad = (n) => String(n).padStart(2, "0");
const keyUtc = (d) => d.toISOString().slice(0, 10);
const keyLocal = (d) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
const keyIntl = (d, tz) => new Intl.DateTimeFormat("sv-SE", { timeZone: tz }).format(d);
 
const samples = ["2026-11-07T00:20:00+09:00", "2026-11-07T08:59:00+09:00",
                 "2026-11-07T09:00:00+09:00", "2026-11-07T23:50:00+09:00"];
for (const s of samples) {
  const d = new Date(s);
  console.log(s.slice(11, 16), "utc:", keyUtc(d), "local:", keyLocal(d), "intl:", keyIntl(d, "Asia/Tokyo"));
}

TZ=Asia/Tokyo node dk.mjs printed:

00:20 utc: 2026-11-06 local: 2026-11-07 intl: 2026-11-07
08:59 utc: 2026-11-06 local: 2026-11-07 intl: 2026-11-07
09:00 utc: 2026-11-07 local: 2026-11-07 intl: 2026-11-07
23:50 utc: 2026-11-07 local: 2026-11-07 intl: 2026-11-07

At 00:20 and 08:59 only the utc column says November 6. It flips to November 7 at exactly 9:00, which matches the complaint.

The streak breaks because "yesterday" is built the same way

Fixing the key alone can still leave the streak wrong. That happens when the line that builds yesterday's key looks like this:

// Yesterday's key: subtracts 24 hours from a UTC-based key
const bad = (d) => keyUtc(new Date(d.getTime() - 86400000));
// Steps back one day on the device calendar instead
const yesterdayKey = (d) => { const y = new Date(d); y.setDate(y.getDate() - 1); return keyLocal(y); };

At 00:20 on November 7, yesterdayKey returned 2026-11-06 while bad returned 2026-11-05. The UTC key was already a day behind, and subtracting 24 hours moved it back a second day. The app then sees today's entry but an empty "yesterday," and the streak resets to 1.

Subtracting 24 hours can also land on the wrong day in regions with daylight saving time. Stepping back with setDate on the calendar avoids that worry.

The fix: decide the date key in exactly one place

There are only a few places to touch.

  • Keep a single function in the app that builds date keys.
  • Build it from the device calendar (getFullYear and friends), or from Intl.DateTimeFormat with the time zone stated explicitly.
  • Don't use toISOString().slice(0, 10) for date keys. It is a format for sending an instant to a server.

Which one you pick depends on one question: if a user travels abroad, whose midnight should the day roll over at? Use the device calendar if they should keep counting by their own daily life, or state Asia/Tokyo if it should stay fixed to Japan time.

Build date text in one function, after deciding the time zone. I put that line into the first prompt of any record-keeping app.

A prompt you can hand to the AI as is

For an app that already exists, this narrows the search:

Find every place that builds a date key (a YYYY-MM-DD string) and replace them
with one shared function, toDateKey.
toDateKey must use the device's local year, month and day, and must not use
toISOString().slice(0, 10).
Do "today" and "yesterday" checks only with that function and setDate(getDate() - 1).
After the change, write tests for 00:20, 08:59, 09:00 and 23:50 and confirm
the streak does not break.

Please keep the last sentence. Looking at the screen is a poor way to check what happens before 9 a.m.

What I checked, and what I didn't

The output above comes from Node 22.23 with the time zone switched between Japan and UTC. With UTC, the local column also read November 6 at 00:20, so the device-calendar form simply follows whatever the device is set to.

I did not test this on a real iPhone or Android phone together with a screen generated by Rork. If your app handles dates in several places, apply the prompt above and then try it once on your own device in the morning.

The same "edge of the record" issue shows up for month boundaries in three lines to add to a budget app's first prompt. For adding changes in small steps, see how to add features one prompt at a time.

As an indie developer, anything with a daily rollover is a spot you can't avoid. I'd start by searching your project for toISOString and seeing whether any hit is building a date key.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

◈ Getting Started2026-10-29
Three One-Line Additions to Your First Budget-App Prompt: Integer Yen, Local-Date Months, Normalized Input
Adding one line each about how money is stored, where a month begins, and how input is cleaned can prevent month-end totals from drifting in a household-budget app. Behavior checked on Node 22, with a small function you can reuse.
◈ Getting Started2026-08-17
Write .gitignore Before You Run git init on an Exported Rork Project
Running git init on a freshly exported Rork project puts your signing keys and .env straight into history. I measured what gets committed when the ignore file comes first versus last, and which exclusion patterns actually work.
◈ Getting Started2026-03-21
Rork App Won't Build? Eight Symptoms to Sort Out First
A troubleshooting FAQ that sorts Rork build failures by layer: dependency conflicts, unresolved Expo modules, simulator and emulator trouble, stalled generation, stale hot reload, and when Fix Now is safe to press.