如何在下午4点和凌晨2点之间的两个时间生成随机时间?
我试过使用 -
int startSeconds = restaurant.openingTime.toSecondOfDay();
int endSeconds = restaurant.closingTime.toSecondOfDay();
LocalTime timeBetweenOpenClose = LocalTime.ofSecondOfDay(ThreadLocalRandom.current().nextInt(startSeconds, endSeconds));
但这通常会遇到错误,如 nextInt(origin, bounds), origin 不能小于 bounds,如果 myopeningTime是 16:00:00 和closingTime02:00:00 ,则会发生这种情况。
回答
您可以添加一天的秒数 ( 24*60*60) 当startSeconds大于时endSeconds表示第二天的秒数,并在获得随机数以一天的秒数取模后,通过有效的秒值将其转换为 LocalTime。
int secondsInDay = (int)Duration.ofDays(1).getSeconds();
if(startSeconds > endSeconds){
endSeconds += secondsInDay;
}
LocalTime timeBetweenOpenClose = LocalTime.ofSecondOfDay(
ThreadLocalRandom.current().nextInt(startSeconds, endSeconds) % secondsInDay);
回答
如果不应用日期和时区,我们无法知道从下午 4 点到凌晨 2 点之间将经过多长时间。因此,我们将使用 解决它ZonedDateTime。
- 第一步将是:
ZonedDateTime通过调用获取LocalDate#atStartOfDay
ZoneId zoneId = ZoneId.systemDefault();
LocalDate.now().atStartOfDay(zoneId);
- 接下来,使用
ZonedDateTime#with获取ZonedDateTime具有指定时间的 a。 - 现在,您可以
Instant从ZonedDateTimeusing派生ZonedDateTime#toInstant。 - 一旦以
Instant这种方式导出start 和 end s,就可以使用ThreadLocalRandom.current().nextLong生成longstart 和 endInstants范围内的值,并使用获得的值来获取所需的Instant. - 最后,您可以
ZonedDateTime从这个Instantusing派生 aInstant#atZone,然后使用获得所需的时间ZonedDateTime#toLocalTime。
演示:
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);
}
}
从Trail: Date Time 中了解有关现代日期时间 API 的更多信息。
ONLINE DEMO 随机打印 100 次。
- @VaibhavAgrawal A `ZonedDateTime` is a date and time in a time zone. If you want the time for a particular day and it needs to work correctly in all time zones, then you need this because it takes DST transitions and other time line anomalies into account. An `Instant` is a plain point in time (as the name says). The code converts from `LocalTime` to `ZonedDateTime` to `Instant` to milliseconds in order to do the math on the milliseconds values, then converts back to `Instant` to `ZonedDateTime` to `LocalTime`.
-
That's neat @OleV.V. I am getting it now..Thanks!!
And the issue of _origin less than bounds_ gets solved because EpochMilli returns the number of milliseconds from the epoch of _1970-01-01T00:00:00Z_.
Although 4 PM and 2 AM were just examples so rather than hardcoding values `LocalTime.of(16, 0)` instead `restaurant.openingTime` can be used. And `ZonedDateTime zdtEnd = today.plusDays(1).atStartOfDay(zoneId).with(LocalTime.of(2, 0));` can be checked using if condition so that if closingTime falls within same day i.e. `if (openingTime.isBefore(closingTime))` then `plusDays(1)` can be removed.