简体   繁体   中英

Create a cron expression for every month's 1st working day and 15th working day at 8 am

I have to create the batch job which will run on two days in every month. Like, it will 1st run on 1st working day of the month and then it should run on 14th working day from 1st working day ie (1+14=15) on 15th working day of the same month. Both days should not be Saturday and Sunday only working day should be considered.

I know the 2 separate cron expressions for 1st working day -> ( 0 0 8 1W * ?) and for 15th working day -> ( 0 0 8 15W * ?). So, I have tried ( 0 0 8 1W,15W * ?) but it is not allowing me to have list of weekdays in a single cron.

I didn't work on coding part yet as first I need is cron expression to run my housekeeping task on 2 weekdays of the single month.

0 0 8 1W,15W * ? with this cron expression I was expecting result as 1st July 2019, Monday and 15th July 2019, Monday but the actual result is only 1st July 2019, Monday.

It looks like there is a bug in the Quartz CronExpression class when it comes to processing the next fire time when the day of the month has the workday flag.

That said the W doesn't appear to work as you have described above in that it finds the nearest workday and not the next workday. So if the 15th fell on a Saturday the job would run on the preceding Friday.

You could, in theory, solve this by writing your own Trigger or Calendar implementation. Alternatively, you could just have the job trigger every day at 8 am and have an early termination if it is an invalid date to run. For example on the first line of your job you could have a line like:

   if (!shouldRunToday()) {
      return;
   };

An implementation of shouldRunToday using JodaTime may look like something like this:

    public static boolean shouldRunToday() {
        LocalDate date = LocalDate.now();

        Set<Integer> days = new HashSet<>();
        days.add(1);
        days.add(15);

        DayOfWeek dayOfWeek = DayOfWeek.of(date.getDayOfWeek());
        if (dayOfWeek == DayOfWeek.MONDAY) {
            days.add(2);
            days.add(3);
            days.add(16);
            days.add(17);
        }

        Set<DayOfWeek> weekend = EnumSet.of(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY);
        return days.contains(date.getDayOfMonth()) && !weekend.contains(dayOfWeek);
    }

If you want to use Calendar the equivalent code would look as follows

    public static boolean shouldRunToday() {
        Calendar date = Calendar.getInstance();

        Set<Integer> days = new HashSet<>();
        days.add(1);
        days.add(15);

        int dayOfWeek = date.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == Calendar.MONDAY) {
            days.add(2);
            days.add(3);
            days.add(16);
            days.add(17);
        }

        List<Integer> weekend = Arrays.asList(Calendar.SATURDAY, Calendar.SUNDAY);
        return days.contains(date.get(Calendar.DAY_OF_MONTH)) && !weekend.contains(dayOfWeek);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM