Articles · GuidesUpdated October 2026

Opening hours in an app are a weekly pattern plus the days that break it.

Store two things and most of this gets easy. A weekly pattern of opening and closing times, and a list of dated exceptions that override it. A holiday closure is an exception. Early closing is an exception with different times. Seasonal hours are a second pattern with a start date. All of it resolves against one more field that people leave out, the time zone identifier of the place the hours belong to, because a phone in another country will happily shift your Tuesday by its own offset.

What follows is the data model, the closure cases that look alike and are not, and the two days a year when a local time either does not exist or happens twice. The platform documentation is explicit about both, and the API names and wording below were read on 14 October 2026.

Start here

The short version

What does an app need to know about your hours?

Three fields and one rule. The weekly pattern says when you are normally open. The exception list says which dates are different and how. The time zone identifier says whose clock all of that is measured on. The rule is that the most specific record wins: a same-day override beats a dated exception, a dated exception beats a seasonal pattern, and the weekly pattern is only the fallback for a date nothing else mentions.

Keep all of it on the server, not in the app bundle. Hours that ship inside a build need a new release to change, and a release is a review plus a wait for customers to install it. Hours that come from an API change in the time it takes to tap save. That single decision is the difference between closing early on a Tuesday and explaining to people why the app said you were open.

What should you actually store?

Start with the weekly pattern: seven days, each with zero, one or two ranges. Two ranges because a kitchen that shuts between lunch and dinner is normal and a single open and close pair cannot express it. Store the times as wall-clock values, half past eight rather than a moment in time, and store a closing time past midnight as exactly that rather than as a smaller number than the opening time. A bar open until one in the morning is the oldest bug in this part of the codebase, and it shows up as a Friday that looks closed.

Then the time zone. Apple documents a time zone as a geopolitical region with an offset from Greenwich Mean Time and an abbreviation, and it is blunt about a trap worth reading twice: entries such as America/Los_Angeles are identifiers, not names, and many of its own functions use the word name when they mean identifier. Store the identifier. Never store the offset, which changes twice a year, and never store the abbreviation, which is a label rather than a key. Apple also distinguishes the time zone the system is using from an auto updating one that follows changes the user makes, which is the right default for formatting a customer-facing time on a phone that has just crossed a border.

Last, the exception list. One row per date, with a flag for closed and optional replacement times for a short day. Keep a free-text reason on the row, because the reason is the notice: shut for refurbishment reads differently from shut for a bank holiday, and customers behave differently in response. Keep bookable separate from open, since a day you are open without taking appointments is a real case and merging the two fields loses it.

One more field earns its place in a booking app: the last bookable start time per day, derived from the closing time minus the length of the service. Without it the app sells a one hour treatment that starts when you close. Multi-room businesses need this per resource rather than per shop, and that is where this stops being a list of hours and starts being a schedule. If you are building a class schedule app the classes carry their own times and the shop hours become a validation rule rather than the thing on display.

Apple, Foundation TimeZone reference, read 14 October 2026

How do you handle a holiday closure without a code change?

By entering a row, which is the whole point of the exception list. The part that goes wrong is not the storing, it is the timing. If customers can book sixty days ahead and you add the Christmas closure in November, the app has been selling those dates for a month. You are no longer closing a day, you are cancelling appointments. So the admin screen should do two things: refuse nothing, but warn loudly when the dates you are closing already have bookings in them, and list those bookings so somebody can ring the people in it.

Resist the urge to store annual holidays as a repeating rule. Easter moves, holidays that fall at a weekend get substituted to the Monday in some countries and not in others, and a rule that says the last Monday in May is correct until a government changes it for a jubilee. A dated row per year is twenty seconds of typing and it is right. The same goes the other way: a day that is a public holiday where your customer lives and a working day where you are is not your closure at all, and inferring one from a holiday library will shut you on days you intended to trade.

Two closures need special handling. The emergency one, boiler or burst pipe, needs a path from a phone to the server in under a minute and a notice that appears on every screen rather than only the booking one. And a long closure needs its edges handled: tell people when you reopen, not just that you are shut, because the reopening date is the question they have. A twenty four hour venue with staffed hours only part of the day has a third case, where closed means unstaffed rather than inaccessible, which is why a gym membership app usually keeps access hours and reception hours as two different patterns.

Pick the situation

What to store, what to show, when to publish it

Six closures that look alike and are not. Each one wants a different record.

What to store

One dated exception per year, not a repeating rule. Easter and the days that hang off it move, and a bank holiday can be substituted when it lands on a weekend. A rule that says the first Monday in May is right until the year it is not.

What the app shows

The date greyed out in the booking calendar with the reason next to it, so nobody taps it twice and then rings you.

When to publish it

Before the booking window reaches that date. See the trap below.

Every row above is one table and two fields. None of it needs a new app version.

What happens on the two days the clocks change?

Two things, one in each direction, and they are not symmetrical. On the day clocks go forward, an hour of local time does not exist at all. A slot inside it has no matching time, so any code that asks for half past two in the morning gets nothing back unless it has said what it wants instead. On the day clocks go back, an hour happens twice, so the same local time has two answers and something has to choose between them.

Apple does not hide this, and the names are useful even if you never write a line of Swift. Calendar.MatchingPolicy is documented as a hint that controls how the search for a date is performed, and it has four cases. One returns the next time that does exist. One, called nextTimePreservingSmallerComponents, returns the next existing value of the missing component while keeping the smaller ones, and Apple's own illustration is that a missing twenty seven minutes past two in the morning comes back as twenty seven minutes past three if that exists. A third does the same in reverse, taking the previous existing value. The fourth, strict, travels as far forward or backward as needed looking for a match. The policy is an argument you pass, not a default you inherit, which is the platform telling you that there is no right answer it can pick for you.

The repeat is handled by a separate type. Apple documents Calendar.RepeatedTimePolicy as deciding which result to use when a time is repeated on a day, and gives the daylight saving case directly: the times between two and three in the morning may happen twice. Its two cases return the first occurrence or the last. For opening hours this is mostly academic, because very few businesses open inside that hour. For a booking app it is not, because a slot generator that runs over the whole day will produce an hour of duplicate slots on the day clocks go back and lose an hour of them on the day they go forward, and neither is a crash. It is a quiet wrong answer.

Two practical defences. Generate bookable slots from the local pattern per date rather than by adding a fixed number of seconds to yesterday, since adding twenty four hours of seconds across a transition lands an hour out. And if you want to know the transition is coming, the platform will tell you: Apple exposes the date of the next daylight saving transition for a time zone, the transition after a given date, whether a zone is on daylight saving time at a date, and the offset that applies then. Those four are enough to put a one line warning in your own admin screen on the right weekend.

Apple, Calendar.MatchingPolicy reference, read 14 October 2026

Which record wins on a given date?

The recordWhat it coversOverrides the weekly patternChangeable without a release
Weekly patternAny date with no exception on itNoYes
Seasonal pattern with a start dateA run of weeksYesYes
Dated exception, closedOne date, or a first and last dateYesYes
Dated exception, short hoursOne dateYesYes
Same-day overrideToday only, until you clear itYesYes
Hours written into the appWhatever shipped in that buildNothing can override itNo

Read it bottom up. The last row is the version of this that forces you to ship a build every time a bank holiday arrives, and the first five are the version that does not.

Should the app or the server decide you are closed?

Both, for different reasons. The app decides what to show, because a phone with no signal still has to print your hours and should say when it last refreshed them rather than pretending to be current. The server decides what is allowed, because the phone showing an open Tuesday is not evidence that Tuesday is open. If the booking endpoint trusts the client, a customer with the app open since yesterday will book the day you have just closed, and the first you hear of it is when they arrive.

That means the same hours resolve twice, so resolve them with the same rule in both places and keep the rule in one file. The failure mode worth designing for is the ambiguous one: when the app cannot reach the server, it is better to show the cached hours with a timestamp and let the booking fail honestly than to hide the hours or to claim you are open. Closed is the safer default for taking money and the worse default for displaying information, and that is not a contradiction, it is two different screens.

Hours are also a monetisation question whether you meant them to be or not, since a last bookable slot and a cancellation window decide how much of the day you actually sell. If you are still choosing how the app earns, the wider decision sits in app monetisation. If you take payment for the booking inside the app rather than at the counter, which route the stores expect you to use is a separate question, and in-app purchases is the page for it. Showing opening hours and closure notices carries none of that weight on its own.

What changes if a builder generated the app?

The data model does not change, and that is the useful part. Ask for opening hours and you will get something that works for the happy path. The three things worth asking for by name are the ones that only bite later: the time zone identifier stored alongside the hours, closing times after midnight handled as such, and an exceptions table that an owner can edit without a developer. Say those out loud in the prompt and you get them. Leave them out and you get a seven row array with no exceptions and no zone, which is fine until the first bank holiday.

Newly is an AI app builder. You describe the app in plain English and it writes a real React Native and Expo project that you own, with two way GitHub sync so the code is never trapped inside the tool. It uploads iOS builds to TestFlight, publishes to Google Play internal testing and produces a standalone Android package. It does not submit to the App Store for you, because Apple requires the owner of the content to submit the app. It is $25 a month to use, and there is no free tier.

The honest limit is the admin side. An app that only displays hours can read them from a file in the project, and for a single shop that never changes its pattern that is enough. The moment somebody other than you needs to close next Thursday from their phone, you need a place to store it and a screen to edit it, which means a backend and an account. Ask for that in the same breath as the hours, rather than discovering it on the Thursday.

Questions people ask about opening hours in an app

As three separate things. A weekly pattern of opening and closing times, a list of dated exceptions that override it, and the time zone identifier of the place the hours belong to. Keep all three on the server so you can change them without shipping a new app version. Store the pattern as wall-clock times, nine in the morning rather than an instant, because nine in the morning stays nine in the morning after a clock change while a fixed instant does not.

Describe the shop, then describe the days it is shut

Write down your weekly pattern, the dates you close next year, and the city the clock belongs to. That page of notes is most of the build, and it is the part no tool can guess.

Start building