apointoo.
Booking Platforms

Why Does Google Calendar events.list Return an Appointment That Starts Before timeMin?

cmsapointoo··8 min read

Google Calendar can return an event that starts before timeMin because events.list uses overlap boundaries. The API defines timeMin as an exclusive lower bound on an event’s end time. It defines timeMax as an exclusive upper bound on an event’s start time.

Those definitions do not mean “event start must fall inside the window.” They mean an event can qualify when it overlaps the window. A 9:30 to 10:30 appointment can appear in a request bounded from 10:00 to 11:00 because its end is after 10:00 and its start is before 11:00.

What do timeMin and timeMax actually filter?

The events.list reference describes timeMin as the exclusive lower bound for an event’s end time. An event must end after that instant to qualify. An event that ends exactly at timeMin does not pass that boundary.

The same reference describes timeMax as the exclusive upper bound for an event’s start time. An event must start before that instant. An event that starts exactly at timeMax does not pass.

With both parameters present, the practical overlap test is event.end > timeMin and event.start < timeMax. That expression follows directly from Google’s two parameter definitions. It includes events crossing either inner edge while excluding events that only touch the outside boundary.

This behavior is separate from a Google Calendar FreeBusy error. FreeBusy reports occupancy intervals and can return per-calendar errors. events.list returns event resources under its own filtering contract.

Why does an event starting before timeMin still appear?

Consider a request from 10:00 to 11:00. An appointment starts at 9:30 and ends at 10:30. Its end is later than timeMin, and its start is earlier than timeMax. It overlaps the first half hour of the requested window, so the API includes it.

Now consider an appointment from 9:00 to 10:00. Its end equals the exclusive timeMin boundary. It does not occupy any time after 10:00, so it is excluded. An appointment starting at exactly 11:00 is also excluded because its start equals the exclusive timeMax boundary.

An event that starts at 10:30 and ends at 11:30 qualifies. Its start is before 11:00, even though its end falls outside the requested window. The API is finding events that intersect the interval, not events fully contained by it.

Operational inference: keep this overlap test in one shared calendar adapter and test both boundary-equality cases. Refiltering results by start time in a later service can erase valid conflicts that began before the visible booking window.

Does every returned event block appointment availability?

No such conclusion follows from events.list alone. The method returns event resources that match the request. Whether a result blocks a clinic slot depends on the application’s approved rules for event status, transparency, ownership, event type, calendar coverage, and scheduling policy.

Operational inference: separate retrieval from occupancy classification. First collect every event that overlaps the window under Google’s boundaries. Then apply a documented rule that decides which events block availability. Keep rejected events visible in diagnostic counts without copying their descriptions or attendee details into general logs.

A returned event also does not prove that every relevant calendar was queried. The article on secondary Google calendars in Jane shows how calendar coverage can be narrower than staff expect. Confirm calendar scope before declaring a provider free.

If the integration uses FreeBusy for occupancy, fail closed on per-calendar errors rather than converting an indeterminate response into open capacity. If it uses event resources, document the event fields that inform the block decision. Do not mix the two contracts in one success flag.

How do time zones affect the overlap window?

Google requires RFC3339 timestamps with a mandatory time zone offset for both parameters. The examples in the reference include an explicit numeric offset and UTC with Z. Milliseconds may be supplied, but Google says they are ignored.

The comparison concerns instants, not the clock labels shown to staff. A window expressed in one offset can overlap an event represented in another offset after both are normalized. Building bounds from a clinic’s local wall time without the intended offset can query a different interval.

Operational inference: derive the booking window in the clinic or provider time zone, convert it to RFC3339 with an explicit offset, and retain that zone context for display. Test daylight-saving transitions for every zone the product supports. Avoid using a server’s default zone as an unstated scheduling rule.

The optional timeZone parameter controls the time zone used in the response. If it is omitted, Google uses the calendar’s time zone. That response choice does not change the need to send valid, explicit offsets in timeMin and timeMax.

What changes when recurring events are involved?

The singleEvents parameter determines whether recurring series are expanded into instances. Its default is false. When true, the response contains one-off events and expanded instances rather than the underlying recurring event records.

Operational inference: a booking conflict check that needs occupied occurrences should choose its recurrence strategy explicitly. Do not assume that the default response has already expanded every appointment occurrence that intersects the requested period.

Use synthetic recurring events to test an occurrence that begins before timeMin, an exception moved into the window, and a cancelled instance. Verify the exact response shape under the chosen singleEvents and deletion settings before relying on it for capacity.

Can time bounds be reused with incremental synchronization?

No. The events.list reference says a request using syncToken cannot also specify timeMin, timeMax, updatedMin, iCalUID, orderBy, q, or the listed extended-property filters. Other parameters should remain the same as the initial synchronization.

A windowed query and an incremental mirror serve different jobs. The first asks which events overlap a period under the supplied bounds. The second asks which resources changed after a stored synchronization state. Combining their parameters is not a supported shortcut.

If a sync token expires, Google returns HTTP 410 and instructs the client to clear its synchronized store and run a full sync without that token. Recovering from Google Calendar 410 Gone covers that state transition in detail.

Operational inference: maintain one coherent calendar mirror with its sync cursor, then run overlap checks against that mirror or issue a separate bounded query. Do not silently fall back from a failed sync request to an empty result, because an empty result can be misread as open availability.

How should an overlap reconciliation test be designed?

Create synthetic events around a fixed window. Include one event wholly before it, one ending exactly at timeMin, one crossing timeMin, one inside the window, one crossing timeMax, one starting exactly at timeMax, and one wholly after it.

The expected included set contains the three events with positive overlap: the one crossing the lower bound, the one inside, and the one crossing the upper bound. Equality at either exclusive outer boundary does not qualify. Run the same cases with explicit offsets that represent the same instants.

Operational inference: record only synthetic calendar aliases, event fingerprints, normalized timestamps, request parameters, and inclusion results. Avoid patient names, attendee addresses, descriptions, or clinical notes. A conflict detector should not need those fields to prove interval behavior.

If the workflow later updates a reconciled event, protect newer edits with the conditional-write pattern described in Google Calendar ETag and If-Match handling. Correct overlap retrieval does not prevent a stale worker from overwriting a later change.

Frequently asked questions

Is timeMin a lower bound on event start time?

No. Google defines timeMin as the exclusive lower bound on an event’s end time. Events that begin earlier can still appear when they end after the boundary.

Is timeMax an upper bound on event end time?

No. Google defines timeMax as the exclusive upper bound on an event’s start time. An event can end later and still qualify when it starts before that boundary.

Does an event ending exactly at timeMin appear?

No. The bound is exclusive. An event whose end equals timeMin does not pass the documented lower-bound condition.

Can timeMin and timeMax be sent with syncToken?

No. Google lists both time parameters among those that cannot be combined with syncToken in an incremental synchronization request.

References

Related articles