49

So I'm lucky enough to use Java 8 and the new time APi but I don't see any rounding functions...

Basically if the time is...

2014-08-28T10:01.00.000 ----> 2014-08-28T10:02.00.000
2014-08-28T10:01.10.123 ----> 2014-08-28T10:02.00.000
2014-08-28T10:01.25.123 ----> 2014-08-28T10:02.00.000
2014-08-28T10:01.49.123 ----> 2014-08-28T10:02.00.000
2014-08-28T10:01.59.999 ----> 2014-08-28T10:02.00.000

This seems to be ok, but is it right?

LocalDateTime now =  LocalDateTime.now(Clock.systemUTC());
LocalDateTime newTime =  now.plusMinutes(1);

System.out.println(newTime.toString());
System.out.println(newTime.format(DateTimeFormatter.ofPattern("yyyy-dd-MM'T'HH:mm:00.000")));
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
user432024
  • 4,392
  • 8
  • 49
  • 85

3 Answers3

76

The java.time API does not support rounding to ceiling, however it does support rounding to floor (truncation) which enables the desired behaviour (which isn't exactly rounding to ceiling):

LocalDateTime now =  LocalDateTime.now();
LocalDateTime roundFloor =  now.truncatedTo(ChronoUnit.MINUTES);
LocalDateTime roundCeiling =  now.truncatedTo(ChronoUnit.MINUTES).plusMinutes(1);

In addition, there is a facility to obtain a clock that only ticks once a minute, which may be of interest:

Clock minuteTickingClock = Clock.tickMinutes(ZoneId.systemDefault());
LocalDateTime now =  LocalDateTime.now(minuteTickingClock);
LocalDateTime roundCeiling =  now.plusMinutes(1);

This clock will automatically truncate minutes to floor (although it is specified such that it may return a delayed cached value). Note that a Clock may be stored in a static variable if desired.

Finally, if this is a common operation that you want to use in multiple places, it is possible to write a library TemporalAdjuster function to perform the rounding. (Adjusters can be written once, tested, and made available as a static variable or method).

JodaStephen
  • 60,927
  • 15
  • 95
  • 117
  • Thanks it's what I need. I know my rounding is a bit weird, but basically I need to query my db system based on the current time. If I have multiple users making a query within the current minute with the rounding up i can cache the filter! :) – user432024 Aug 28 '14 at 22:06
  • 16
    This algorithm would be incorrect for exact-minute times. E.g. let's say the current time is exactly 5 minutes (i.e. 0 seconds, 0 nanos, etc). In that case I would expect roundCeiling to be 5 minutes (i.e. like the ceiling of "1.00" decimal number is "1") - but the algorithm would give 6 minutes. roundCeiling calculation above should check if the truncated value is the same as 'now' - in that case return 'now', otherwise the +1 minutes. – andrius.velykis Nov 18 '17 at 20:07
  • 1
    Although now I noticed that the original question asks to always round up (even if the number is already round), so the accepted answer is correct in that case. – andrius.velykis Nov 19 '17 at 10:35
6
LocalDateTime newTime = now.plusMinutes(1).minusNanos(1).withSecond(0).withNano(0);

This will round up to the nearest minute, acting as a ceiling function with minutes as the integer part.

Sean Van Gorder
  • 3,393
  • 26
  • 26
  • Where is the simplification? Writing complex `TemporalAdjuster`-implementations should in most cases be limited to frameworks or library writers, not end users. Here the burden to write the adjuster-code is still with the user. Just my 2 cents... – Meno Hochschild Aug 28 '14 at 16:44
  • @Meno Hochschild: You're right, I was digging through java.time for relevant functionality and wound up in library writing mode. Definitely overkill for this problem. – Sean Van Gorder Aug 28 '14 at 17:07
2

java.time (the new time API in Java 8) has no rounding features like some other libraries. You try to use formatting to round on String-level. If you want to round the time objects however, then you can do this rounding manually:

LocalDateTime now =  LocalDateTime.now(Clock.systemUTC());
LocalDateTime newTime =  now.plusMinutes(1).withSecond(0).withNano(0);

By the way, you surely meant floor, not ceiling, isn't it?

Update:

I have found this slightly better way for setting to floor (obviously the only rounding feature, ceiling is not supported):

LocalDateTime now =  LocalDateTime.now(Clock.systemUTC());
LocalDateTime newTime =  now.plusMinutes(1).truncatedTo(ChronoUnit.MINUTES);
Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126