0

I have an array of cell[] containing all classes for a student ID, each cell has two variables relevant to this context: int day and int startTime. I also have two given values for the currentDay and currentTime, both in the same format as cell's day and startTime

I want to make a loop that finds the cell element that contains the next class.

I've tried looping through the cell array and selecting the closest day that contains at least one class, with some success, and I imagine that I would need to make another array that contains all the classes for that day then do the same logic to them. I just can't figure out how.

public Cell getNextClass(int studentID, Context context){
      DBHelper dbHelper = new DBHelper(context);

      Cell[] cell = dbHelper.queryCellData(studentID);

      Date currentTime = Calendar.getInstance().getTime();

      int currentDay = getCurrentDay(currentTime.toString());
      Log.d(TAG, "currentDay: " + currentDay);

      DateFormat dateFormat = new SimpleDateFormat("hh a");
      String formattedDate= dateFormat.format(currentTime);
      int currentHour = getCurrentHour(formattedDate);

      //TODO Find next class given currentDay and currentHour

      Cell nextClass = cell[0];

      for (int i = 0; i < cell.length; i++) {
         if (cell[i].getDay() >= currentDay && cell[i].getDay() <= nextClass.getDay()){
            //?????
         }
      }
      return nextClass;
   }
 }

In this example, cell[0] has one class on hour 12, and is displayed by default because the loop doesn't change anything. However at time of posting in NZ the values would be:

    currentDay = 2
    currentHour = 21

As shown in this screenshot of my timetable: i.imgur.com/X6HzR6y.png

The next class will be tomorrow, day 3, hour 8.

Asad Ali Choudhry
  • 4,985
  • 4
  • 31
  • 36
  • Please don't use `int` to represent time or date. Use the proper classes provided by `java` for this. Then you can use build in methods to solve you problems. – Jocke Jun 19 '19 at 09:47
  • @Jocke I realise this, but the values used in ```Cell``` object are also integers, do you know of any built in methods to convert this so I can compare? I can't store the day and hour in ```Cell``` as anything other than ```int``` for the purpose of displaying the table in the screenshot. – DigitalJesus Jun 19 '19 at 10:14
  • you should use DateTime or OffsetDateTime in the cell class, then if you need to the displaying the schema have a methods that return the int value for day and hour. And the DateTime classes have methods for that – Jocke Jun 19 '19 at 10:18
  • @Jocke Does DateTime have the ability to store based upon a day of the week / time of day like I have in the cell class? The class seems to be overloaded for the scope of my app and would require much rewriting of core methods to implement. It would be so much easier to either convert the values given from ```cell``` into a workable format, or find an algorithm that does it using the integer values like in my original question. – DigitalJesus Jun 19 '19 at 10:42
  • As an aside consider throwing away the long outmoded and notoriously troublesome `DateFormat` 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. – Ole V.V. Jun 19 '19 at 14:29
  • Related: [How do you compare Day of week and Time in Java](https://stackoverflow.com/questions/43722150/how-do-you-compare-day-of-week-and-time-in-java) – Ole V.V. Jun 19 '19 at 15:25

3 Answers3

1

Here is a good entry point for you: https://docs.oracle.com/javase/tutorial/datetime/iso/index.html

I do understand that you don't want to change your code. But since your application deals with dates and time it should use the build in api's the java language gives you. Just try to introduce it a controlled and testable way. The String class is also massive, but I bet you use that one, and not your own implementation.

Jocke
  • 2,189
  • 1
  • 16
  • 24
1

I recommend that you use java.time classes for the fields of your Cell class, not int:

public class Cell {
    DayOfWeek day;
    LocalTime startTime;

    // Constructor, getters, toString, etc.
}

Also if you can, fit your class with a method that given a day of week and time calculates how long it is until the class occurs next time:

    public Duration getTimeUntilNext(DayOfWeek currentDay, LocalTime currentTime) {
        int daysUntil = day.getValue() - currentDay.getValue();
        Duration time = Duration.ofDays(daysUntil).plus(Duration.between(currentTime, startTime));
        if (time.isNegative()) { // over for this week
            // Calculate time until next week’s occurrence
            time = time.plusDays(7);
            assert ! time.isNegative() : time;
        }
        return time;
    }

If you cannot add this method to the Cell class, you may declare it a static method somewhere else and just add the cell as an extra parameter.

Now the rest is not so bad:

    Cell[] classes = new Cell[] {
            new Cell(DayOfWeek.THURSDAY, LocalTime.of(12, 0)),
            new Cell(DayOfWeek.MONDAY, LocalTime.of(14, 0)),
            new Cell(DayOfWeek.THURSDAY, LocalTime.of(10, 0)),
            new Cell(DayOfWeek.FRIDAY, LocalTime.of(9, 0)),
            new Cell(DayOfWeek.THURSDAY, LocalTime.of(6, 0))
    };
    ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Pacific/Auckland"));
    final DayOfWeek currentDay = now.getDayOfWeek();
    final LocalTime currentTime = now.toLocalTime();
    Comparator<Cell> comparatorByTimeUntilNext = new Comparator<Cell>() {

        @Override
        public int compare(Cell c1, Cell c2) {
            return c1.getTimeUntilNext(currentDay, currentTime)
                    .compareTo(c2.getTimeUntilNext(currentDay, currentTime));
        }
    };
    Cell nextClass = Collections.min(Arrays.asList(classes), comparatorByTimeUntilNext);
    System.out.println("Next class from " + now + " is " + nextClass);

When I ran this just now, it output:

Next class from 2019-06-20T06:49:23.188+12:00[Pacific/Auckland] is THURSDAY at 10:00

Even if you stick with int fields in your class, you should still be able to use the idea. Then getTimeUntilNext may either still return a Duration or an int denoting the number of hours. I recommend the former, of course.

It seems to me that your code was formatting the current date and time into two different strings and parsing each of them back to get the day and time. That’s certainly the detour. Also as I already said in a comment, I recommend you avoid Date, Calendar, DateFormat and SimpleDateFormat since they are all poorly designed and long outdated.

Question: Can I use java.time on Android?

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

Thank you for your reference, @Jocke however, I found my own way of doing it (poorly), so for posterity and the sake of any poor student who coded themselves into the same situation as me, I just added a bunch of messy edge cases for how time works in looped week scenarios like timetables. I will be using default libraries when possible in the future. Don't you worry. Here's the final method that I used.

public Cell getNextClass(int studentID, Context context){
      DBHelper dbHelper = new DBHelper(context);

      Cell[] cell = dbHelper.queryCellData(studentID);

      Date currentTime = Calendar.getInstance().getTime();

      int currentDay = getCurrentDay(currentTime.toString());
      Log.d(TAG, "currentDay: " + currentDay);

      DateFormat dateFormat = new SimpleDateFormat("hh a");
      String formattedDate= dateFormat.format(currentTime);
      int currentHour = getCurrentHour(formattedDate);

      ArrayList<Cell> classesInDay = new ArrayList<>();

      if (currentHour >= 17){
         currentDay++;          //If the current hour is past the end of the day, add 1 to the day so that tomorrow is scanned.
      }
      if (currentDay > 4){
         currentDay = 0;       //If the current day is greater than 4 (the weekend) set day to monday.
      }

      for (int i = 0; i < cell.length; i++) {
         if (cell[i].getDay() == currentDay){
            Log.d(TAG, "getNextClass: cell " + i +" has a class today");
            classesInDay.add(cell[i]);
         }
      }

      Cell nextClass = classesInDay.get(0);

      Log.d(TAG, "getNextClass: "+classesInDay.size());

      //If today's classes are over, then search tomorrow.
      if (classesInDay.size() == 1 && classesInDay.get(0).getStartTime() < currentHour){
         classesInDay.clear();
         currentDay++;
         for (int i = 0; i < cell.length; i++) {
            if (currentDay > 4){
               currentDay = 0;       //If the current day is greater than 4 (the weekend) set day to monday.
            }
            if (cell[i].getDay() == currentDay){
               Log.d(TAG, "getNextClass: cell " + i +" has a class today");
               classesInDay.add(cell[i]);
            }
         }
         nextClass = classesInDay.get(0); //ReApply default class for new day
      }

      for (int i = 1; i < (classesInDay.size()) ; i++) {
         int diff1 = classesInDay.get(i).getStartTime() - currentHour-1; //Minus one to ensure that the next class if found, not the current one.
         int diff2 = nextClass.getStartTime() - currentHour-1;

         Log.d(TAG, "diff1: "+diff1+" diff2: "+diff2);

         if (diff1 < 0){                     //This means that the Test cell is before the current hour

         }else if(diff2 < 0){                //This means that the current choice is before the current hour
            nextClass = classesInDay.get(i);
         }else if (diff1 < diff2){           //This means that the test cell is closer to the current hour than the current choice
            nextClass = classesInDay.get(i);
         }else if (diff2 < diff1){           //This means that the current choice is closer to the current hour than the test cell

         }
      }
      return nextClass;
   }