1. Обзор
В этом уроке мы увидим, как генерировать случайные даты и время в ограниченных и неограниченных модах.
Мы рассмотрим, как генерировать эти значения с помощью устаревшего java.util.API даты, а также новая библиотека даты и времени из Java 8.
2. Случайная дата и время
Даты и время-это не более чем 32-битные целые числа по сравнению с временем эпохи , поэтому мы можем генерировать случайные временные значения, следуя этому простому алгоритму:
- Сгенерируйте случайное 32-разрядное число, int
- Передайте сгенерированное случайное значение соответствующему конструктору даты и времени или конструктору
2.1. Ограниченный момент времени
java.время.I instant является одним из новых дополнений даты и времени в Java 8. Они представляют собой мгновенные точки на временной шкале.
Чтобы сгенерировать случайное Мгновенное между двумя другими, мы можем:
- Сгенерируйте случайное число между секундами эпохи заданных мгновений
- Создайте случайное Мгновенное , передав это случайное число в метод ofEpochSecond () |/
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); }
Чтобы добиться большей пропускной способности в многопоточных средах, мы используем ThreadLocalRandom для генерации случайных чисел.
Мы можем проверить, что сгенерированный 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);
Помните, конечно, что тестирование случайности по своей сути недетерминировано и, как правило, не рекомендуется в реальном приложении.
Аналогично, можно также сгенерировать случайный Мгновенный после или до другого:
public static Instant after(Instant startInclusive) { return between(startInclusive, Instant.MAX); } public static Instant before(Instant upperExclusive) { return between(Instant.MIN, upperExclusive); }
2.2. Ограниченная дата
Один из java.util.Дата конструкторы принимают количество миллисекунд после эпохи. Таким образом, мы можем использовать тот же алгоритм для генерации случайной Даты между двумя другими:
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); }
Точно так же мы должны быть в состоянии проверить это поведение:
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. Неограниченный Момент времени
Чтобы сгенерировать полностью случайное Мгновенное , мы можем просто сгенерировать случайное целое число и передать его в метод ofEpochSecond() :
public static Instant timestamp() { return Instant.ofEpochSecond(ThreadLocalRandom.current().nextInt()); }
Использование 32-битных секунд, так как время эпохи генерирует более разумные случайные времена, поэтому мы используем метод nextInt() здесь .
Кроме того, это значение должно по-прежнему находиться между минимально и максимально возможным Мгновенные значения, которые может обрабатывать Java:
Instant random = RandomDateTimes.timestamp(); assertThat(random).isBetween(Instant.MIN, Instant.MAX);
2.4. Неограниченная Дата
Подобно ограниченному примеру, мы можем передать случайное значение в конструктор Date , чтобы сгенерировать случайную Дату:
public static Date timestamp() { return new Date(ThreadLocalRandom.current().nextInt() * 1000L); }
Поскольку единица времени конструктора составляет миллисекунды, мы преобразуем 32-битные секунды эпохи в миллисекунды, умножив их на 1000.
Конечно, это значение все еще находится между минимально и максимально возможными Данными значениями:
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. Случайная Дата
До сих пор мы генерировали случайные временные значения, содержащие как компоненты даты, так и компоненты времени. Аналогично, мы можем использовать концепцию дней эпохи для генерации случайных временных чисел только с компонентами даты.
День эпохи равен количеству дней, прошедших с 1 января 1970 года. Поэтому, чтобы сгенерировать случайную дату, нам просто нужно сгенерировать случайное число и использовать это число в качестве дня эпохи.
3.1. Ограниченные
Нам нужна временная абстракция, содержащая только компоненты даты, поэтому 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); }
Здесь мы используем метод toEpochDay() для преобразования каждого LocalDate в соответствующий день эпохи. Аналогичным образом, мы можем проверить правильность этого подхода:
LocalDate start = LocalDate.of(1989, Month.OCTOBER, 14); LocalDate end = LocalDate.now(); LocalDate random = RandomDates.between(start, end); assertThat(random).isBetween(start, end);
3.2. Неограниченный
Чтобы генерировать случайные даты независимо от любого диапазона, мы можем просто генерировать случайный день эпохи:
public static LocalDate date() { int hundredYears = 100 * 365; return LocalDate.ofEpochDay(ThreadLocalRandom .current().nextInt(-hundredYears, hundredYears)); }
Наш генератор случайных дат выбирает случайный день из 100 лет до и после эпохи. Опять же, обоснование этого заключается в том, чтобы генерировать разумные значения данных:
LocalDate randomDay = RandomDates.date(); assertThat(randomDay).isBetween(LocalDate.MIN, LocalDate.MAX);
4. Случайное Время
Подобно тому, что мы делали с датами, мы можем генерировать случайные временные значения только с компонентами времени. Для этого/| мы можем использовать концепцию второго дня. То есть случайное время равно случайному числу, представляющему секунды с начала дня.
4.1. Ограниченные
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); }
Чтобы сгенерировать случайное время между двумя другими, мы можем:
- Сгенерируйте случайное число между секундой дня заданного времени
- Создайте случайное время, используя это случайное число
Мы можем легко проверить поведение этого алгоритма генерации случайного времени:
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. Неограниченный
Даже неограниченные значения времени должны находиться в диапазоне от 00:00:00 до 23:59:59, поэтому мы можем просто реализовать эту логику путем делегирования:
public static LocalTime time() { return between(LocalTime.MIN, LocalTime.MAX); }
5. Заключение
В этом уроке мы сократили определение случайных дат и времени до случайных чисел. Затем мы увидели, как это сокращение помогло нам генерировать случайные временные значения, такие как временные метки, даты или время.
Как обычно, пример кода доступен на GitHub .