1. Overview
1.概述
In this tutorial, we’re going to see how to generate random dates and times in bounded and unbounded fashions.
在本教程中,我们将看到如何以有界和无界的方式生成随机日期和时间。
We’ll be looking at how to generate these values using the legacy java.util.Date API and also the new date-time library from Java 8.
我们将研究如何使用传统的java.util.Date API 以及 Java 8 的新的日期时间库来生成这些值。
2. Random Date and Time
2.随机日期和时间
Dates and times are nothing more than 32-bit integers compared to an epoch time, so we can generate random temporal values by following this simple algorithm:
日期和时间与epoch time相比,不过是32位的整数,所以我们可以按照这个简单的算法来生成随机的时间值。
- Generate a random 32-bit number, an int
- Pass the generated random value to an appropriate date and time constructor or builder
2.1. Bounded Instant
2.1.有边界的瞬时
java.time.Instant is one of the new date and time additions in Java 8. They represent instantaneous points on the time-line.
java.time.Instant是Java 8中新增的日期和时间之一。它们代表时间线上的瞬时点。
In order to generate a random Instant between two other ones, we can:
为了在其他两个人之间产生一个随机的Instant,我们可以。
- Generate a random number between the epoch seconds of the given Instants
- Create the random Instant by passing that random number to the ofEpochSecond() method
public static Instant between(Instant startInclusive, Instant endExclusive) {
long startSeconds = startInclusive.getEpochSecond();
long endSeconds = endExclusive.getEpochSecond();
long random = ThreadLocalRandom
.current()
.nextLong(startSeconds, endSeconds);
return Instant.ofEpochSecond(random);
}
In order to achieve more throughput in multi-threaded environments, we’re using the ThreadLocalRandom to generate our random numbers.
为了在多线程环境中实现更多的吞吐量,我们使用ThreadLocalRandom来生成我们的随机数。
We can verify that the generated Instant is always greater than or equal to the first Instant and is less than the second Instant:
我们可以验证,生成的Instant总是大于或等于第一个Instant,小于第二个Instant:。
Instant hundredYearsAgo = Instant.now().minus(Duration.ofDays(100 * 365));
Instant tenDaysAgo = Instant.now().minus(Duration.ofDays(10));
Instant random = RandomDateTimes.between(hundredYearsAgo, tenDaysAgo);
assertThat(random).isBetween(hundredYearsAgo, tenDaysAgo);
Remember, of course, that testing randomness is inherently non-deterministic and is generally not recommended in a real application.
当然,请记住,测试随机性本身就是非决定性的,一般不建议在实际应用中使用。
Similarly, it’s also possible to generate a random Instant after or before another one:
同样地,也可以在另一个人之后或之前生成一个随机的Instant。
public static Instant after(Instant startInclusive) {
return between(startInclusive, Instant.MAX);
}
public static Instant before(Instant upperExclusive) {
return between(Instant.MIN, upperExclusive);
}
2.2. Bounded Date
2.2.有边界的日期
One of the java.util.Date constructors take the number of milliseconds after the epoch. So, we can use the same algorithm to generate a random Date between two others:
其中一个java.util.Date构造器取的是历时后的毫秒数。因此,我们可以使用相同的算法来生成一个介于两个其他的随机Date。
public static Date between(Date startInclusive, Date endExclusive) {
long startMillis = startInclusive.getTime();
long endMillis = endExclusive.getTime();
long randomMillisSinceEpoch = ThreadLocalRandom
.current()
.nextLong(startMillis, endMillis);
return new Date(randomMillisSinceEpoch);
}
Similarly, we should be able to verify this behavior:
同样地,我们应该能够验证这种行为。
long aDay = TimeUnit.DAYS.toMillis(1);
long now = new Date().getTime();
Date hundredYearsAgo = new Date(now - aDay * 365 * 100);
Date tenDaysAgo = new Date(now - aDay * 10);
Date random = LegacyRandomDateTimes.between(hundredYearsAgo, tenDaysAgo);
assertThat(random).isBetween(hundredYearsAgo, tenDaysAgo);
2.3. Unbounded Instant
2.3.无界的Instant
In order to generate a totally random Instant, we can simply generate a random integer and pass it to the ofEpochSecond() method:
为了生成一个完全随机的Instant,我们可以简单地生成一个随机的整数并将其传递给ofEpochSecond()方法。
public static Instant timestamp() {
return Instant.ofEpochSecond(ThreadLocalRandom.current().nextInt());
}
Using 32-bit seconds since the epoch time generates more reasonable random times, hence we’re using the nextInt() method here.
使用32位的秒,因为纪元时间会产生更合理的随机时间,因此我们在这里使用nextInt()方法。
Also, this value should be still between the minimum and maximum possible Instant values that Java can handle:
另外,这个值应该仍然在Java可以处理的最小和最大可能的Instant值之间。
Instant random = RandomDateTimes.timestamp();
assertThat(random).isBetween(Instant.MIN, Instant.MAX);
2.4. Unbounded Date
2.4.无界的Date
Similar to the bounded example, we can pass a random value to Date’s constructor to generate a random Date:
与有界的例子类似,我们可以向Date的构造器传递一个随机值,以生成一个随机的Date:。
public static Date timestamp() {
return new Date(ThreadLocalRandom.current().nextInt() * 1000L);
}
Since the constructor’s time unit is milliseconds, we’re converting the 32-bit epoch seconds to milliseconds by multiplying it by 1000.
由于 构造器的时间单位是毫秒,所以我们要通过乘以1000来将32位纪元秒转换为毫秒。
Certainly, this value is still between the minimum and maximum possible Date values:
当然,这个值仍然在最小和最大可能的Date值之间。
Date MIN_DATE = new Date(Long.MIN_VALUE);
Date MAX_DATE = new Date(Long.MAX_VALUE);
Date random = LegacyRandomDateTimes.timestamp();
assertThat(random).isBetween(MIN_DATE, MAX_DATE);
3. Random Date
3. 随机日期
Up until now, we generated random temporals containing both date and time components. Similarly, we can use the concept of epoch days to generate random temporals with just date components.
到目前为止,我们生成的随机时态同时包含了日期和时间成分。同样地,我们可以使用纪元日的概念来生成只包含日期成分的随机时间。
An epoch day is equal to the number of days since the 1 January 1970. So in order to generate a random date, we just have to generate a random number and use that number as the epoch day.
一个纪元日等于1970年1月1日以来的天数。因此,为了生成一个随机日期,我们只需生成一个随机数,并使用该数字作为纪元日。
3.1. Bounded
3.1.有边际的
We need a temporal abstraction containing only date components, so java.time.LocalDate seems a good candidate:
我们需要一个只包含日期成分的时间抽象,所以java.time.LocalDate似乎是一个不错的候选。
public static LocalDate between(LocalDate startInclusive, LocalDate endExclusive) {
long startEpochDay = startInclusive.toEpochDay();
long endEpochDay = endExclusive.toEpochDay();
long randomDay = ThreadLocalRandom
.current()
.nextLong(startEpochDay, endEpochDay);
return LocalDate.ofEpochDay(randomDay);
}
Here we’re using the toEpochDay() method to convert each LocalDate to its corresponding epoch day. Similarly, we can verify that this approach is correct:
这里我们使用toEpochDay()方法将每个LocalDate转换为其对应的纪元日。同样地,我们可以验证这种方法是正确的。
LocalDate start = LocalDate.of(1989, Month.OCTOBER, 14);
LocalDate end = LocalDate.now();
LocalDate random = RandomDates.between(start, end);
assertThat(random).isAfterOrEqualTo(start, end);
3.2. Unbounded
3.2.无界
In order to generate random dates regardless of any range, we can simply generate a random epoch day:
为了生成不受任何范围限制的随机日期,我们可以简单地生成一个随机纪元日。
public static LocalDate date() {
int hundredYears = 100 * 365;
return LocalDate.ofEpochDay(ThreadLocalRandom
.current().nextInt(-hundredYears, hundredYears));
}
Our random date generator chooses a random day from 100 years before and after the epoch. Again, the rationale behind this is to generate reasonable date values:
我们的随机日期生成器从纪元之前和之后的100年中随机选择一天。同样,这背后的原理是为了生成合理的日期值。
LocalDate randomDay = RandomDates.date();
assertThat(randomDay).isBetween(LocalDate.MIN, LocalDate.MAX);
4. Random Time
4.随机时间
Similar to what we did with dates, we can generate random temporals with just time components. In order to do that, we can use the second of the day concept. That is, a random time is equal to a random number representing the seconds since the beginning of the day.
与我们对日期所做的类似,我们可以只用时间成分来生成随机时间。为了做到这一点,我们可以使用一天中的秒的概念。也就是说,一个随机时间等于一个代表从一天开始的秒的随机数字。
4.1. Bounded
4.1.有边际的
The java.time.LocalTime class is a temporal abstraction that encapsulates nothing but time components:
java.time.LocalTime类是一个时间抽象,它只封装了时间组件。
public static LocalTime between(LocalTime startTime, LocalTime endTime) {
int startSeconds = startTime.toSecondOfDay();
int endSeconds = endTime.toSecondOfDay();
int randomTime = ThreadLocalRandom
.current()
.nextInt(startSeconds, endSeconds);
return LocalTime.ofSecondOfDay(randomTime);
}
In order to generate a random time between two others, we can:
为了在其他两个人之间产生一个随机时间,我们可以。
- Generate a random number between the second of the day of the given times
- Create a random time using that random number
We can easily verify the behavior of this random time generation algorithm:
我们可以很容易地验证这种随机时间生成算法的行为。
LocalTime morning = LocalTime.of(8, 30);
LocalTime randomTime = RandomTimes.between(LocalTime.MIDNIGHT, morning);
assertThat(randomTime)
.isBetween(LocalTime.MIDNIGHT, morning)
.isBetween(LocalTime.MIN, LocalTime.MAX);
4.2. Unbounded
4.2.无界
Even unbounded time values should be in 00:00:00 until 23:59:59 range, so we can simply implement this logic by delegation:
即使是无界的时间值也应该在00:00:00到23:59:59的范围内,所以我们可以简单地通过委托实现这个逻辑。
public static LocalTime time() {
return between(LocalTime.MIN, LocalTime.MAX);
}
5. Conclusion
5.总结
In this tutorial, we reduced the definition of random dates and times to random numbers. Then, we saw how this reduction helped us to generate random temporal values behaving like timestamps, dates or times.
在本教程中,我们将随机日期和时间的定义简化为随机数。然后,我们看到了这种减少是如何帮助我们产生像时间戳、日期或时间一样的随机时间值的。
As usual, the sample code is available over on GitHub.
像往常一样,样本代码可以在GitHub上获得。