Search code examples
javatimercountdown

Countdown until the end of the day


I'm having a hard time trying to make a countdown that ends until the end of the day (23:59).

I have a method that returns how much time is left, it returns something like this: "5h 10m 1s" and that's fine, the problem is that I want it to return me the remaining how much is left until 23:59.

I am saving in millis when a complete the action in and from that I want to calculate the time until the end of the day.

I have something like this:

public String getCountdown(UUID uuid, Quest quest) {

    String countdownTimePlaceholder = "";
    long questCompletedTimeMillis = plugin.getDatabaseManager().getQuestCompletedMillis(uuid, quest);
    long currentTimeMillis = System.currentTimeMillis();
    int hour = new Date().getHours();
    int minutes = new Date().getMinutes();
   

 int second = new Date().getSeconds();
        long seconds = ((24*60*60) - ((hour*60*60) + (minutes*60) + second));
        long seconds2 = seconds * 1000L;
        long waitingTime = currentTimeMillis - questCompletedTimeMillis;
        long waitingTimeDiv = waitingTime / 1000L;
        long waitingTimeSeconds = seconds - waitingTimeDiv, waitingTimeMinutes = waitingTimeSeconds / 60L, waitingTimeHours = waitingTimeMinutes / 60L;
        
        if (questCompletedTimeMillis + seconds2 > currentTimeMillis && questCompletedTimeMillis != 0L) {
            
            if (waitingTimeSeconds > 59L) waitingTimeSeconds -= 60L * waitingTimeMinutes;
            
            if (waitingTimeSeconds != 0L) countdownTimePlaceholder = waitingTimeSeconds + "s";
            
            if (waitingTimeMinutes > 59L) waitingTimeMinutes -= 60L * waitingTimeHours;
            
            if (waitingTimeMinutes > 0L) countdownTimePlaceholder = waitingTimeMinutes + "m " + countdownTimePlaceholder;
            
            if (waitingTimeHours > 0L) countdownTimePlaceholder = waitingTimeHours + "h " + countdownTimePlaceholder;
            
            return countdownTimePlaceholder;
        }
        return "-1";
    }

Solution

  • You said:

    until the end of the day (23:59)

    Aiming for 23:59 is a flawed approach. For one thing, that time of day may not exist on some dates in some time zones. For another, you fail to cover the whole day, ignoring the entire minute that exists before the new day starts. You cannot neatly abut days, because of that missing minute gap.

    Instead, generally the best approach is Half-Open, where the beginning is inclusive while the ending is exclusive. So a day runs up to, but does not include, the beginning of the following day.

    Capture the current moment as seen in the time zone of interest to you.

    ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
    ZonedDateTime now = ZonedDateTime.now( z ) ;
    

    Get first moment of the day tomorrow.

    LocalDate tomorrow = now.toLocalDate().plusDays( 1 ) ;
    ZonedDateTime tomorrowStart = tomorrow.atStartOfDay( z ) ;
    

    Calculate elapsed time.

    Duration d = Duration.between( now.toInstant() , tomorrowStart.toInstant() ) ;
    

    Tip: For a class representing a span of time as a pair of Instant objects, see Interval in ThreeTen-Extra.