diff --git a/lib/types/later.d.ts b/lib/types/later.d.ts
index ec2cd572dd882d3838877dad016ff8030527ef17..ae691223a8387b0a187ce4b7563fbe3e1f98944a 100644
--- a/lib/types/later.d.ts
+++ b/lib/types/later.d.ts
@@ -101,7 +101,36 @@ declare module '@breejs/later' {
     [timeperiodAndModifierName: string]: number[] | undefined;
   }
 
-  const later: { parse: { text: (s: string) => ScheduleData } };
+  interface Schedule {
+    /**
+     * True if the specified value is valid for the specified date, false otherwise.
+     *
+     * @param date - The given date.
+     */
+    isValid(date: Date): boolean;
+  }
+
+  const later: {
+    /**
+     * Parse
+     * For generating schedule data.
+     */
+    parse: {
+      /**
+       * Create schedule data by paring a human readable string.
+       *
+       * @param [input] - A string value to parse.
+       */
+      text: (s: string) => ScheduleData;
+    };
+
+    /**
+     * Compiles schedule instances from schedule data.
+     *
+     * @param data - The given schedule data.
+     */
+    schedule(data: ScheduleData): Schedule;
+  };
 
   export = later;
 }
diff --git a/lib/workers/branch/schedule.spec.ts b/lib/workers/branch/schedule.spec.ts
index 0b0978d9a3dd9a0b31e552d80ab9d4638cc8c156..0ad1dfb7f00446202c406ad93f40087fd1248d6e 100644
--- a/lib/workers/branch/schedule.spec.ts
+++ b/lib/workers/branch/schedule.spec.ts
@@ -156,12 +156,30 @@ describe(getName(), () => {
       const res = schedule.isScheduledNow(config);
       expect(res).toBe(false);
     });
-    it('supports timezone', () => {
-      config.schedule = ['after 4:00pm'];
-      config.timezone = 'Asia/Singapore';
-      mockDate.set('2017-06-30T10:50:00.000Z'); // Globally 2017-06-30 10:50am
-      const res = schedule.isScheduledNow(config);
-      expect(res).toBe(true);
+    describe('supports timezone', () => {
+      const cases: [string, string, string, boolean][] = [
+        ['after 4pm', 'Asia/Singapore', '2017-06-30T15:59:00.000+0800', false],
+        ['after 4pm', 'Asia/Singapore', '2017-06-30T16:01:00.000+0800', true],
+        [
+          'before 3am on Monday',
+          'Asia/Tokyo',
+          '2017-06-26T02:59:00.000+0900',
+          true,
+        ],
+        [
+          'before 3am on Monday',
+          'Asia/Tokyo',
+          '2017-06-26T03:01:00.000+0900',
+          false,
+        ],
+      ];
+
+      test.each(cases)('%p, %p, %p', (sched, tz, datetime, expected) => {
+        config.schedule = [sched];
+        config.timezone = tz;
+        mockDate.set(datetime);
+        expect(schedule.isScheduledNow(config)).toBe(expected);
+      });
     });
     it('supports multiple schedules', () => {
       config.schedule = ['after 4:00pm', 'before 11:00am'];
@@ -257,5 +275,19 @@ describe(getName(), () => {
       const res = schedule.isScheduledNow(config);
       expect(res).toBe(false);
     });
+    it('supports weekday instances', () => {
+      config.schedule = ['on Monday on the first day instance'];
+
+      const cases: [string, boolean][] = [
+        ['2017-02-01T06:00:00.000', false], // Locally Thursday, 2 February 2017 6am
+        ['2017-02-06T06:00:00.000', true], // Locally Monday, 6 February 2017 6am
+        ['2017-02-13T06:00:00.000', false], // Locally Monday, 13 February 2017 6am
+      ];
+
+      cases.forEach(([datetime, expected]) => {
+        mockDate.set(datetime);
+        expect(schedule.isScheduledNow(config)).toBe(expected);
+      });
+    });
   });
 });
diff --git a/lib/workers/branch/schedule.ts b/lib/workers/branch/schedule.ts
index ec34edaff02a6f32d7fd9894bcf587f9ceec2fa0..443510053c43ef4faca0cec13bbe28c66fcf28bc 100644
--- a/lib/workers/branch/schedule.ts
+++ b/lib/workers/branch/schedule.ts
@@ -115,76 +115,23 @@ export function isScheduledNow(config: RenovateConfig): boolean {
   logger.trace(`currentSeconds=${currentSeconds}`);
   // Support a single string but massage to array for processing
   logger.debug(`Checking ${configSchedule.length} schedule(s)`);
+
+  // later is timezone agnostic (as in, it purely relies on the underlying UTC date/time that is stored in the Date),
+  // which means we have to pass it a Date that has an underlying UTC date/time in the same timezone as the schedule
+  const jsNow = now.setZone('utc', { keepLocalTime: true }).toJSDate();
+
   // We run if any schedule matches
   const isWithinSchedule = configSchedule.some((scheduleText) => {
     const massagedText = scheduleMappings[scheduleText] || scheduleText;
     const parsedSchedule = later.parse.text(fixShortHours(massagedText));
     logger.debug({ parsedSchedule }, `Checking schedule "${scheduleText}"`);
-    // Later library returns array of schedules
-    return parsedSchedule.schedules.some((schedule) => {
-      // Check if months are defined
-      if (schedule.M) {
-        const currentMonth = now.month;
-        if (!schedule.M.includes(currentMonth)) {
-          logger.debug(
-            `Does not match schedule because ${currentMonth} is not in ${String(
-              schedule.M
-            )}`
-          );
-          return false;
-        }
-      }
-      // Check if days are defined
-      if (schedule.d) {
-        // We need to map because 'luxon' uses monday as first day
-        // and later uses sundays as first day of week
-        // http://bunkat.github.io/later/time-periods.html#day-of-week
-        const dowMap = [6, 7, 1, 2, 3, 4, 5, 6];
-        const scheduledDays = schedule.d.map((day) => dowMap[day]);
-        logger.trace({ scheduledDays }, `scheduledDays`);
-        if (!scheduledDays.includes(currentDay)) {
-          logger.debug(
-            `Does not match schedule because ${currentDay} is not in ${String(
-              scheduledDays
-            )}`
-          );
-          return false;
-        }
-      }
-      if (schedule.D) {
-        logger.debug({ schedule_D: schedule.D }, `schedule.D`);
-        const currentDayOfMonth = now.day;
-        if (!schedule.D.includes(currentDayOfMonth)) {
-          return false;
-        }
-      }
-      // Check for start time
-      if (schedule.t_a) {
-        const startSeconds = schedule.t_a[0];
-        if (currentSeconds < startSeconds) {
-          logger.debug(
-            `Does not match schedule because ${currentSeconds} is earlier than ${startSeconds}`
-          );
-          return false;
-        }
-      }
-      // Check for end time
-      if (schedule.t_b) {
-        const endSeconds = schedule.t_b[0];
-        if (currentSeconds > endSeconds) {
-          logger.debug(
-            `Does not match schedule because ${currentSeconds} is later than ${endSeconds}`
-          );
-          return false;
-        }
-      }
-      // Check for week of year
-      if (schedule.wy && !schedule.wy.includes(now.weekNumber)) {
-        return false;
-      }
+
+    if (later.schedule(parsedSchedule).isValid(jsNow)) {
       logger.debug(`Matches schedule ${scheduleText}`);
       return true;
-    });
+    }
+
+    return false;
   });
   if (!isWithinSchedule) {
     logger.debug('Package not scheduled');