javadatejava-calendar

Update Daily Counter Of Date From Specific Time


I have two dates with me say '2018-01-01'Start Date and '2018-01-31' End Date

I want to make my logic in a way that, each day my start date will increase until its reach 2018-02-28. Below is the code snippet I tried. How can this fix as Start Date should change on daily basis.

public class myclass {
    public static void main(String a[]) {
        try {
            String dt = "2008-01-01";  // Start date
            String dt1 = "2008-01-31";  // End date
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Calendar c = Calendar.getInstance();
            c.setTime(sdf.parse(dt));
            c.add(Calendar.DATE, 1);  // number of days to add
            dt = sdf.format(c.getTime());  //
            System.out.println(dt);
        }catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

PS : This execution is Real Time, In scheduler which runs daily and check against the finale date from the given date. How many days remaining.

Thanks


Solution

  • Runnable

    Define the work you need to done as a Runnable.

    Then use a Scheduled ExecutorService to run this every minute or so, checking the current date against the target date. If the countdown has incremented, updated the display in the GUI. If not, do nothing, let the Runnable run again after another minute.

    See the Oracle Tutorial on Executors.

    ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();  // Use a single thread, as we need this to run sequentially, not in parallel.
    ses.scheduleWithFixedDelay( r , 0L , 1L , TimeUnit.MINUTES ); // Pass the `Runnable`, an initial delay, a count to wait between runs, and the unit of time for those two other number arguments.
    

    It would be more efficient to schedule a new Runnable each time, rather than auto-repeating, so as set the delay a calculated amount of time until the next midnight. This way the executor would sleep all day rather than running every minute. But that approach can go haywire if the user's clock updates to a significantly different current time or if the user's current default time zone changes (if you are depending on the default rather than setting one explicitly). Given how little this Runnable needs to do (just check current date & calc remaining days) there no practical reason to not just let it run every minute or two (however long is your minimum tolerance for fresh update to the user - a business policy of your app’s management).

    LocalDate

    The LocalDate class represents a date-only value without time-of-day and without time zone or offset-from-UTC.

    A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.

    If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment during runtime(!), so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.

    Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

    ZoneId z = ZoneId.of( "Asia/Kolkata" );  // Or ZoneId.systemDefault() to rely on the JVM’s current default time zone.
    LocalDate today = LocalDate.now( z );
    

    Example

    Here is complete example. For more info, search Stack Overflow. The use of ScheduledExecutorService has been covered many times already.

    package work.basil.example;
    
    import java.time.Instant;
    import java.time.LocalDate;
    import java.time.Month;
    import java.time.ZoneId;
    import java.time.temporal.ChronoUnit;
    import java.util.Objects;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public class DailyCountdown implements Runnable {
        private LocalDate dueDate;
        private Long daysRemaining;
    
        public DailyCountdown ( LocalDate dueDate ) {
            this.dueDate = dueDate;
        }
    
        @Override
        public void run () {
            try {
                System.out.println( "DEBUG - Running the DailyCountdown::run method at " + Instant.now() );
                ZoneId z = ZoneId.of( "America/Montreal" );  // Or ZoneId.systemDefault() to rely on the JVM’s current default time zone.
                LocalDate today = LocalDate.now( z );
                Long count = ChronoUnit.DAYS.between( today , this.dueDate );
                if ( Objects.isNull( this.daysRemaining ) ) {
                    this.daysRemaining = ( count - 1 );
                }
                if ( this.daysRemaining.equals( count ) ) {
                    // Do nothing.
                } else {
                    // … Schedule on another thread for the GUI to update with the new number.
                    this.daysRemaining = count;
                }
            } catch ( Exception e ) {
                // Log this unexpected exception, and notify sysadmin.
                // Any uncaught exception reaching the scheduled executor service would have caused it to silently halt any further scheduling.
            }
        }
    
        public static void main ( String[] args ) {
            // Put this code where ever appropriate, when setting up your GUI after the app launches.
            Runnable r = new DailyCountdown( LocalDate.of( 2018 , Month.FEBRUARY , 15 ) );
            ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
            ses.scheduleWithFixedDelay( r , 0L , 1L , TimeUnit.MINUTES );
    
            // Be sure to gracefully shutdown the ScheduledExecutorService when your program is stopping. Otherwise, the executor may continue running indefinitely on the background thread.
            try {
                Thread.sleep( TimeUnit.MINUTES.toMillis( 7 ) ); // Sleep 7 minutes to let the background thread do its thing.
            } catch ( InterruptedException e ) {
                System.out.println( "The `main` thread was woken early from sleep." );
            }
            ses.shutdown();
            System.out.println( "App is exiting at " + Instant.now() ) ;
        }
    }