Pin the zone explicitly
@Scheduled accepts a zone attribute with any IANA timezone id. Setting it makes the schedule independent of the server configuration.
@Scheduled(cron = "0 0 9 * * MON-FRI", zone = "Europe/Berlin")
DST is a wall-clock schedule
Cron matches local calendar time, not elapsed hours. When a timezone switches to daylight saving time, the local clock jumps forward, so a 02:30 job may not exist on that day; when the clock falls back, the same local time happens twice.
In this tool, a local time that does not exist is skipped rather than silently shifted, which matches how a wall-clock schedule should behave.
Midnight jobs and zone changes
Some zones (for example America/Santiago) skip midnight on the transition day. A "0 0 0 * * *" job will not run on that date, because there is no midnight to run at.