To generate a random date in Java without writing date-math code, open the Random Date Generator, type a YYYY-MM-DD start date and end date, enter a count from 1 to 1,000, and click Generate. The tool draws dates from the inclusive UTC day-ordinal range using browser Web Crypto, formats them as strict YYYY-MM-DD strings, and lets you copy the list directly into LocalDate.parse() calls, JUnit fixtures, or any other Java date input.
Many developers who search for a random date in Java actually need test data more than they need code. Writing a correct random date in Java takes more effort than it looks: you must keep both endpoints inclusive, avoid the daylight-saving trap that lands on 23:00 or 01:00 of the wrong day, and validate leap years without rolling April 31 into May. The browser tool handles all three so you can focus on the test logic that matters.

Why Java's Built-in Date Randomizers Are Tricky
The Java standard library gives you three common paths to a random number, and each one carries a small footgun when the result is meant to be a date.
- Math.random() returns a double in [0.0, 1.0). Scaling that into an integer range is exclusive on the upper bound, so picking dates "between Jan 1 and Dec 31" silently drops the last day unless you add one.
- java.util.Random and ThreadLocalRandom expose nextInt(int bound), which is also exclusive. To stay inclusive on both ends you have to do bound + 1 arithmetic by hand.
- Instant.plus(Duration.ofDays(k)) looks safe, but Duration uses absolute 24-hour spans. Crossing a spring-forward or fall-back transition in a non-UTC zone lands the instant at the wrong wall-clock hour, so the formatted date can skip or repeat a calendar day.
Once you survive those, the next surprise is leap-year validation. Java's LocalDate is strict and will throw a DateTimeException for "2023-02-29" or "2025-04-31", but most naive date-math codebases use ZonedDateTime or a long milliseconds value and silently let invalid dates round forward. Test fixtures written with that code can mask bugs that the production code never sees.
How the Random Date Generator Solves It
The Random Date Generator treats each date as a UTC integer day position measured from 1970-01-01 in 86,400,000-millisecond steps. Both endpoints sit on the same inclusive lattice as every date in between, so 2024-02-28 through 2024-03-01 can return February 28, the leap day February 29, or March 1 with equal probability. Because the ordinals are UTC rather than local, daylight-saving transitions cannot shift the result by an hour.
Randomness comes from browser Web Crypto getRandomValues over unsigned 32-bit words, with rejection sampling to remove the modulo bias that would otherwise give some dates one extra underlying value when the range does not divide 2^32. Math.random is not used. The Gregorian rules follow the ECMAScript Date definition, so century years divisible by four but not by 400 — like 1900 — are correctly rejected while 2000 and 2024 are accepted.
All of this runs in the browser. No date range or result list is sent to a server, which makes the tool safe for internal deadlines, payroll sample dates, or other data you would not want uploaded.
Generate Random Dates Step by Step
- Open the Random Date Generator and enter your start date in the first field as a strict YYYY-MM-DD value, for example 2024-01-01.
- Enter the end date in the second field using the same format, for example 2024-12-31. Both endpoints are eligible for selection.
- Type a count between 1 and 1,000 in the third field. Anything blank, fractional, zero, negative, or above 1,000 is reported as an error and the previous list is cleared.
- Decide whether to allow repeats. Leave the duplicate toggle on for independent draws, or turn it off if you need unique dates — unique mode rejects a count larger than the number of days in the range instead of returning a shorter list.
- Click Generate. The tool draws the dates, formats each one in UTC, and shows the list below.
- Verify the displayed range and count at the top of the result block so you know the values match the controls you set, then copy or record them.
- If you edit either endpoint, change the count, or toggle duplicate mode, the old list and any prior error clear automatically, so a stale result cannot stay on screen as if it matched the current controls.
Pasting the Output Back Into Java Code
Because the output is plain YYYY-MM-DD, the list drops directly into a Java test class. Read each line into a String and pass it to LocalDate.parse(line); the format matches ISO_LOCAL_DATE exactly so no DateTimeFormatter is required. If you need the values as a long primitive, LocalDate.toEpochDay() returns the same integer ordinal the tool sampled from, so values stay comparable across the two systems. For an Instant at midnight UTC, LocalDate.atStartOfDay(ZoneOffset.UTC).toInstant() is the cleanest mapping and matches the tool's internal representation.
This pattern keeps your production code clear and your test fixtures honest: the dates the tool returns are the dates your test sees, with no hidden offset, no DST surprise, and no off-by-one endpoint.
Duplicate Mode vs Unique Mode
Duplicate mode is the right choice when each draw should be independent: sample 30 dates from a 365-day range and you may legitimately see the same day twice, because every requested draw samples the full range on its own. This matches the behavior of Math.random or Random.nextInt, but with the date layer already handled.
Unique mode runs a sparse partial Fisher-Yates selection without replacement. Memory grows with the requested count rather than with the size of the date range, so the tool stays responsive even on multi-decade ranges. If you ask for more unique dates than the inclusive range contains, the tool reports the error and does not silently switch back to duplicate mode or return a truncated list.
Input Validation and Edge Cases
The tool reports invalid input rather than repairing it. The table below shows common inputs and what happens.
| Input | Result |
|---|---|
| 2000-02-29 to 2000-03-01 | Accepted, can return the leap day or either endpoint |
| 1900-02-29 to 1900-03-01 | Rejected, 1900 is not a leap year under Gregorian rules |
| 2025-04-31 to 2025-05-01 | Rejected, April has 30 days and does not roll into May |
| 2024-01-01 to 2024-01-01 | Accepted, single-day range always returns that date in duplicate mode |
| 2024-12-31 to 2024-01-01 | Rejected, start date is after end date |
| Count 0 or 1,001 | Rejected, allowed range is 1 to 1,000 |
| Years 0001 through 9999 | Accepted, setUTCFullYear keeps them literal |
For reproducible software tests, store the resulting dates or use your own seeded test generator; Web Crypto is intentionally not seedable through this interface. Equal probability does not guarantee that any particular run looks evenly spaced, and duplicate mode can legitimately repeat values. If the draw has financial, legal, contest, security, or audit consequences, use a documented procedure with independent oversight and retained evidence rather than a single browser tool.
Finally, remember that the list contains no time of day, no timezone offset, and does not exclude weekends, public holidays, historical calendar transitions, or organization-specific blackout dates. Check those constraints separately before the value lands in a real process.