Skip to content

HomeHelp › Golden-hour and sunset scheduling

Golden-hour and sunset scheduling

When a session type is set to golden hour, ShootCal figures out the sunset (or sunrise) time for your location on the chosen day and builds your shoot times around it. For a sunset type, the prime slot is the one that ends right at sunset, so you are shooting into the best light and finishing as the sun goes down. For a sunrise type, the prime slot starts at sunrise instead.

If you book more than one shoot in a day, ShootCal cascades extra slots away from the sun: sunset types step backward into the afternoon, sunrise types step forward into the morning, each one separated by your break time. As it builds those fallback slots it looks at what is already on your calendar that day and routes around it, so it never offers a time that collides with an existing event.

You do not have to think about any of this. You set the location once, pick whether a type is sunset or sunrise, set the shoot length and break, and the app, the website, and the public booking page all compute the same times the same way. Sun times are estimates good to roughly the minute, and the anchor snaps to the nearest 5 minutes (a 7:18 sunset becomes a 7:20 anchor), because for scheduling that is close enough.

Where sunrise and sunset come from

ShootCal works out sunrise and sunset itself, right on your device, with no internet lookup. It uses a well-known astronomy formula from your location and the date, so it's accurate and works offline. The app, the website, and your booking page all run the same calculation, so they never disagree on a time.

Far north or south, where the sun may not actually rise or set on a given day, ShootCal falls back to solar noon instead of failing. And there is one careful detail: the calculation is anchored to local noon rather than midnight, which fixed an old bug that once stamped US sun times a day early.

For the curious: the underlying formula is a port of Mourner's SunCalc, computing the sun's position from latitude, longitude, and date and solving for the standard sunrise/sunset altitude (the one that accounts for the solar disc and atmospheric refraction). It is implemented identically on the native app, the backend, and the web so all three land on the same time.

How a day's slots are built

The prime slot is pinned to the sun: a sunset shoot ends right at sunset, a sunrise shoot starts right at sunrise. If you book more than one shoot in a day, ShootCal steps the next slots away from the sun (sunset types into the afternoon, sunrise types into the morning), each one separated by your break time, and routes around whatever's already on your calendar. So a 7:15 PM event just makes the next slot end at 6:45 PM instead of leaving an awkward gap. It builds up to six candidate slots in this order, prime first, and offers the first one that's actually free.

Only that first, sun-pinned slot wears the "Golden hour" tag, and only when it really landed on the sun event. If a calendar conflict pushed even the first slot off the sun, it is correctly not tagged as prime.

The five session-type modes

A session type's scheduling mode selects how slots are generated:

  • Sunset, golden hour ending at sunset, cascade backward.
  • Sunrise, golden hour starting at sunrise, cascade forward.
  • Studio hours, tile your open-to-close hours, each session one session-length long with a turnover gap between, in chronological order. Ignores the sun. (The built-in "Photo Studio" is 30-minute sessions, 15-minute turnover, 9 AM to 5 PM.)
  • Fixed time, a single slot at one clock time (defaults to 1 PM), ignores the sun. The built-in "Real Estate Photography" uses this for even midday interior light.
  • All-day, returns no slots (for example a Wedding).

These modes work identically in the native app, the web app, and the public booking page, so a session type offers the same slots everywhere.

Per-day capacity (how many slots get offered)

Sun types stack multiple sessions per day, but the booking page only publishes as many open slots as the type's per-day cap allows, minus what is already booked.

For a sunset or sunrise type, ShootCal resolves your per-day limit (default 1, clamped between 1 and 50), counts that day's already-accepted bookings of the same type, and works out how many remain. It then offers slots until that remaining count hits zero, skipping any slot that is already booked and any slot before the lead-time cutoff. So with the default limit of one, only the prime golden-hour slot is published. Raise it and the next cascade slots open up.

The per-day limit is resolved in order: the type's own explicit value if it carries one, then your studio default, then a built-in default. If you don't set a per-day limit on a session type, it uses your Studio Default (or 1).

Studio and fixed types behave differently: they publish ALL their slots, including booked ones (clearly flagged) so clients can see what is taken. There is also a studio "Fill" mode: unless a studio type has an explicit per-day limit, its limit is effectively unlimited and it fills every available slot.

The submit path re-checks the same limit as a 'day full' gate and re-checks slot overlap, so the picker and the actual booking can never disagree about a day's capacity.

Where the data lives

  • Session-type library (native): stored on-device as your encoded list of session types. Decoding is tolerant: missing fields derive from legacy ones so an old library still loads, and an unreadable or missing store reads as empty rather than resurrecting the built-in defaults.
  • Sun-relevant per-type settings: the scheduling mode and sun mode, the session length, and the break (for sun types); open hours, close hours, and turnover (for studio); the fixed start time (for fixed). The per-day limit can be left unset, which means inherit.
  • Location: your latitude and longitude come from your app settings. On the backend they are read from your saved settings and passed into the slot planner. If there is no location, sun types return zero slots.
  • Booking-page state: your global booking config (public token, which calendar, lead time, how far ahead bookings open, which weekdays, your per-day limit, and so on). Studio defaults and session types both live in your saved settings, which sync across your devices. Accepted bookings are what the day-count consults for capacity.
  • Timezone: the backend places minute-of-day values and the day's noon in your calendar's timezone, so anchors land on the right local day.

FAQ

Does ShootCal call a weather or sunrise API, or is the sun time computed locally?

It is computed locally, with no network call. All three surfaces (native, backend, and web) run the same SunCalc-derived astronomical formula from latitude, longitude, and the date. It uses a sun altitude of -0.833 degrees, the standard value that accounts for the solar disc and refraction.

For a sunset type, does the shoot start at sunset or end at sunset?

It ends at sunset. The cascade packs backward from the sunset anchor with the prime slot's END pinned to sunset. A sunrise type is the mirror: the prime slot's START is pinned to sunrise and slots cascade forward (later).

How does the cascade avoid double-booking against events already on my calendar?

Before emitting each slot it checks the proposed interval against the day's busy intervals. On a conflict it does not just skip a fixed grid step; it jumps the cursor to one break before the conflicting event's start (sunset) or one break after its end (sunrise), so the next slot butts right up against the existing event instead of leaving a gap. Your busy intervals are sorted by start and the earliest overlap is used.

Why is my sunset slot at 7:20 when the actual sunset is 7:18?

The anchor snaps to the nearest 5 minutes. On native the sun instant is rounded to the nearest minute first and then snapped to 5; on the backend and web the raw sun instant is snapped straight to 5. Either way exact-second precision is not needed for scheduling, so a 7:18 sunset yields a 7:20 anchor.

How many golden-hour slots will a single day offer?

The cascade can generate up to six candidate slots, but the public booking page only publishes as many as your per-day limit allows minus what is already booked. The default limit is one, so by default only the prime golden-hour slot is offered. Raising the limit opens the next backward (or forward) cascade slots.

Why did sun times used to be off by a day, and is that fixed?

An early version could show US sun times a day off; that was fixed long ago.

What happens at extreme latitudes where the sun may not rise or set?

The math can have no valid solution for that day (no sunrise or sunset). In that case all three implementations fall back to solar noon (the transit) rather than failing. Also, if no location is configured at all, sun-anchored types simply return no slots.

Do studio and fixed types use any of the sun math?

No. Studio-hours types tile fixed clock hours (open to close, session length plus turnover) and fixed-time types are a single fixed clock start (default 1 PM). Both ignore latitude, longitude, and the sun entirely. Only sun-anchored types (sunset or sunrise) run the sun calculation.

How do the app and the website stay in agreement on slot times?

The slot logic is deliberately ported three times with matching constants and structure across the native app, the backend, and the web. The backend re-applies the same limit and overlap checks the picker used, so the offered slot and the booking commit can never disagree about availability or capacity.

What is the studio 'Fill' behavior versus a sun type's per-day cap?

For a studio type with no explicit per-day limit, the limit becomes effectively unlimited, so every open studio slot can be booked. Sun types instead resolve a concrete per-day limit (default 1, max 50) and publish only that many open slots after subtracting the day's accepted bookings. ← Back to Help Center

ShootCal — scheduling, clients, and galleries for photographers.