0

I have to take an action if the time falls between start and stop time and on a specific day. I referred some existing threads on SO to check if the time falls within the specified time range.

Say if start time is 23:00pm, stop time is 7:00am and current time is 2:00am. Just the time validity function returns true. But if I include days in this code, the function returns false. Eg: user selects [Monday, Tuesday, Wednesday]. Even though Thursday is not in the list, but the end time 7:00am falls on Thursday, action can be taken anytime between 23:00pm Wed - 7:00am Thu, but action cannot be taken on 23:00pm Thu or any days not mentioned in the list.

Below is my code:

private fun isCurrentTimeBetweenProvidedTime(context: Context): Boolean {
        var reg = "^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$".toRegex()
        val startTime = getStartTime()
        val endTime = getEndTime()
        val currentTime = getCurrentTime()

        if (reg.containsMatchIn(startTime) && reg.containsMatchIn(endTime) && reg.containsMatchIn(currentTime)) {
            var valid = false

            var startTime = SimpleDateFormat("HH:mm:ss").parse(startTime)
            var startCalendar = Calendar.getInstance()
            startCalendar.time = startTime

            var currentTime = SimpleDateFormat("HH:mm:ss").parse(currentTime)
            var currentCalendar = Calendar.getInstance()
            currentCalendar.time = currentTime

            var endTime = SimpleDateFormat("HH:mm:ss").parse(endTime)
            var endCalendar = Calendar.getInstance()
            endCalendar.time = endTime

            if (currentTime.compareTo(endTime) < 0) {
                currentCalendar.add(Calendar.DATE, 1)
                currentTime = currentCalendar.time
            }

            if (startTime.compareTo(endTime) < 0) {
                startCalendar.add(Calendar.DATE, 1)
                startTime = startCalendar.time
            }

            if (currentTime.before(startTime)) {
                valid = false
            } else {
                if (currentTime.after(endTime)) {
                    endCalendar.add(Calendar.DATE, 1)
                    endTime = endCalendar.time
                }

                if (currentTime.before(endTime)) {
                    valid = true
                } else {
                    valid = false
                }
            }

            // This won't work if day is Thursday and time is 2:00am, even though time falls between 23:00-7:00
            var todayCalendar = Calendar.getInstance()
            if ((currentTime >= startTime && todayCalendar.get(Calendar.DAY_OF_WEEK) in selectedDays.values) &&
                    (currentTime <= endTime && (todayCalendar.get(Calendar.DAY_OF_WEEK) in selectedDays.values || todayCalendar.get(Calendar.DAY_OF_WEEK)-1 in selectedDays.values))) {
                Log.d(TAG, "Days are valid")
            }

            return valid
        }

        return false
    }

How do I handle the days scenario?

tech_human
  • 6,592
  • 16
  • 65
  • 107
  • 1
    Consider throwing away the long outmoded and notoriously troublesome `SimpleDateFormat` and friends, and adding [ThreeTenABP](https://github.com/JakeWharton/ThreeTenABP) to your Android project in order to use `java.time`, the modern Java date and time API. It is so much nicer to work with and will support your task much better. – Ole V.V. Sep 27 '19 at 08:27
  • It seems to me to be a duplicate question. Maybe not of a single previous question, but if you combine for example [Check if a given time lies between two times regardless of date](https://stackoverflow.com/questions/17697908/check-if-a-given-time-lies-between-two-times-regardless-of-date) and [What is the easiest way to get the current day of the week in Android?](https://stackoverflow.com/questions/5574673/what-is-the-easiest-way-to-get-the-current-day-of-the-week-in-android)? – Ole V.V. Sep 27 '19 at 08:31
  • Do I understand correctly? In your example you want the action taken between Monday at 23 and Tuesday at 7 and similarly in the nights between Tuesday and Wednesday and between Wednesday and Thursday? But *not* Monday before 7 and *not* Thursday after 23? – Ole V.V. Sep 27 '19 at 08:34

2 Answers2

1

java.time and ThreeTenABP

Please note: This code can work on Android API levels both under and over level 26. I will explain further down. I will have to trust you to translate from Java code.

If I have understood your requirements correctly:

    ZoneId zone = ZoneId.of("America/Chihuahua");

    LocalTime startTime = LocalTime.of(23, 0);
    LocalTime endTime = LocalTime.of(7, 0);
    Set<DayOfWeek> selectedDays
            = EnumSet.of(DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY);

    ZonedDateTime now = ZonedDateTime.now(zone);
    LocalTime timeNow = now.toLocalTime();
    DayOfWeek currentDayOfWeek = now.getDayOfWeek();
    boolean inIntervalOnDay;
    if (startTime.isAfter(endTime)) { // crosses midnight
        if (timeNow.isBefore(endTime)) { // in interval, after midnight
            // Day is correct if the day before is among the selected days
            inIntervalOnDay = selectedDays.contains(currentDayOfWeek.minus(1));
        } else if (timeNow.isBefore(startTime)) {
            inIntervalOnDay = false;
        } else { // after start time, before midnight
            inIntervalOnDay = selectedDays.contains(currentDayOfWeek);
        }
    } else {
        inIntervalOnDay = ! timeNow.isBefore(startTime)
                && timeNow.isBefore(endTime)
                && selectedDays.contains(currentDayOfWeek);
    }
    System.out.println("Now: " + now + " (" + currentDayOfWeek + ") Valid? " + inIntervalOnDay);

When I ran the snippet just now, the output was:

Now: 2019-09-27T03:47:56.856-06:00[America/Chihuahua] (FRIDAY) Valid? false

Please substitute your desired time zone if it didn’t happen to be America/Chihuahua. Time zone matters.

Question: Can I use java.time on Android below API level 26? How?

Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.

  • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
  • In Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
  • On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

One possible approach could be to normalize all your times to offsets from a chosen week starting point, say Sunday 12:00am = 0. Convert all your times into minutes since the starting point. Then simply check whether your chosen time (also converted to minutes since start) falls within any of the ranges.

Dan Harms
  • 4,725
  • 2
  • 18
  • 28
  • Thanks @dharms! Your approach gave me another idea. Incase if my start time is 23:00 and end time is on next day at 7:00, time in millis for 23:00 will be greater than time in millis at 7:00. I can use that as a check always. If that's the case, from 23:00-23:59:59, I can look into the list of selected days and from 00:00-7:00, I can look into list of selected+1 days. Incase if user start time us 9:00am-5:00pm in this case time in millis of start time is smaller than time in millis of end time. I think this approach might work. – tech_human Sep 26 '19 at 20:59
  • That would definitely work, but may be more complicated to implement than what I've suggested. Ultimately, you are free to do it as you want, and I'm happy to help! – Dan Harms Sep 26 '19 at 21:06