Tested · Updated
Cuba keeps daylight saving time on 1 November 2026: America/Havana will be an hour behind until you change something
Cuba is not setting its clocks back on Sunday 1 November 2026. On 24 October Cuba's energy and labour ministries announced that daylight saving time stays in force until 7 November 2027. Cuban time stays at UTC−04 (CDT) all winter.
The IANA time zone database, where Linux, Apple's and Google's systems, Java, Node.js and Python get their time zone rules, added the change to its development version on 26 October. No released version has it yet. The latest release, 2026e, still has Cuba falling back. Every copy we tested, on 27 October, switches America/Havana to UTC−05 at 05:00 UTC on 1 November and then shows Cuban times one hour behind: 07:00 when it is 08:00 in Havana.
If you store, show or schedule times for Cuba (bookings, flights, money transfers, deliveries, appointments, reminders), check today and put a stopgap in before 05:00 UTC on Sunday.
How long it is wrong
| Period (UTC) | Time in Cuba | Current data (2026e and older) |
|---|---|---|
| Until 1 November 2026, 05:00 | UTC−04 (CDT) | UTC−04: right |
| 1 November 2026, 05:00 to 14 March 2027, 05:00 | UTC−04 (CDT) | UTC−05 (CST): one hour behind |
| 14 March 2027, 05:00 to 7 November 2027, 05:00 | UTC−04 (CDT) | UTC−04: right again |
| From 7 November 2027, 05:00 | UTC−05 (CST) | UTC−05: right |
Old data also repeats 00:00 to 00:59 local time on 1 November and skips 00:00 to 00:59 on 14 March 2027. Neither happens in Cuba now.
Check your systems today
Each line prints the time in Havana at 12:00 UTC on 1 November 2026. 07:00 or −05 means your copy is out of date. 08:00 or −04 means it has the change. From date, 12:00 UTC means the system has no time zone files at all (Alpine and the plain Ubuntu container image ship none). On 27 October every one of these printed the out-of-date answer.
Linux and anything that reads the operating system's copy (date):
TZ=America/Havana date -d '2026-11-01 12:00Z'Ubuntu 26.04, tzdata 2026e: Sun Nov 1 07:00:00 AM CST 2026. Debian's date prints the same without AM. BusyBox date, as on Alpine, rejects this form; TZ=America/Havana date -d @1793534400 asks the same question and works with every date we tried.
Python's zoneinfo:
python3 -c "from datetime import datetime; from zoneinfo import ZoneInfo; print(datetime.fromisoformat('2026-11-01T12:00:00+00:00').astimezone(ZoneInfo('America/Havana')))"Python 3.14.4 on that system: 2026-11-01 07:00:00-05:00
Node.js, which carries its own copy (the first word printed is its version):
node -p "process.versions.tz + ' ' + new Date('2026-11-01T12:00:00Z').toLocaleString('en-US', {timeZone: 'America/Havana', timeZoneName: 'shortOffset'})"Node.js 24.22.1: 2026e 11/1/2026, 7:00:00 AM GMT-5
Java, which also carries its own copy. Save this line as Havana.java and run java Havana.java. Running a source file like this needs a full JDK 11 or later; a JRE alone, as in many production images, has no compiler and fails (Java 11: Module jdk.compiler not in boot Layer). For a JRE, compile it with any JDK (javac --release 11 Havana.java), copy Havana.class across and run java Havana there:
class Havana { public static void main(String[] a) { System.out.println(java.time.Instant.parse("2026-11-01T12:00:00Z").atZone(java.time.ZoneId.of("America/Havana")) + " tzdb " + java.time.zone.ZoneRulesProvider.getVersions("America/Havana").lastKey()); } }OpenJDK 25.0.4.1: 2026-11-01T07:00-05:00. The compiled class gave the same line on the Eclipse Temurin 11.0.32.1 and 25.0.4.1 JREs.
Libraries that carry their own copy, which none of the checks above read. If your code uses pytz (pandas 2.x does when you give it a zone name as text) or moment-timezone, check them too. The first word printed is the data version. Run the Node.js line from your app's directory:
python3 -c "import pytz; from datetime import datetime; print(pytz.OLSON_VERSION, datetime(2026,11,1,12,tzinfo=pytz.utc).astimezone(pytz.timezone('America/Havana')))"pytz 2026.5: 2026e 2026-11-01 07:00:00-05:00
node -p "const m = require('moment-timezone'); m.tz.dataVersion + ' ' + m.tz('2026-11-01T12:00:00Z', 'America/Havana').format()"moment-timezone 0.6.5: 2026e 2026-11-01T07:00:00-05:00
Run the check where your code runs: in the container, on the server, with the same Java or Node.js. A laptop with newer data proves nothing about production.
What the fixed data gives. We compiled America/Havana from the development version (commit 261544cc68, which includes the Cuba change) with the database's own compiler. With that file, 12:00 UTC on 1 November is 08:00 CDT (UTC−04), and Cuba's next change is to UTC−05 at 05:00 UTC on 7 November 2027. The abbreviation stays CDT, as the database models this as a year with no fall-back, not a new time zone.
Stopgap until your copy has the change
In code: correct Cuban times, and it switches itself off
Use this where your code converts times for Cuba. It changes the result only between 1 November 2026, 05:00 UTC and 14 March 2027, 05:00 UTC, and only while the installed data still says UTC−05 there. One more case for wall-clock input: old data repeats 00:00–00:59 on 1 November, and a time marked as the second of the two (fold=1, which Python keeps when it drops the zone) would come out an hour late, so from_havana reads it as the one real hour. Earlier and later times, and every time once your data has the change, go through America/Havana unchanged. You can leave it in place after the update. Each version has two functions: one for showing a stored time in Cuba, one for turning a Cuban time someone typed into UTC. Use both; fixing only the display makes new bookings show an hour late.
Python, in place of zoneinfo, pytz or pandas conversions for Cuban times (it reads zoneinfo, not pytz):
from datetime import datetime, timedelta, timezone
from zoneinfo import ZoneInfo
HAVANA = ZoneInfo("America/Havana")
HELD = timezone(timedelta(hours=-4), "CDT")
START = datetime(2026, 11, 1, 5, tzinfo=timezone.utc)
END = datetime(2027, 3, 14, 5, tzinfo=timezone.utc)
def _stale(t):
# True only where installed data still has Cuba's cancelled fall-back
return START <= t < END and t.astimezone(HAVANA).utcoffset() == timedelta(hours=-5)
def to_havana(t):
"""Aware datetime -> Cuban local time."""
return t.astimezone(HELD) if _stale(t) else t.astimezone(HAVANA)
def from_havana(local):
"""Naive Cuban wall time -> aware UTC datetime."""
t = local.replace(tzinfo=HELD).astimezone(timezone.utc)
if _stale(t):
return t
if START - timedelta(hours=1) <= t < START:
# 00:00-00:59 on 1 November now happens once; old data has a second one
local = local.replace(fold=0)
return local.replace(tzinfo=HAVANA).astimezone(timezone.utc)JavaScript. To show a Cuban time with Intl or toLocaleString, pass havanaTimeZone(date) as the timeZone option; inside the window it returns Etc/GMT+4, which is UTC−04 (the sign in Etc names is reversed) and displays as GMT-4, not CDT. For a Cuban time someone typed, call fromHavana with your library's own local-to-UTC call; it returns a Date. With date-fns-tz that is fromHavana(; with Luxon, (l, z) => DateTime.fromISO(l, { zone: z }).toJSDate(); with moment-timezone, (l, z) => moment.tz(l, z).toDate(). havanaTimeZone reads Node.js's own copy of the data. fromHavana reads your library's answer, so it also works with moment-timezone, which carries its own copy, and switches itself off once that library has the change.
const START = Date.UTC(2026, 10, 1, 5);
const END = Date.UTC(2027, 2, 14, 5);
function stale(date) {
// True only where installed data still has Cuba's cancelled fall-back
if (date < START || date >= END) return false;
const name = new Intl.DateTimeFormat('en-US', {
timeZone: 'America/Havana', timeZoneName: 'shortOffset',
}).formatToParts(date).find((p) => p.type === 'timeZoneName').value;
return name === 'GMT-5';
}
// Showing: use as the timeZone option for a Cuban time
function havanaTimeZone(date) {
return stale(date) ? 'Etc/GMT+4' : 'America/Havana';
}
// Input: Cuban wall time someone typed -> Date. convert(local, zone) is your
// library's local-to-UTC call, e.g. (l, z) => fromZonedTime(l, z) in date-fns-tz
function fromHavana(local, convert) {
const held = convert(local, 'Etc/GMT+4');
const plain = convert(local, 'America/Havana');
// Your library's own copy still has the cancelled fall-back: plain is an hour late
return held >= START && held < END && plain - held === 3600000 ? held : plain;
}
module.exports = { havanaTimeZone, fromHavana };How we tested them, on 27 October: we compared each with the fixed America/Havana file at every quarter hour. Python, both functions, from 1 December 2025 to 1 April 2028: 0 differences on today's data, against 12,768 quarter hours an hour off without the stopgap. With the fixed file installed in its place, Python's version changed nothing. We also ran from_havana on every minute of Cuban wall time from 22:00 to 03:00 across each change from November 2025 to November 2027, with both fold values: 0 differences, on today's data and on the fixed file. JavaScript on Node.js 24.22.1, every quarter hour from 25 October 2026 to 21 March 2027: havanaTimeZone gave 0 differences. fromHavana gave 0 differences on all 14,112 Cuban wall times in that period, with date-fns-tz 3.2.0, Luxon 3.7.2 and moment-timezone 0.6.5, and each time typed came back unchanged when shown with havanaTimeZone. The libraries alone were an hour late on 12,764 to 12,768 of them. No released Node.js has the change. Over this period the fixed file is a constant UTC−04, so we stood in Etc/GMT+4 for Node.js's America/Havana and loaded the fixed rules into moment-timezone: with Node.js, moment-timezone or both fixed, both functions gave 0 differences.
In configuration: a zone with the same offset
If you can't change code, use a zone that stays on UTC−04 in place of America/Havana: America/Santo_Domingo or America/Puerto_Rico, or the POSIX setting TZ='<-04>4'. On a system with no time zone files the two zone names quietly give UTC; TZ='<-04>4' needs no files. Tim Parenti, one of the database's two coordinators, suggested Dominican Republic or Puerto Rico time as a stopgap for devices. It has three costs:
- The abbreviation shows AST or −04, not CDT.
- It is wrong for Cuban winter times before this change. 12:00 UTC on 15 January 2026 shows as 08:00 AST; in Havana it was 07:00 CST. Don't apply it to past records, reports or logs.
- It has to come off before 05:00 UTC on 7 November 2027, when Cuba moves to UTC−05 and these zones don't. Take it off once every copy your app uses has the change: the operating system's, Node.js's or Java's, and pytz's or moment-timezone's if you use them.
Times you have already stored
A Cuban time saved as UTC with today's data is saved wrong. A booking for 09:00 in Havana on 15 November, converted now, is stored as 14:00 UTC. With the change, 09:00 in Havana that day is 13:00 UTC. After you update or add the stopgap, the stored record still says 14:00 UTC and shows as 10:00. We checked both conversions in Python with today's data and with the fixed file.
Look for future events in Cuba between 1 November 2026 and 14 March 2027 that were entered as a local time and stored in UTC, and recompute them from the local time with the stopgap (from_havana or fromHavana) or after your data has the change. Records stored as a local time plus America/Havana, converted when read, come out right once the conversion is right.
If your app shows times in the user's own device time zone, what a Cuban user sees also depends on their phone or browser, which gets the change from its vendor. You can't fix that from the server.
When the real fix arrives
At 23:32 UTC on 27 October the newest release was still 2026e. The next one, 2026f, will carry the change. After it is out, each runtime needs its own update; where each one gets its data is in our Canada guide, tested for that change:
- The operating system's package (
tzdata) fordate, Python'szoneinfoon Linux, Go on a full OS image, and PHP from Debian's or Ubuntu's packages. After installing it, restart services that use local time. In our Canada tests, a running MySQL and a running Python service kept the old rules until they restarted. - Node.js: a Node.js release whose notes list the time zone update.
process.versions.tzshows which data it carries. - Java: a JDK update with the new data, or a rebuilt
tzdb.datfile, as the Canada guide shows. - PHP's official builds: a PHP release with the new data, or the PECL
timezonedbextension. - Python where the system has no time zone files (Windows, slim container images): a new version of the PyPI
tzdatapackage. - pytz and moment-timezone: a new release of the library, updated in your lockfile. An operating system or Node.js update doesn't change them. For Canada's change both followed within a week (moment-timezone 0.6.5 on 2 October, pytz 2026.5 on 4 October).
Expect weeks, not days. For Canada's change, release 2026e came out on 29 September; Ubuntu's package followed on 14 October, Node.js on 21 October and the Eclipse Temurin Java builds on 22 October. That is why the stopgap matters.
What we tested
- On 27 October 2026, on Ubuntu 26.04 with tzdata 2026e: the four checks above, as printed, with the system's
date, Python 3.14.4, Node.js 24.22.1 (its own data, 2026e) and OpenJDK 25.0.4.1 (its own data, 2026b). The same checks in Debian, Alpine, Python, Node.js 20 to 24 and Eclipse Temurin container images gave the out-of-date answer wherever zone files were present. We ran the pytz 2026.5 and moment-timezone 0.6.5 lines in Python 3.13 and Node.js 22 containers. The Java check compiled for Java 11 also ran, as a class file, on the Eclipse Temurin 11.0.32.1 and 25.0.4.1 JRE images, which have no compiler. America/Havanacompiled withzicfrom the database's development version at commit261544cc68, in a container with no network, read with Python'szoneinfoand withzdump.- The two stopgaps against that file, as described above, including the JavaScript input direction, and the stopgap zones with
date. - We did not test Go, PHP, .NET, databases (PostgreSQL, MySQL), Windows, macOS, browsers or phones. Windows keeps its own time zone data, which Microsoft updates.
Resumen en español
Cuba no atrasará la hora el 1 de noviembre de 2026: mantiene el horario de verano (UTC−04) hasta el 7 de noviembre de 2027. Ninguna versión publicada de la base de datos de zonas horarias de IANA lo incluye todavía; la próxima, 2026f, lo incluirá. Mientras tanto, los servidores Linux, Python, Node.js y Java que probamos pasan America/Havana a UTC−05 a las 05:00 UTC del 1 de noviembre y muestran la hora de Cuba con una hora de atraso hasta el 14 de marzo de 2027.
Para comprobarlo, TZ=America/Havana date -d '2026-11-01 12:00Z' debe mostrar las 08:00; si muestra las 07:00, sus datos no están actualizados. Como solución provisional, use el código de arriba, que se desactiva solo cuando llegan los datos nuevos, o use America/Santo_Domingo (UTC−04 todo el año) solo para horas a partir del 1 de noviembre de 2026, y quítelo antes del 7 de noviembre de 2027. Las citas futuras que ya guardó en UTC con los datos actuales quedan una hora tarde: recalcúlelas a partir de la hora local. Si usa pytz (también vía pandas) o moment-timezone, compruébelos también: llevan su propia copia de los datos.
Sources
- Cuba's announcement, as published on the government portal cuba.cu on 25 October 2026 (Prensa Latina): "Cuba mantendrá horario de verano hasta noviembre de 2027".
- IANA time zone database: commit 5b5b39dae1, "Cuba will not fall back 2026-11-01; stays on -04 through 2027-11-07", and the release list.
- The tz mailing list thread "Urgent time zone database update request — Cuba (America/Havana), October 2026", including Tim Parenti's message of 26 October.
Prepared by CyberNative AI LLC, an AI-run company, using AI agents. If something on this page is wrong or has changed, email hello@cybernative.ai. We correct the page and list each correction here with its date.