Sum hours and minutes together Java

1.1k views Asked by At

Summing hours and minutes together results in the wrong answer.

Here are 2 lists with hours.

[[0 hours : 0 mins : 0 sec, 1 hours : 16 mins : 22 sec, 0 hours : 1 mins : 53 sec, 23 hours : 54 mins : 18 sec], [0 hours : 8 mins : 22 sec, 0 hours : 8 mins : 22 sec, 0 hours : 8 mins : 22 sec]]this is HOURS

Then, I divide it into sublists, to calculate for each. Here is one of the sublists.

[0 hours : 0 mins : 0 sec, 1 hours : 16 mins : 22 sec, 0 hours : 1 mins : 53 sec, 23 hours : 54 mins : 18 sec]

So, the answer I get for this sublist is: 1 hours:12 minutes:33 seconds, which is incorrect. I suppose to get around 25 hours plus a few minutes.

public List<String> getTheHoursWorked() {
    DateTimeFormatter parser = DateTimeFormatter.ofPattern("H 'hours :' m 'mins :' s 'sec'", Locale.US);
    final DateFormat dt = new SimpleDateFormat("HH:mm:ss");
    final Calendar c = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault());

    c.clear();
    long startingMS = c.getTimeInMillis();
    int counter = 0;

    for (int k = 0; k < hours.size(); k++){
        List<Object> shorter = new ArrayList<>();
        List<Object> temp;
        temp = (List<Object>) hours.get(k);
        
        long milliseconds = 0;
        for (int m = 0; m < shorter.size(); m++) {
            LocalTime odt = LocalTime.parse((CharSequence) shorter.get(m), parser);
            DateTimeFormatter formatter =
                    DateTimeFormatter.ofPattern("HH:mm:ss");
            String printDate = formatter.format(odt);
            try {
                milliseconds = milliseconds + (dt.parse(printDate).getTime() - startingMS);
                System.out.println(milliseconds + "MILISECONDS");
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        hoursToString.add(String.valueOf(shorter));
        String s = milliseconds / 1000 % 60   + " seconds";
        String m = milliseconds /(60 * 1000) % 60 + " minutes";
        String h = milliseconds / (60 * 60 * 1000) % 24 + " hours";
        String together = h+":"+m+":"+s;
        togetherHours.add(together);
    }
    return togetherHours;
}
3

There are 3 answers

0
Arvind Kumar Avinash On BEST ANSWER

The steps of the solution should be

  1. Start with a time of 0:0
  2. Iterate the list and add all hours, minutes and seconds separately after parsing the time strings using the corresponding formatter.
  3. Adjust hour, minutes and seconds if minute and/or second exceed 60.

Demo:

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> list = List.of("0 hours : 0 mins : 0 sec", "1 hours : 16 mins : 22 sec",
                "0 hours : 1 mins : 53 sec", "23 hours : 54 mins : 18 sec");

        // Start with a time of 0:0
        int sumHours = 0;
        int sumMinutes = 0;
        int sumSeconds = 0;

        // Iterate the list and add all hours, minutes and seconds separately after
        // parsing the time strings using the corresponding formatter
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("H' hours : 'm' mins : 's' sec'");
        for (String strTime : list) {
            LocalTime time = LocalTime.parse(strTime, timeFormatter);
            sumHours += time.getHour();
            sumMinutes += time.getMinute();
            sumSeconds += time.getSecond();
        }

        // Adjust hour, minutes and seconds if minute and/or second exceed 60
        sumMinutes += sumSeconds / 60;
        sumSeconds %= 60;
        sumHours += sumMinutes / 60;
        sumMinutes %= 60;

        String strSum = String.format("%d hours : %d mins : %d sec", sumHours, sumMinutes, sumSeconds);
        System.out.println(strSum);
    }
}

Output:

25 hours : 12 mins : 33 sec
0
WJS On

One way to approach this is to use Duration. Convert each time value to a duration and then sum them. The supplied time values are shown in an array of two strings.

String[] hours = {
        "0 hours : 0 mins : 0 sec, 1 hours : 16 mins : 22 sec, 0 hours : 1 mins : 53"
                + "sec, 23 hours : 54 mins : 18 sec",
        "0 hours : 8 mins : 22 sec, 0 hours : 8"
                + " mins : 22 sec, 0 hours : 8 mins : 22 sec" };

The conversion is done using streams. The process is explained in the comments.

List<Duration> times = Arrays.stream(hours)
        // remove all the spaces in each string
        .map(str -> str.replaceAll("\\s+", ""))

        // split each string on the commas.  At this
        // point, each string is processed independently
        // of the other in a separate stream
        .map(str -> Arrays.stream(str.split(","))
                
                // parse the time
                .map(tm -> LocalTime.parse(tm,
                        DateTimeFormatter.ofPattern(
                                "H'hours':m'mins':s'sec'")))

                // convert each time to a duration
                .map(lt -> Duration
                        .between(LocalTime.of(0, 0, 0), lt))

                // sum the durations
                .reduce(Duration.ZERO, (a, b) -> a.plus(b)))
        // and collect in a list
        .collect(Collectors.toList());

At this point you can print the durations in the standard Duration format.

times.forEach(System.out::println);

Prints

PT25H12M33S
PT25M6S

To print them in a more familiar format, the following lambda can be used.

Function<Duration, String> durationToString = d -> {
    StringBuilder timeString = new StringBuilder();   
    long h = d.toDaysPart()*24+d.toHoursPart();
    timeString.append(h == 1 ? (h + " hour ") : h > 1 ?  (h + " hours ") : "");
    long m = d.toMinutesPart();
    timeString.append(m == 1 ? (m + " minute ") : m > 1 ? (m + " minutes ") : "");
    long s = d.toSecondsPart();
    timeString.append(s == 1 ? (s + " second ") : s > 1 ? (s + " seconds ") : "");
    return timeString.toString();
};

Prints

25 hours 12 minutes 33 seconds 
25 minutes 6 seconds 
0
SkateScout On
  1. The logical error in your routine is %24 so you remove full days.

  2. Your code contain many useless parts like temp and is not clean.

  3. Building an parser in an loop is an very bad style.

  4. You do very much stuff that is not required and the working with milliseonds and calendar is useless. Here are two versions that return the expected result. Second is for newer java versions.

     public static List<String> getTheHoursWorked() {
     final DateTimeFormatter parser = DateTimeFormatter.ofPattern("H 'hours :' m 'mins :' s 'sec'", Locale.US);
     final List<String> togetherHours = new LinkedList<>();
     for (int k = 0; k < hours.size(); k++){
         final List<String> shorter = hours.get(k);
         long seconds = 0;
         for (int m = 0; m < shorter.size(); m++) {
             final LocalTime odt = LocalTime.parse(shorter.get(m), parser);
             seconds += odt.getHour() * 3600 + odt.getMinute() * 60 + odt.getSecond();
         }
         final String s = (seconds       ) % 60 + " seconds";
         final String m = (seconds /   60) % 60 + " minutes";
         final String h = (seconds / 3600)      + " hours";
         final String together = h+":"+m+":"+s;
         togetherHours.add(together);
     }
     return togetherHours;
     }
    
     public static List<String> getTheHoursWorked_new() {
     final DateTimeFormatter parser = DateTimeFormatter.ofPattern("H 'hours :' m 'mins :' s 'sec'", Locale.US);
     final List<String> togetherHours = new LinkedList<>();
     for (final var shorter: hours){
         long seconds = 0;
         for (final var duration : shorter) {
             final LocalTime odt = LocalTime.parse(duration, parser);
             seconds += odt.getHour() * 3600 + odt.getMinute() * 60 + odt.getSecond();
         }
         final String s = (seconds       ) % 60 + " seconds";
         final String m = (seconds /   60) % 60 + " minutes";
         final String h = (seconds / 3600)      + " hours";
         final String together = h+":"+m+":"+s;
         togetherHours.add(together);
     }
     return togetherHours;
     }