diff --git a/core/src/main/java/hudson/scheduler/CronTab.java b/core/src/main/java/hudson/scheduler/CronTab.java index 81fa5075c9..40381e2b71 100644 --- a/core/src/main/java/hudson/scheduler/CronTab.java +++ b/core/src/main/java/hudson/scheduler/CronTab.java @@ -532,4 +532,17 @@ public final class CronTab { return null; } } + + /** + * Returns the configured time zone, or null if none is configured + * + * @return the configured time zone, or null if none is configured + * @since TODO + */ + @CheckForNull public TimeZone getTimeZone() { + if (this.specTimezone == null) { + return null; + } + return TimeZone.getTimeZone(this.specTimezone); + } } diff --git a/core/src/main/java/hudson/scheduler/CronTabList.java b/core/src/main/java/hudson/scheduler/CronTabList.java index 3243dda38e..bb20834597 100644 --- a/core/src/main/java/hudson/scheduler/CronTabList.java +++ b/core/src/main/java/hudson/scheduler/CronTabList.java @@ -131,7 +131,7 @@ public final class CronTabList { public @CheckForNull Calendar previous() { Calendar nearest = null; for (CronTab tab : tabs) { - Calendar scheduled = tab.floor(Calendar.getInstance()); + Calendar scheduled = tab.floor(tab.getTimeZone() == null ? Calendar.getInstance() : Calendar.getInstance(tab.getTimeZone())); if (nearest == null || nearest.before(scheduled)) { nearest = scheduled; } @@ -143,7 +143,7 @@ public final class CronTabList { public @CheckForNull Calendar next() { Calendar nearest = null; for (CronTab tab : tabs) { - Calendar scheduled = tab.ceil(Calendar.getInstance()); + Calendar scheduled = tab.ceil(tab.getTimeZone() == null ? Calendar.getInstance() : Calendar.getInstance(tab.getTimeZone())); if (nearest == null || nearest.after(scheduled)) { nearest = scheduled; } diff --git a/core/src/test/java/hudson/triggers/TimerTriggerTest.java b/core/src/test/java/hudson/triggers/TimerTriggerTest.java index ef6edf4400..8489776eee 100644 --- a/core/src/test/java/hudson/triggers/TimerTriggerTest.java +++ b/core/src/test/java/hudson/triggers/TimerTriggerTest.java @@ -24,9 +24,14 @@ package hudson.triggers; import antlr.ANTLRException; +import hudson.scheduler.CronTabList; +import hudson.scheduler.Hash; +import org.junit.Assert; import org.junit.Test; import org.jvnet.hudson.test.Issue; +import java.util.TimeZone; + /** * @author Kanstantsin Shautsou */ @@ -36,4 +41,22 @@ public class TimerTriggerTest { public void testNoNPE() throws ANTLRException { new TimerTrigger("").run(); } + + @Issue("JENKINS-43328") + @Test + public void testTimeZoneOffset() throws Exception { + TimeZone defaultTz = TimeZone.getDefault(); + TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin")); + try { + String cron = "TZ=GMT\nH 0 * * *"; + CronTabList ctl = CronTabList.create(cron, Hash.from("whatever")); + Assert.assertEquals("previous occurrence is in GMT", "GMT", ctl.previous().getTimeZone().getID()); + + cron = "TZ=America/Denver\nH 0 * * *"; + ctl = CronTabList.create(cron, Hash.from("whatever")); + Assert.assertEquals("next occurrence is in America/Denver", "America/Denver", ctl.next().getTimeZone().getID()); + } finally { + TimeZone.setDefault(defaultTz); + } + } }