Search code examples
javaeventstimecalendarweekday

Current time/date event listener


Is there a way in java to make an event listener based on the day/hour Like run this code block on every Wednesday at 15.30 or run this code block on 15th november at 17.30 for example?


Solution

  • ScheduledExecutorService

    For both your problems, ScheduledExecutorService is the solution. Learn about the Executors framework built into Java to make multi-threaded work much easier and more reliable.

    Run once at specific date/time

    this code block on 15th november at 17.30

    The executor service can run a task after waiting a certain amount of time.

    First determine the moment to run.

    ZoneId z = ZoneId.of( "America/Montreal" );
    ZonedDateTime zdt = ZonedDateTime.of( 2020 , 11 , 15 , 17 , 30 , 0 , 0 , z );
    

    Define your task to be run then.

    Runnable runnable = new Runnable()
    {
        @Override
        public void run ( )
        {
            System.out.println( "Runnable running. " + ZonedDateTime.now( z ) );
        }
    };
    

    Obtain an executor service, backed by a thread pool.

    ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
    

    Calculate how to wait from now until when the task needs to run. Here we use the Duration class to calculate elapsed time. We pass Instant objects which are always in UTC (an offset-from-UTC of zero hours-minutes-seconds).

    long delay = Duration.between( Instant.now() , zdt.toInstant() ).getSeconds();  // Calculate amount of time to wait until we run.
    

    Tell the executor service to run the task after waiting that amount of time. Be sure that the unit-of-time used in calculating the delay long integer matches the TimeUnit argument.

    scheduledExecutorService.schedule( runnable , delay , TimeUnit.SECONDS );  // ( Runnable , delay , TimeUnit of delay )
    

    If you want to track the completion of that task, capture the ScheduledFuture object returned by that schedule call.

    Run repeatedly

    run this code block on every Wednesday at 15.30

    Use code similar that that seen above. At the end of each task’s run, calculate the time to wait until the next run, and call scheduledExecutorService.schedule again. So part of the task’s work is to schedule its next run.

    The approach just mentioned must be followed if you want to stick with a strict schedule per the time-of-day and day-of-week as seen in a particular time zone. Politicians often change the offset-from-UTC used by their jurisdictions, so the length of days vary. Therefore we cannot schedule a weekly task as being 7 days * 24 hours * 60 minutes * 60 seconds. Weeks vary in length, so we must recalculate the length each time.

    If you do want to run repeatedly with the exact same gap in time, so you do not care about the locality’s changing clock, then use ScheduledExecutorService.scheduleAtFixedRate​ or ScheduledExecutorService.scheduleWithFixedDelay​. These have been covered many times already on Stack Overflow, so search to learn more.