
The booking that happened on the wrong day
A customer books the 11:00 PM slot on Monday. The operator opens the record and sees Tuesday. Nobody typed the wrong thing and no automation misfired. Two people are reading one stored value through two different display settings, and the record never said which instant the customer meant. Airtable's help centre documents this exact case: two date fields in the same base, one with "use the same time zone for all collaborators" turned on and one without, will show the same moment as 4:00 PM and 5:00 PM.
The display setting is doing the schema's job
Airtable stores dates in Greenwich Mean Time and converts them on the way out. A collaborator in Sydney and one in Paris see different clock times for the same record unless you turn on the override, and that override lives in each field's configuration menu. Per field. Whether a booking reads correctly depends on whether the person who added the column remembered to flip a toggle, and nothing in the base will tell you later that they forgot.
The API inherits the ambiguity. Ask for records with cellFormat=string and Airtable requires timeZone and userLocale as query parameters, then adds in the same document that you should not rely on the format of those strings because it is subject to change. The text your integration parses is a function of two parameters the caller happened to pick, against a shape the vendor reserves the right to alter. I have written that parser. It holds up until someone edits a view.
This is not carelessness on Airtable's part. It is a spreadsheet that grew into a database, and a spreadsheet's job really is to show you a value in your own locale. A bookings table has a different job, which is to record one moment in a way that survives being read from somewhere else.
Changing a time zone by way of a string
Airtable's documented way to pin a date to a fixed zone is to format it into text and parse it back out: DATETIME_PARSE(DATETIME_FORMAT(SET_TIMEZONE(Date, 'America/Los_Angeles'), 'M/D/Y h:mm A'), 'M/D/YYYY h:mm A'). SET_TIMEZONE has to sit inside DATETIME_FORMAT or the result misbehaves, which the help centre states twice on one page. The round trip exists because DATETIME_FORMAT hands back a string and date arithmetic needs a date.
The simpler alternative in that same article is the more dangerous one. It offers DATEADD with a hardcoded hour offset and lists New York at -4, Chicago at -5 and London at +1. Those are summer values. Run the formula in January and every converted time sits an hour off. Airtable's own FAQ names the matching trap from the other direction: America/Atikokan is a fixed UTC-5 zone that never adjusts, so a field set to it falls an hour behind Eastern Time from roughly March to November.
Each of those formulas is a correct answer. The problem is the question. You are computing a time zone at display time because the stored value never carried one, and a formula field has no test suite, so the January bug ships in June and waits.
What an unambiguous instant costs
In PostgreSQL, timestamptz costs 8 bytes. Every timezone-aware value is held internally in UTC and converted to the session's zone on the way out, using the IANA database. Write 2026-10-12T23:00:00-05:00 and the row holds one instant with no display preference attached to it. Alongside it, date costs 4 bytes and holds a calendar day with no time at all, which is the right type for a checkout day or a public holiday.
The hard parts are written down instead of hidden. The Postgres docs spell out that abbreviations are fixed offsets while full names carry daylight-saving rules, so 2014-06-04 12:00 EST means noon at UTC-5 whatever the calendar said that day. They mention that MSK meant UTC+3 in some years and UTC+4 in others. Zone names are not compiled into the server, they come from files under share/timezone, so when a government moves its clocks you update tzdata rather than hunting through formula fields. And you can write a test that asserts a booking lands at 23:00 in America/Lima in both July and January.
When we moved Stay World Class off Webflow and Xano onto Next.js, NestJS and Supabase, Lighthouse went from 55.91 to 91 out of 100 and LCP came down 77%. The slowest part of that project was a four stage ETL that mapped legacy platform IDs onto PostgreSQL UUIDs, because thousands of old rows had to keep pointing at each other through the move. Dates were the same shape of problem in miniature. A value that was written without a zone cannot be repaired by a better schema. Someone has to decide what it meant, and the honest version of that fix is usually to ask the customer.
When staying put is the right call
If your team and your customers all sit in one time zone, turn on "use the same time zone for all collaborators" for every date field and the problem is gone. Airtable's model is then correct for your situation and migrating over dates alone would be a waste of a quarter. The same goes if your dates are all-day values nobody ever compares across regions.
Bubble deserves a distinction here. It stores every date as milliseconds since the Unix epoch, which is a genuine instant, and its backend workflows accept a timezone_string parameter taking an IANA name like Europe/Oslo. Its documented failure runs the other way: because a Bubble date always includes a time, an all-day value saved at midnight UTC shows up as the previous day for users west of UTC, and the recommended fix is to split it into separate fields. That is a workaround for a missing type, not a missing instant.
Writing it yourself does not make the subject easy. Temporal, the JavaScript API built around storing an instant plus a zone, is still listed on MDN as limited availability and not Baseline as of September 2026, so you ship a library and you still have to decide what each column means. What changes is that the decision gets a name, a type and a test, and the test can run in January while it is still July.
