Рубрики
Без рубрики

Генерация случайных дат в Java

Узнайте, как генерировать случайные даты в Java

Автор оригинала: baeldung.

1. Обзор

В этом уроке мы увидим, как генерировать случайные даты и время в ограниченных и неограниченных модах.

Мы рассмотрим, как генерировать эти значения с помощью устаревшего java.util.API даты, а также новая библиотека даты и времени из Java 8.

2. Случайная дата и время

Даты и время-это не более чем 32-битные целые числа по сравнению с временем эпохи , поэтому мы можем генерировать случайные временные значения, следуя этому простому алгоритму:

  1. Сгенерируйте случайное 32-разрядное число, int
  2. Передайте сгенерированное случайное значение соответствующему конструктору даты и времени или конструктору

2.1. Ограниченный момент времени

java.время.I instant является одним из новых дополнений даты и времени в Java 8. Они представляют собой мгновенные точки на временной шкале.

Чтобы сгенерировать случайное Мгновенное между двумя другими, мы можем:

  1. Сгенерируйте случайное число между секундами эпохи заданных мгновений
  2. Создайте случайное Мгновенное , передав это случайное число в метод 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);
}

Чтобы сгенерировать случайное время между двумя другими, мы можем:

  1. Сгенерируйте случайное число между секундой дня заданного времени
  2. Создайте случайное время, используя это случайное число

Мы можем легко проверить поведение этого алгоритма генерации случайного времени:

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 .