2

I am trying to calculate the sum of a list of time duration for an attendance app. I was able to calculate the difference of 2 times but not sure how to traverse through the list to add the dates together.

The below code is what I have attempted so far. There are 2 time durations in the list and they are added to the list from Firebase using an object class.

Duration 1 = 0:5:42
Duration 2 = 0:0:09
Expected Total = 0:5:51

//initialized

long sum;

//current method attempted

public void grandTotal() throws ParseException {
        java.util.Date date1;
        java.util.Date date2;

        DateFormat formatter = new SimpleDateFormat("hh:mm:ss");
        for(int i = 0 ; i < newList.size(); i++) {
            String str_time1 = newList.get(i).getDuration();
            date1 = formatter.parse(str_time1);

            for (int j = 1; j < newList.size(); j++) {
                String str_time2 = newList.get(j).getDuration();
                date2 = formatter.parse(str_time2);
                sum = date1.getTime() + date2.getTime();
            }
        }
        secs = sum/1000;

        mins = secs/60;
        secs%=60;
        hours = mins/60;
        mins%=60;
        txtDailyBalance.setText(hours+":"+mins+":"+String.format("%02d",secs));
    }

Result output I get is = -1:59:42

I got the solution using this method but I don't think this is good practice so I have been looking into learning more about the different methods in this post so thank you.

//Sum of time durations for that day
public void grandTotal() throws ParseException {
    java.util.Date date1;
    java.util.Date date2;

    DateFormat formatter = new SimpleDateFormat("hh:mm:ss");
    for(int i = 0 ; i < newList.size(); i++) {
        timeDuration.add(newList.get(i).getDuration());
    }
    long tDur = 0;
    for (String tmp : timeDuration){
        String[] arr = tmp.split(":");
        tDur += Integer.parseInt(arr[2]);
        tDur += 60 * Integer.parseInt(arr[1]);
        tDur += 3600 * Integer.parseInt(arr[0]);
    }
    long hours = tDur / 3600;
    tDur %= 3600;
    long mins = tDur / 60;
    tDur %= 60;
    long secs = tDur;
    txtDailyBalance.setText(hours+":"+mins+":"+String.format("%02d",secs));
}
Abra
  • 19,142
  • 7
  • 29
  • 41
James Ferry
  • 127
  • 1
  • 3
  • 12
  • 1
    Consider using `java.time` or `ThreeTenABP` for working with dates. Much easier, more coherent code and less chance for running into these kinds of errors. – M. Prokhorov Feb 08 '18 at 12:16
  • 2
    I'm suggesting this because you seem to have actual durations in the list, whereas you are trying to parse them as dates. This already places a big stretch on correctness of your answer. Another thing is you sum everything with everything in your list several times, which for list larger than 2 elements will get you larger intervals. – M. Prokhorov Feb 08 '18 at 12:32
  • A `Date` is a point in time, it’s not a duration. What you are doing, is wrong. For durations, I recommend `java.time.Duration` (or for older Android `org.threeten.bp.Duration` from ThreeTenABP). It has a `plus` method for adding. – Ole V.V. Feb 08 '18 at 12:57
  • Under all circumstances 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. – Ole V.V. Feb 08 '18 at 12:58

2 Answers2

5

As I have said in the comments, use the Duration class for durations:

    List<Duration> durations = List.of(
            Duration.ofMinutes(5).plusSeconds(42), // 0:05:42
            Duration.ofSeconds(9),                 // 0:00:09
            Duration.parse("PT11M"));              // 0:11:00

    Duration sum = Duration.ZERO;
    for (Duration dur : durations) {
        sum = sum.plus(dur);
    }

    System.out.println(sum);

This prints

PT16M51S

So 16 minutes 51 seconds.

Durations parse and produce ISO 8601 format natively, it goes like what you just saw, PT16M51S. If you need to have your duration strings in hh:mm:ss format, I am sure you can write auxiliary methods for formatting and parsing that format. For formatting there are already a couple of questions on Stack Overflow, for example How to format a duration in java? (e.g format H:MM:SS) (search for more).

Why not Date?

Using a Date for a duration is incorrect. A point in time and an amount of time are two different concepts. The error you saw may be due to time zone offset, but you risk other errors along the way, and worse, your code is difficult to read and easy to misunderstand.

Also the Date class is long outdated and replaced by classes in java.time, the modern Java date and time API. The same API introduces the classes Period (for years, months and days) and Duration (for hours, minutes, seconds and fraction of second).

Question: Can I use java.time on Android?

Yes, you can use java.time on Android. It just requires at least Java 6.

  • In Java 8 and later and on newer Android devices the modern API comes built-in.
  • In Java 6 and 7 get the ThreeTen Backport, the backport of the new 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
  • thanks Ole, i have put a way i got the solution in my question. Thanks for the links as well I will be learning more using them when i want to improve the app – James Ferry Feb 13 '18 at 21:08
1

If you don't insist on having a customized format but just look for an easier way to add duration objects then Oles answer might be okay for you. However, ThreetenABP lacks a duration formatter.

But if you want to avoid writing auxiliary methods for formatting and parsing durations in the format "hh:mm:ss" (and are willing to add a 3rd-party-dependency) then you might try my lib Time4A and use a pattern-based approach:

Duration.Formatter<ClockUnit> parser = Duration.formatter(ClockUnit.class, "#h:#m:ss");
String[] durations = { "0:5:42", "0:0:09" };
Duration<ClockUnit> d = Duration.ofZero();

for (String duration : durations) {
    d = d.plus(parser.parse(duration));
}

d = d.with(Duration.STD_CLOCK_PERIOD); // normalization
Duration.Formatter<ClockUnit> printer = Duration.formatter(ClockUnit.class, "hh:mm:ss");
System.out.println(printer.format(d)); // 00:05:51
Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126