Menjana Tarikh Rawak di Jawa

1. Gambaran keseluruhan

Dalam tutorial ini, kita akan melihat bagaimana menghasilkan tarikh dan masa secara rawak dalam fesyen tanpa had dan tanpa had.

Kami akan melihat bagaimana menghasilkan nilai-nilai ini menggunakan API java.util.Date lama dan juga perpustakaan tarikh-tarikh baru dari Java 8.

2. Tarikh dan Masa Rawak

Tarikh dan waktu tidak lebih daripada bilangan bulat 32-bit dibandingkan dengan masa zaman , jadi kita dapat menghasilkan nilai temporal rawak dengan mengikuti algoritma mudah ini:

  1. Hasilkan nombor 32-bit rawak, int
  2. Berikan nilai rawak yang dihasilkan kepada pembangun atau pembina tarikh dan masa yang sesuai

2.1. terbatas Segera

java.time.I nstant adalah salah satu tarikh dan masa yang tambahan baru di Jawa 8. Mereka mewakili mata serta-merta kepada masa-line.

Bagi menjana rawak Segera antara dua yang lain, kita boleh:

  1. Menjana nombor rawak antara saat zaman yang diberikan Segera
  2. Buat rawak Segera dengan melepaskan yang nombor rawak kepada ofEpochSecond () kaedah
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); }

Untuk mencapai lebih banyak throughput dalam persekitaran multi- utas , kami menggunakan ThreadLocalRandom untuk menghasilkan nombor rawak kami.

Kami dapat mengesahkan bahawa Instan yang dihasilkan selalu lebih besar daripada atau sama dengan Instan pertama dan kurang daripada Instan kedua :

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);

Ingatlah, tentu saja, bahawa ujian rawak secara semula jadi tidak bersifat deterministik dan umumnya tidak digalakkan dalam aplikasi sebenar.

Begitu juga, untuk menghasilkan Instan rawak selepas atau sebelum yang lain:

public static Instant after(Instant startInclusive) { return between(startInclusive, Instant.MAX); } public static Instant before(Instant upperExclusive) { return between(Instant.MIN, upperExclusive); }

2.2. Tarikh Terikat

Salah satu pembina tarikh java.util.Date mengambil bilangan milisaat selepas zaman itu. Oleh itu, kita boleh menggunakan algoritma yang sama untuk menghasilkan Tarikh rawak antara dua yang lain:

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); }

Begitu juga, kita seharusnya dapat mengesahkan tingkah laku ini:

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. kurnia yang amat besar Segera

Dalam usaha untuk menjana betul-betul rambang Segera , kita hanya boleh menjana integer rawak dan menyebarkannya kepada ofEpochSecond () kaedah:

public static Instant timestamp() { return Instant.ofEpochSecond(ThreadLocalRandom.current().nextInt()); }

Menggunakan 32-saat saat kerana zaman menjana masa rawak yang lebih munasabah, oleh itu kami menggunakan kaedah nextInt () di sini .

Juga, nilai ini harus masih antara minimum dan maksimum yang mungkin Segera nilai yang Java boleh mengendalikan:

Instant random = RandomDateTimes.timestamp(); assertThat(random).isBetween(Instant.MIN, Instant.MAX);

2.4. Tarikh Tidak Terikat

Sama dengan contoh yang dibatasi, kita boleh memberikan nilai rawak kepada pembangun Date untuk menghasilkan Tarikh rawak :

public static Date timestamp() { return new Date(ThreadLocalRandom.current().nextInt() * 1000L); }

Sejakunit masa pembina adalah milisaat, kami menukar detik 32-bit menjadi milisaat dengan mengalikannya dengan 1000.

Sudah tentu, nilai ini masih di antara nilai Tarikh minimum dan maksimum yang mungkin :

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. Tarikh Rawak

Sehingga kini, kami menghasilkan temporal rawak yang mengandungi komponen tarikh dan waktu. Begitu juga, kita boleh menggunakan konsep zaman zaman untuk menghasilkan temporal rawak dengan komponen tarikh sahaja.

Hari zaman sama dengan jumlah hari sejak 1 Januari 1970. Oleh itu, untuk menghasilkan tarikh rawak, kita hanya perlu menghasilkan nombor rawak dan menggunakan nombor itu sebagai hari zaman.

3.1. Terikat

Kami memerlukan abstraksi temporal yang hanya mengandungi komponen tarikh, jadi java.time.LocalDate nampaknya calon yang baik:

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); }

Di sini kita menggunakan kaedah toEpochDay () untuk menukar setiap LocalDate ke zaman yang sesuai. Begitu juga, kita dapat mengesahkan bahawa pendekatan ini betul:

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. Tidak terikat

Untuk menjana tarikh rawak tanpa mengira julat apa pun, kita hanya dapat menghasilkan hari zaman rawak:

public static LocalDate date() { int hundredYears = 100 * 365; return LocalDate.ofEpochDay(ThreadLocalRandom .current().nextInt(-hundredYears, hundredYears)); }

Penjana tarikh rawak kami memilih hari rawak dari 100 tahun sebelum dan selepas zaman. Sekali lagi, alasan di sebalik ini adalah untuk menghasilkan nilai tarikh yang munasabah:

LocalDate randomDay = RandomDates.date(); assertThat(randomDay).isBetween(LocalDate.MIN, LocalDate.MAX);

4. Masa Rawak

Sama seperti apa yang kita lakukan dengan tarikh, kita dapat menghasilkan temporal rawak dengan komponen masa sahaja. Untuk melakukan itu, kita dapat menggunakan konsep hari kedua. Maksudnya, waktu rawak sama dengan nombor rawak yang mewakili detik sejak awal hari.

4.1. Terikat

The java.time.LocalTime kelas adalah duniawi abstraksi yang merangkumi apa-apa tetapi masa komponen:

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); }

Untuk menghasilkan masa secara rawak antara dua yang lain, kita dapat:

  1. Hasilkan nombor rawak antara detik hari pada waktu yang ditentukan
  2. Buat masa rawak menggunakan nombor rawak itu

Kami dapat mengesahkan tingkah laku algoritma penjanaan masa rawak ini dengan mudah:

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. Tidak terikat

Nilai masa yang tidak terhad sekalipun harus berada dalam rentang 00:00:00 hingga 23:59:59, jadi kami dapat menerapkan logik ini secara delegasi:

public static LocalTime time() { return between(LocalTime.MIN, LocalTime.MAX); }

5. Kesimpulan

Dalam tutorial ini, kami mengurangkan definisi tarikh dan masa rawak kepada nombor rawak. Kemudian, kami melihat bagaimana pengurangan ini membantu kami menghasilkan nilai temporal rawak yang berkelakuan seperti cap waktu, tarikh atau masa.

Seperti biasa, kod sampel boleh didapati di GitHub.