0

I am fairly new to (Java) programming and I am trying to build a little Android app that will tell you if it's already weekend or not.

I already got it so far that it can tell you if it's weekend or not, however I also want to show a little countdowntimer in that app until the weekend starts, or ends.

I am unable to think about an Algorithm to calculate the time (in milliseconds) between the current time and the next Saturday (if it's not in a weekend) or Monday if it's a weekend.

I know how to get the current day in the week using the Calendar class, however I get stuck when I try to get the time until the next Saturday or Monday. I can't think about a way to do this.

This might sound like a stupid question but I have really lost my mind in this. Hopefully one of you guys can help me out.

Rik
  • 90
  • 8

2 Answers2

4

Here's the process, but as a description rather than code, leaving the rest for you as an implementation exercise:

  • Get the current time in milliseconds, and remember it for later
  • Create an appropriate Calendar object
  • Work out the day you're trying to aim for (Saturday or Monday)
  • Work out how many days you need to add to get there (based on the current "day of week" and the day of week you're aiming for), and add that many days
    • As a simpler (but less efficient) alternative: keep adding 1 day until the day of week is correct!
  • Use multiple set calls to get to the right time of day (so set the hour to 0, the minute to 0, the second to 0, the millisecond to 0) - assuming that you're looking for midnight, of course
  • Use getTimeInMillis() to get the point in time you're aiming for
  • Subtract the original value, and the result will be the number of milliseconds you need to wait

One thing to bear in mind is that daylight saving time changes can make things "interesting"... so at the very start of Saturday, there might be 47 or 49 hours before you get to the start of Monday, instead of the normal 48. I'd expect the above algorithm to cope in most cases, but if you "aim" for Sunday you could have an odd situation in Brazil (and a few other places) when you try to get to midnight, as that might be skipped entirely... Time zones are annoying like that.

Additionally, if you can use Joda Time it could make your life simpler.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thank you for your help, currently i'm stuck at working on out how many days I need to add, but i'm sure I will find something for that! – Rik Mar 07 '14 at 18:42
  • @Rik: Consider using the "just keep adding a day until the day of week is correct" approach then - that's pretty simple :) – Jon Skeet Mar 07 '14 at 18:58
  • Well, all I have to figure out is the date of the Saturday/Monday I am aiming for and then I should have it working :p – Rik Mar 07 '14 at 19:22
  • @Rik: If you *start* by adding a day, can't you just keep going until the result is Saturday or Monday? You don't even need to know which of them you're aiming for! – Jon Skeet Mar 07 '14 at 19:23
  • Doesn't the Calendar.set function require the right date in the month? I only got it working with the right day by hardcoding it. – Rik Mar 07 '14 at 19:27
  • @Rik: I never suggested using `Calendar.set` with a date field - use `Calendar.add(Calendar.DATE, 1)` to add a day at a time. I only suggested using `Calendar.set` to clear out the time of day when you've got to the right day. – Jon Skeet Mar 07 '14 at 19:27
  • I know you didn't suggest it for the date, but I thought that was the way you should set a date. Sorry for the inconvenience. Anyway, I hardcoded it for now, tomorrow I will continue with the development of my app. Thanks for your help. – Rik Mar 07 '14 at 20:03
1

java.time

The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.

Also, quoted below is a notice from the home page of Joda-Time:

Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.

Solution using java.time, the modern Date-Time API:

The solution uses following functions:

  1. ZonedDateTime#now(ZoneId): Returns the current date-time from the system clock in the specified timezone.
  2. ZonedDateTime#getDayOfWeek: Returns the day-of-week field, which is an enum DayOfWeek.
  3. TemporalAdjusters#next: Returns the next day-of-week adjuster, which adjusts the date to the first occurrence of the specified day-of-week after the date being adjusted.
  4. ZonedDateTime#toLocalDate: Returns the LocalDate part of this date-time.
  5. LocalTime#atStartOfDay(ZoneId): Returns a zoned date-time from this date at the earliest valid time according to the rules in the time-zone.
  6. ChronoUnit#between: Calculates the amount of time between two temporal objects.

Demo:

import static java.time.DayOfWeek.SATURDAY;
import static java.time.DayOfWeek.SUNDAY;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.TextStyle;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // Tests
        process(ZonedDateTime.now(ZoneId.systemDefault()));
        process(ZonedDateTime.of(LocalDate.of(2021, 6, 23), LocalTime.of(10, 20, 30, 123456789),
                ZoneId.systemDefault()));
        process(ZonedDateTime.of(LocalDate.of(2021, 6, 26), LocalTime.of(10, 20, 30, 123456789),
                ZoneId.systemDefault()));
    }

    static long millisBetween(ZonedDateTime start, ZonedDateTime end) {
        return ChronoUnit.MILLIS.between(start, end);
    }

    static boolean isWeekend(ZonedDateTime now) {
        DayOfWeek dow = now.getDayOfWeek();
        return dow == SATURDAY || dow == SUNDAY;
    }

    static void process(ZonedDateTime now) {
        String dow = now.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.ENGLISH);
        if (isWeekend(now)) {
            System.out.printf("It's %s (a weekend) now. Monday is %d milliseconds ahead.%n", dow,
                    millisBetween(now, now.with(TemporalAdjusters.next(DayOfWeek.MONDAY)).toLocalDate()
                            .atStartOfDay(ZoneId.systemDefault())));
        } else {
            System.out.printf("It's %s (a weekday) now. Saturday is %d milliseconds ahead.%n", dow,
                    millisBetween(now, now.with(TemporalAdjusters.next(DayOfWeek.SATURDAY)).toLocalDate()
                            .atStartOfDay(ZoneId.systemDefault())));
        }
    }
}

Output from a sample run:

It's Sunday (a weekend) now. Monday is 30258373 milliseconds ahead.
It's Wednesday (a weekday) now. Saturday is 221969876 milliseconds ahead.
It's Saturday (a weekend) now. Monday is 135569876 milliseconds ahead.

ONLINE DEMO

Note: For the code to work for a timezone different from the JVM's timezone, replace ZoneId.systemDefault() with the applicable timezone ID e.g. ZoneId.of("America/New_York").

Learn more about the modern Date-Time API from Trail: Date Time.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110