Vaibhav Agrawal
Vaibhav Agrawal

Reputation: 81

How to generate a random time between two times say 4PM and 2AM?

I have tried using -

int startSeconds = restaurant.openingTime.toSecondOfDay();
int endSeconds = restaurant.closingTime.toSecondOfDay();
LocalTime timeBetweenOpenClose = LocalTime.ofSecondOfDay(ThreadLocalRandom.current().nextInt(startSeconds, endSeconds));

But this usually runs into an error as in nextInt(origin, bounds), origin can't be less than bounds which will happen if my openingTime is 16:00:00 and closingTime is 02:00:00.

Upvotes: 7

Views: 959

Answers (2)

Eklavya
Eklavya

Reputation: 18430

You can add the seconds of one day(24*60*60) when startSeconds is greater than endSeconds to represent the next day's second and after getting a random number modulo it by the seconds of one day to convert it into LocalTime by a valid second value.

int secondsInDay = (int)Duration.ofDays(1).getSeconds();
if(startSeconds > endSeconds){
  endSeconds += secondsInDay;
}
LocalTime timeBetweenOpenClose = LocalTime.ofSecondOfDay(
              ThreadLocalRandom.current().nextInt(startSeconds, endSeconds) % secondsInDay);

Upvotes: 5

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79075

We cannot know how much time will elapse between 4 PM and 2 AM without applying a date and time zone. Therefore, we will solve it using ZonedDateTime.

  1. The first step will be: obtain a ZonedDateTime by calling LocalDate#atStartOfDay
ZoneId zoneId = ZoneId.systemDefault();
LocalDate.now().atStartOfDay(zoneId);
  1. Next, use ZonedDateTime#with to get a ZonedDateTime with the specified time.
  2. Now, you can derive an Instant from a ZonedDateTime using ZonedDateTime#toInstant.
  3. Once you have the start and end Instants derived this way, you can use ThreadLocalRandom.current().nextLong to generate a long value in the range of the start and the end Instants and use the obtained value to get the required Instant.
  4. Finally, you can derive a ZonedDateTime from this Instant using Instant#atZone and then get the required time using ZonedDateTime#toLocalTime.

Demo:

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.concurrent.ThreadLocalRandom;

public class Main {
    public static void main(String[] args) {
        // Change it as per the applicable timezone e.g. ZoneId.of("Europe/London")
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDate today = LocalDate.now();
        
        ZonedDateTime zdtStart = today.atStartOfDay(zoneId)
                                      .with(LocalTime.of(16, 0));
        
        ZonedDateTime zdtEnd = today.plusDays(1)
                                    .atStartOfDay(zoneId)
                                    .with(LocalTime.of(2, 0));
        
        ZonedDateTime zdtResult = 
                Instant.ofEpochMilli(
                            ThreadLocalRandom
                            .current()
                            .nextLong(
                                        zdtStart.toInstant().toEpochMilli(), 
                                        zdtEnd.toInstant().toEpochMilli()
                                    )
                        ).atZone(zoneId);
        
        LocalTime time = zdtResult.toLocalTime();
        System.out.println(time);
    }
}

Learn more about the modern date-time API from Trail: Date Time.

ONLINE DEMO printing 100 random times.

Upvotes: 5

Related Questions