RORK LABJP
BUILD — Rork Max runs real Macs in the cloud loaded with Xcode and the iOS SDK, writing SwiftUI, compiling, reading the errors and building again. That loop, not the code generation, is what lifts the outputNATIVE — What comes out is pure Swift and SwiftUI, not React Native. Reaching AR, Metal graphics and widgets that React Native cannot touch is the real gap between this and other buildersPLATFORMS — Coverage spans iPhone, iPad, Apple Watch, Apple TV and Vision Pro, plus iMessage. Worth a look if you want to start from a watch app or an extension rather than a phone screenCOMPANION — The Rork Companion app lets you check a generated build on a real iPhone without a paid Apple Developer account, lowering the bar for trying a first project end to endPRICING — Free to start, paid plans from $25 a month, and Rork Max on the $200 Max plan. Worth working out up front how many projects it takes to earn that backDEADLINE — From August 31, 2026, Google Play requires target API level 36 or higher for new apps and updates alike. Ten days out, and the targetSdkVersion of what you generate is yours to verifyBUILD — Rork Max runs real Macs in the cloud loaded with Xcode and the iOS SDK, writing SwiftUI, compiling, reading the errors and building again. That loop, not the code generation, is what lifts the outputNATIVE — What comes out is pure Swift and SwiftUI, not React Native. Reaching AR, Metal graphics and widgets that React Native cannot touch is the real gap between this and other buildersPLATFORMS — Coverage spans iPhone, iPad, Apple Watch, Apple TV and Vision Pro, plus iMessage. Worth a look if you want to start from a watch app or an extension rather than a phone screenCOMPANION — The Rork Companion app lets you check a generated build on a real iPhone without a paid Apple Developer account, lowering the bar for trying a first project end to endPRICING — Free to start, paid plans from $25 a month, and Rork Max on the $200 Max plan. Worth working out up front how many projects it takes to earn that backDEADLINE — From August 31, 2026, Google Play requires target API level 36 or higher for new apps and updates alike. Ten days out, and the targetSdkVersion of what you generate is yours to verify
Articles/Dev Tools
Dev Tools/2026-06-25Advanced

Why Your 9 AM Reminder Stops Arriving Abroad — Making Expo Local Notifications Survive Time Zones and DST

Daily reminders built with Rork (Expo) can drift to the wrong local time when users travel or DST flips. Here is the timeInterval trap, and a design that reschedules against local wall-clock time, with working code.

Rork539expo-notifications7Time ZonesLocal Notifications2React Native227DST

Premium Article

A user of one of my wallpaper apps once wrote in to say that the morning "image of the day" was arriving in the evening after they moved to Europe. It fired reliably at 9 AM in Japan, so my first guess was something server-side. The real cause sat much earlier in the stack: how the local notification trigger was built.

Running about six healing- and manifestation-style apps on my own, the bugs I dread most are the ones that never reproduce on my own device. A drifting daily reminder is the textbook example. This article separates out exactly why Expo local notifications drift across time zones and DST, and lays out a rescheduling design that keeps them anchored to local time, with code you can drop in.

Why "local 9 AM" stops arriving

The drift comes down to one distinction: does the trigger point at an absolute instant, or at a time on the device's local calendar? expo-notifications triggers fall into three families.

Trigger typeWhat it points atAcross travel / DST
timeInterval (n seconds)An absolute instant (fixed seconds from scheduling time)Drifts
date (a fixed Date)An absolute instant (one point in UTC)Drifts
daily / calendar (hour, minute)A time on the device's local calendarTracks correctly

The pattern that bites most is computing "seconds until the next 9 AM" and passing it to a timeInterval trigger. It looks right, but at scheduling time it is frozen into an absolute "fire N seconds from now." When the user moves nine hours east, that promised instant does not move. So it rings in the evening locally.

Passing a fixed Date drifts for the same reason. new Date(2026, 5, 26, 9, 0) is baked into one UTC instant using the device's current offset, so after a move it no longer lines up with the local clock.

I had shipped both. Because I wanted to vary the message per day, I had deliberately stacked one date at a time instead of using a calendar trigger. In exchange for per-day copy, I gave up time-zone resilience.

The basics: if you only need local time, use DAILY

If the same copy at the same local time every day is enough, the answer is simple. With SchedulableTriggerInputTypes.DAILY, the OS re-evaluates against the local calendar, so both travel and DST switches are absorbed for you.

import * as Notifications from 'expo-notifications';
 
export async function scheduleDailyReminder(hour: number, minute: number) {
  // Clear the existing daily slot first, then re-add (avoid duplicates)
  await Notifications.cancelAllScheduledNotificationsAsync();
 
  await Notifications.scheduleNotificationAsync({
    content: {
      title: 'Your image of the day is here',
      body: 'A quiet change of mood for your home screen.',
    },
    trigger: {
      type: Notifications.SchedulableTriggerInputTypes.DAILY,
      hour,   // interpreted in the device's local time
      minute,
    },
  });
}

On iOS this maps to a UNCalendarNotificationTrigger; on Android, to a repeating alarm. Both mean "local hour:minute," so a reminder set in Tokyo still rings at the local 9 AM nine hours away. Swapping timeInterval for DAILY is, in fact, the most common one-line fix.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Why timeInterval/Date triggers drift across time zones and DST, and how the DAILY calendar trigger tracks local time instead
A design that stores the intended local hour:minute and rebuilds the schedule on foreground when a time-zone change is detected
Safe next-fire computation that handles the spring-forward gap (a 2:30 that does not exist) while keeping a rolling window under the 64-notification cap
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
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 →

Related Articles

Dev Tools2026-06-22
Your Daily Reminder Stops Firing After a Couple of Weeks — iOS's Invisible 64-Notification Cap
When a daily reminder built with Rork (Expo) goes silent after a while, the cause is usually iOS's 64 pending-notification limit. Design a repeating calendar trigger for fixed messages and a rolling reschedule for daily-changing content, with working code that survives DST and multiple reminders.
Dev Tools2026-04-05
Rork × expo-notifications — Local Notifications That Fire When You Expect Them To
A complete guide to implementing local notifications in Rork using expo-notifications. Learn how to schedule one-time and repeating reminders with clear code examples.
Dev Tools2026-08-14
Find the native edits expo prebuild will erase before you upgrade to SDK 57
Expo SDK 57 makes expo prebuild clear and regenerate ios and android by default. Here is how to audit your hand edits first, move them into config plugins, and why 57.0.9 matters for Reanimated apps.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →