Search code examples
javaroundingdurationzoneddatetime

How to round a ZonedDateTime to a Duration


I have a ZonedDateTime stored in a timeStamp variable.

I also have a Duration barDuration that can be one minute, 5 minutes, 15 minutes, one hour, 6 hours or one day.

I'm plotting a candle chart which width is barDuration.

If the bar duration is set to 1 minute, I need that bars to start at a round minute (e.g. 9:43:00).

If it is set to 5 minutes, I need the bars to start at 9:45, 9:50, 9:55 etc.

If is is set to 15 minutes, then the bars start at 9:45, 10:00, 10:15, etc.

When barDuration is 1 minute, I know I can compute the end time of the bar using:

timeStamp.truncatedTo(ChronoUnit.MINUTES).plus(barDuration)

But this is hard-coded and I want to use the barDuration directly to perform the truncation. How can this be done?

Edit:

I found here a solution with Clocks:

Clock baseClock = Clock.tickMinutes(timeStamp.getZone());
Clock barClock = Clock.tick(baseClock, barDuration);
LocalDateTime now =  LocalDateTime.now(barClock);
LocalDateTime barEndTime =  now.plus(barDuration);

This would work, but it is not based to my timeStamp, but on using LocalDateTime.now(), which is not what I want (I'm not sure the local time on my machine is synchronized with the timestamp I retrieve from a remote server).


Solution

  • As a humble supplement to JB Nizets answer here’s (EDIT:) a Java 9 version that is more time unit neutral.

    static ZonedDateTime truncateToDuration(ZonedDateTime zonedDateTime, Duration duration) {
        ZonedDateTime startOfDay = zonedDateTime.truncatedTo(ChronoUnit.DAYS);
        return startOfDay.plus(duration.multipliedBy(
                Duration.between(startOfDay, zonedDateTime).dividedBy(duration)));
    }
    

    I have not tested thoroughly, but I expect it to work with rounding to for example 500 nanos too. I divide the duration since start of day with the duration to round to, and immediately multiply back, just to obtain a whole number of that duration.

    Funny results will probably occur if your duration doesn’t divide into an hour, or your day starts on something else than a whole hour (if that occurs at all).