3

How do I get the average of two LocalTimes? Can't find any suitable methods for this.

So for example 08:00 and 14:30, should return (14-8)/2 = 3 + minutes (30-00= 30)/2, so 3:15 And then smth like

Localtime xxx = LocalTime.parse("08:00", formatter).plus(3, ChronoUnit.HOURS); 
//and after that's done
xxx = xxx.plus(15, ChronoUnit.MINUTES);

Now suppose that I have the following code:

   //this means that if code is 08:00, it should look whether the average of Strings split21 and split2 (which are put in time2 and time3, where time2 is ALWAYS before time3) is before 08:00
   if(code1.contains("800")) {

        LocalTime time1 = LocalTime.parse("08:00", formatter);
        LocalTime time2 = LocalTime.parse(split21, formatter);
        LocalTime time3 = LocalTime.parse(split2, formatter);
        LocalTime average = 
        if(time2.isBefore(time1)) {
            return true;
        }
        else {
            return false;
        }
    }

Obviously I can use.getHour and .getMinute , but there are two problems here.

  1. I cannot divide LocalTime (only if working with hours and minutes seperately but honestly that's a bit too medieval
  2. If I don't directly divide the hours and minutes, it will be higher than 24:00 and I've no clue what will happen then: I suppose it goes further with 00:00 etc instead of 36:00 for example.

Is there someone who could finish this code/explain what's wrong?

Youcef LAIDANI
  • 55,661
  • 15
  • 90
  • 140
Not Dutch
  • 49
  • 7
  • 1
    why minus in `(14-8)/2` and plus in `(00+30 = 30)/2` I don't get it! – Youcef LAIDANI Jun 21 '18 at 10:12
  • that is actually a good question, sorry I wrote this very quick. I obviously mean (30-00) – Not Dutch Jun 21 '18 at 10:14
  • what is the average of two Times? how is the average of `8:00` and `14:30` just `3:15`??? I would assume it is `11:15`. or you need the **difference**? that would be `6:30` – user85421 Jun 21 '18 at 11:25
  • I did not say the average is 3:15. You have to add 3:15 to the first time to get the average. Quick maths – Not Dutch Jun 22 '18 at 23:22

5 Answers5

6

Since a LocalTime is effectively defined by the nano seconds since midnight, you can do something like this:

public static LocalTime average(LocalTime t1, LocalTime... others) {
  long nanosSum = t1.toNanoOfDay();
  for (LocalTime other : others) {
    nanoSum += others.toNanoOfDay();
  }
  return LocalTime.ofNanoOfDay(nanoSum / (1+others.length));
}
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
2

The way I am thinking of your question you want the midpoint between your two times. Thinking this way I find it most natural to take the difference between the times, divide by 2 and add to the first time (or subtract from the second). This also seems to be what you tried in the question. Rather than handling hours and minutes yourself use the Duration class:

    LocalTime time1 = LocalTime.of(8, 0);
    LocalTime time2 = LocalTime.of(14, 30);
    Duration diff = Duration.between(time1, time2);
    LocalTime midpoint = time1.plus(diff.dividedBy(2));
    System.out.println(midpoint);

Output:

11:15

It obviously only works for two times, not for three or more. The case of more than two times is handled nicely in a couple of the other answers.

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

I think you mean something like so :

public static LocalTime average(LocalTime time1, LocalTime time2) {
    if (time1.isAfter(time2)) {
        return LocalTime.of(
                time1.plusHours(time2.getHour()).getHour() / 2,
                time1.plusMinutes(time2.getMinute()).getMinute() / 2
        );
    } else {
        return LocalTime.of(
                time2.plusHours(time1.getHour()).getHour() / 2,
                time2.plusMinutes(time1.getMinute()).getMinute() / 2
        );
    }
}

Then you can call your method multiples times :

LocalTime time1 = LocalTime.of(14, 30);
LocalTime time2 = LocalTime.of(8, 00);

LocalTime result = average(time1, time2);

In case of three times for example :

LocalTime time1 = LocalTime.of(14, 30);
LocalTime time2 = LocalTime.of(8, 00);
LocalTime time3 = LocalTime.now();

LocalTime result = average(average(time1, time2), time3);

..and so on

Outputs of first example

11:15
Youcef LAIDANI
  • 55,661
  • 15
  • 90
  • 140
  • 2
    there is no sercuity if time2 < time1 – Arnault Le Prévost-Corvellec Jun 21 '18 at 10:25
  • which security you mean @ArnaultLePrévost-Corvellec? did you check the result of the first example? – Youcef LAIDANI Jun 21 '18 at 10:28
  • for an average : average(time1,time2) == average(time2,time1) in your fonction it is not – Arnault Le Prévost-Corvellec Jun 21 '18 at 10:29
  • if you rune System.out.println(average(time2, time1).format(DateTimeFormatter.ISO_LOCAL_TIME)); System.out.println(average(time1, time2).format(DateTimeFormatter.ISO_LOCAL_TIME)); the result is 03:15:00 09:15:00 – Arnault Le Prévost-Corvellec Jun 21 '18 at 10:30
  • LocalTime average = (time2.plusHours(result.getHour()).plusMinutes(result.getMinute())); Is this correct for average? Where result is from your code – Not Dutch Jun 21 '18 at 10:32
  • @ArnaultLePrévost-Corvellec if you read my post, I ensured that that was ALWAYS the case – Not Dutch Jun 21 '18 at 10:34
  • good point @NotDutch Yes I think I need to check which date is before the other to make the correct operation check My edit – Youcef LAIDANI Jun 21 '18 at 10:34
  • @NotDutch you did'nt say that explicitly pls be more carfully for your next questions ^^ – Arnault Le Prévost-Corvellec Jun 21 '18 at 10:38
  • @YCF_L that seems ok ^^ – Arnault Le Prévost-Corvellec Jun 21 '18 at 10:38
  • for some reason I get the same output as when I tried to write this myself, which was pretty similar lol. It outputs 00:00, while it does actually output correctly when I don't take average, but when I just compare the two times – Not Dutch Jun 21 '18 at 10:38
  • @ArnaultLePrévost-Corvellec I did. Look in the code text "//this means that if code is 08:00, it should look whether the average of Strings split21 and split2 (which are put in time2 and time3, where time2 is ALWAYS before time3) is before 08:00" – Not Dutch Jun 21 '18 at 10:39
  • @NotDutch ok sorry i didnt scroll horizontally your code pls splt the comment in 2 line it's will avoid that some make the same error that me – Arnault Le Prévost-Corvellec Jun 21 '18 at 10:43
  • https://pastebin.com/JSCtYgLM Look, when i use this code or my own written code it always outputs 00:00... While it does NOT when I didn't take the average, but only compared the two times. Strange here is that this process of taking average / comparing is AFTER the if/else statements.... Any ideas? This is the entire class (https://pastebin.com/a6K3pkwc) – Not Dutch Jun 21 '18 at 10:46
  • @NotDutch I can't access to that link can you use https://ideone.com to share you code please? – Youcef LAIDANI Jun 21 '18 at 11:39
  • This Answer is needlessly complicated. The nanoseconds approach seen in [this other Answer](https://stackoverflow.com/a/50966867/642706) is much simpler. – Basil Bourque Jun 21 '18 at 17:08
  • The outputs of first example — I had expected 11:15 as the correct average. I can confirm that I get 3:15, but how can this make sense as average between 14:30 and 08:00? – Ole V.V. Jun 22 '18 at 15:33
  • @OleV.V. this is correct the logic of the OP seems not correct, I edit my answer and put the correct solution – Youcef LAIDANI Jun 22 '18 at 15:36
  • I did not say the average is 3:15. You have to add 3:15 to the first time to get the average. Quick maths – Not Dutch Jun 22 '18 at 23:23
1

You can easily do this with the Java 8 java.time package, using the LocalTime.ofSecondOfDay(long) method. This is effectively the hour and minute (and second) of the day combined.

public static LocalTime average(LocalTime... times) {
    return LocalTime.ofSecondOfDay((long) Arrays.stream(times)
        .mapToInt(LocalTime::toSecondOfDay)
        .average()
        .getAsDouble());
}
LocalTime t1 = LocalTime.of(8, 0);
LocalTime t2 = LocalTime.of(14, 30);
System.out.println(average(t1, t2)); // Prints 11:15
MC Emperor
  • 22,334
  • 15
  • 80
  • 130
0

I have come out with this code considering your comment in the code //(which are put in time2 and time3, where time2 is ALWAYS before time3)

DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_TIME;

    LocalTime time1 = LocalTime.parse("08:00", formatter);
    LocalTime time2 = LocalTime.parse("14:30", formatter);

    int hour1 = time1.get(ChronoField.CLOCK_HOUR_OF_DAY);
    int hour2 = time2.get(ChronoField.CLOCK_HOUR_OF_DAY);

    int min1 = time1.get(ChronoField.MINUTE_OF_HOUR);
    int min2 = time2.get(ChronoField.MINUTE_OF_HOUR);

    int avgHour = (hour2-hour1)/2;
    int avgMin = (min2-min1)/2;

    String newavgHour = "00:00";
    if(String.valueOf(avgHour).length() == 1) {
        newavgHour = "0"+avgHour+":00";
    } else {
        newavgHour = avgHour+":00";
    }

    LocalTime avgTime = LocalTime.parse(newavgHour, formatter).plus(avgMin, ChronoUnit.MINUTES);
    System.out.println(avgTime);
  • 1
    thats a very broken code LOL gotta love it, I'm not here to get such responses as I'm able to do this myself as well. – Not Dutch Jun 21 '18 at 11:38
  • I tried your code with times `09:45` and `14:30`. Expected average: 12:07:30. Actual output: 01:53. – Ole V.V. Jun 22 '18 at 12:50