71

I'm trying to generate a random date of birth for people in my database using a Java program. How would I do this?

Stevoisiak
  • 23,794
  • 27
  • 122
  • 225
user475529
  • 731
  • 1
  • 5
  • 6

15 Answers15

89
import java.util.GregorianCalendar;

public class RandomDateOfBirth {

    public static void main(String[] args) {

        GregorianCalendar gc = new GregorianCalendar();

        int year = randBetween(1900, 2010);

        gc.set(gc.YEAR, year);

        int dayOfYear = randBetween(1, gc.getActualMaximum(gc.DAY_OF_YEAR));

        gc.set(gc.DAY_OF_YEAR, dayOfYear);

        System.out.println(gc.get(gc.YEAR) + "-" + (gc.get(gc.MONTH) + 1) + "-" + gc.get(gc.DAY_OF_MONTH));

    }

    public static int randBetween(int start, int end) {
        return start + (int)Math.round(Math.random() * (end - start));
    }
}
Saul
  • 17,973
  • 8
  • 64
  • 88
  • 3
    This is not an uniform distribution because for example in February there should be less people. – lbalazscs May 16 '13 at 07:55
  • 2
    @lbalazscs - Indeed. I updated the example, it should be a bit better now. – Saul May 16 '13 at 09:33
  • 7
    For the sake of completeness - you should use access constants via `Calendar` class (`Calendar.YEAR`, `Calendar.DAY_OF_YEAR`) not via instance `gc`. – mareckmareck Mar 13 '15 at 10:14
  • 1
    This answer is rather old, but month is counted from 0. So January results in 0. For printing the actual date you have to print `(gc.get(gc.MONTH)+1)` – Maze Nov 10 '15 at 14:08
  • 1
    @Maze - Some answers remain useful and relevant even when several years pass but your observation is entirely accurate. Fixed it. – Saul Nov 10 '15 at 15:05
43

java.util.Date has a constructor that accepts milliseconds since The Epoch, and java.util.Random has a method that can give you a random number of milliseconds. You'll want to set a range for the random value depending on the range of DOBs that you want, but those should do it.

Very roughly:

Random  rnd;
Date    dt;
long    ms;

// Get a new random instance, seeded from the clock
rnd = new Random();

// Get an Epoch value roughly between 1940 and 2010
// -946771200000L = January 1, 1940
// Add up to 70 years to it (using modulus on the next long)
ms = -946771200000L + (Math.abs(rnd.nextLong()) % (70L * 365 * 24 * 60 * 60 * 1000));

// Construct a date
dt = new Date(ms);
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    This is exactly what I started thinking when I first read the question. – AJMansfield May 23 '13 at 12:41
  • 1
    This answer is much more to my preference too. No need to do separate random calls for month, day, and year when a single number can determine it. – ewall Apr 10 '15 at 02:58
  • 1
    It's a nice and simple solution, but I'd rather use `RandomUtils.nextLong(0, 70L * 365 * 24 * 60 * 60 * 1000);` from apache lang3 – Alissa Apr 10 '17 at 14:26
41

Snippet for a Java 8 based solution:

Random random = new Random();
int minDay = (int) LocalDate.of(1900, 1, 1).toEpochDay();
int maxDay = (int) LocalDate.of(2015, 1, 1).toEpochDay();
long randomDay = minDay + random.nextInt(maxDay - minDay);

LocalDate randomBirthDate = LocalDate.ofEpochDay(randomDay);

System.out.println(randomBirthDate);

Note: This generates a random date between 1Jan1900 (inclusive) and 1Jan2015 (exclusive).

Note: It is based on epoch days, i.e. days relative to 1Jan1970 (EPOCH) - positive meaning after EPOCH, negative meaning before EPOCH


You can also create a small utility class:

public class RandomDate {
    private final LocalDate minDate;
    private final LocalDate maxDate;
    private final Random random;

    public RandomDate(LocalDate minDate, LocalDate maxDate) {
        this.minDate = minDate;
        this.maxDate = maxDate;
        this.random = new Random();
    }

    public LocalDate nextDate() {
        int minDay = (int) minDate.toEpochDay();
        int maxDay = (int) maxDate.toEpochDay();
        long randomDay = minDay + random.nextInt(maxDay - minDay);
        return LocalDate.ofEpochDay(randomDay);
    }

    @Override
    public String toString() {
        return "RandomDate{" +
                "maxDate=" + maxDate +
                ", minDate=" + minDate +
                '}';
    }
}

and use it like this:

RandomDate rd = new RandomDate(LocalDate.of(1900, 1, 1), LocalDate.of(2010, 1, 1));
System.out.println(rd.nextDate());
System.out.println(rd.nextDate()); // birthdays ad infinitum
Jens Hoffmann
  • 6,699
  • 2
  • 25
  • 31
  • 4
    This is a fine answer, but the utility class might be made a little more efficient by doing the toEpochDay() conversions for min and max in the constructor and saving the int results rather than the LocalDates. Then it only needs to be done once, rather than once for each call to nextDate(). – L. Blanc Nov 11 '15 at 18:00
  • You can avoid casting the epoch days to `int` by calling [ThreadLocalRandom.current().nextLong(n)](https://stackoverflow.com/questions/2546078/java-random-long-number-in-0-x-n-range). – jaco0646 May 23 '18 at 21:04
  • This is going into going into my testing toolbox for generating mock reports. Thanks for the contribution – Edward J Beckett Aug 17 '19 at 11:04
21

You need to define a random date, right?

A simple way of doing that is to generate a new Date object, using a long (time in milliseconds since 1st January, 1970) and substract a random long:

new Date(Math.abs(System.currentTimeMillis() - RandomUtils.nextLong()));

(RandomUtils is taken from Apache Commons Lang).

Of course, this is far to be a real random date (for example you will not get date before 1970), but I think it will be enough for your needs.

Otherwise, you can create your own date by using Calendar class:

int year = // generate a year between 1900 and 2010;
int dayOfYear = // generate a number between 1 and 365 (or 366 if you need to handle leap year);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, randomYear);
calendar.set(Calendar.DAY_OF_YEAR, dayOfYear);
Date randomDoB = calendar.getTime();
Romain Linsolas
  • 79,475
  • 49
  • 202
  • 273
  • 5
    Is it really so burdensome to just use the standard random? – AJMansfield May 23 '13 at 12:42
  • 1
    this answer is a little outdated. When I type `new Date(Math.abs(System.currentTimeMillis() - RandomUtils.nextLong()));`, it shows the method is deprecated. However I cannot find a parallel equivalent method anywhere else. – Ren Nov 23 '14 at 19:46
10

For Java8 -> Assumming the data of birth must be before current day:

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.temporal.ChronoUnit;
import java.util.Random;

public class RandomDate {

    public static LocalDate randomBirthday() {
        return LocalDate.now().minus(Period.ofDays((new Random().nextInt(365 * 70))));
    }

    public static void main(String[] args) {
        System.out.println("randomDate: " + randomBirthday());
    }
}
Witold Kaczurba
  • 9,845
  • 3
  • 58
  • 67
  • 3
    Consider using a [`ThreadLocalRandom`](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/ThreadLocalRandom.html) rather than instantiating a new [`Random`](https://docs.oracle.com/javase/9/docs/api/java/util/Random.html) each time. – Basil Bourque Dec 04 '17 at 05:56
  • True. Better practice. – Witold Kaczurba Dec 04 '17 at 07:24
3

If you don't mind adding a new library to your code you can use MockNeat (disclaimer: I am one of the authors).

MockNeat mock = MockNeat.threadLocal();

// Generates a random date between [1970-1-1, NOW)
LocalDate localDate = mock.localDates().val();
System.out.println(localDate);

// Generates a random date in the past
// but beore 1987-1-30
LocalDate min = LocalDate.of(1987, 1, 30);
LocalDate past = mock.localDates().past(min).val();
System.out.println(past);

LocalDate max = LocalDate.of(2020, 1, 1);
LocalDate future = mock.localDates().future(max).val();
System.out.println(future);

// Generates a random date between 1989-1-1 and 1993-1-1
LocalDate start = LocalDate.of(1989, 1, 1);
LocalDate stop = LocalDate.of(1993, 1, 1);
LocalDate between = mock.localDates().between(start, stop).val();
System.out.println(between);
Andrei Ciobanu
  • 12,500
  • 24
  • 85
  • 118
2

Generating random Date of Births:

import java.util.Calendar;

public class Main {
  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
        System.out.println(randomDOB());
    }
  }

  public static String randomDOB() {

    int yyyy = random(1900, 2013);
    int mm = random(1, 12);
    int dd = 0; // will set it later depending on year and month

    switch(mm) {
      case 2:
        if (isLeapYear(yyyy)) {
          dd = random(1, 29);
        } else {
          dd = random(1, 28);
        }
        break;

      case 1:
      case 3:
      case 5:
      case 7:
      case 8:
      case 10:
      case 12:
        dd = random(1, 31);
        break;

      default:
        dd = random(1, 30);
      break;
    }

    String year = Integer.toString(yyyy);
    String month = Integer.toString(mm);
    String day = Integer.toString(dd);

    if (mm < 10) {
        month = "0" + mm;
    }

    if (dd < 10) {
        day = "0" + dd;
    }

    return day + '/' + month + '/' + year;
  }

  public static int random(int lowerBound, int upperBound) {
    return (lowerBound + (int) Math.round(Math.random()
            * (upperBound - lowerBound)));
  }

  public static boolean isLeapYear(int year) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.YEAR, year);
    int noOfDays = calendar.getActualMaximum(Calendar.DAY_OF_YEAR);

    if (noOfDays > 365) {
        return true;
    }

    return false;
  }
}
Attila
  • 28,265
  • 3
  • 46
  • 55
2

You can checkout randomizer for random data generation.This library helps to create random data from given Model class.Checkout below example code.

public class Person {

    @DateValue( from = "01 Jan 1990",to = "31 Dec 2002" , customFormat = "dd MMM yyyy")
    String dateOfBirth;

}

//Generate random 100 Person(Model Class) object 
Generator<Person> generator = new Generator<>(Person.class);  
List<Person> persons = generator.generate(100);                          

As there are many built in data generator is accessible using annotation,You also can build custom data generator.I suggest you to go through documentation provided on library page.

Ronak Poriya
  • 2,369
  • 3
  • 18
  • 20
2

Look this method:

public static Date dateRandom(int initialYear, int lastYear) {
    if (initialYear > lastYear) {
        int year = lastYear;
        lastYear = initialYear;
        initialYear = year;
    }

    Calendar cInitialYear = Calendar.getInstance();
    cInitialYear.set(Calendar.YEAR, 2015);
    long offset = cInitialYear.getTimeInMillis();

    Calendar cLastYear = Calendar.getInstance();
    cLastYear.set(Calendar.YEAR, 2016);
    long end = cLastYear.getTimeInMillis();

    long diff = end - offset + 1;
    Timestamp timestamp = new Timestamp(offset + (long) (Math.random() * diff));
    return new Date(timestamp.getTime());
}
Alberto Cerqueira
  • 1,339
  • 14
  • 18
2

I think this will do the trick:

public static void main(String[] args) {
    Date now = new Date();
    long sixMonthsAgo = (now.getTime() - 15552000000l);
    long today = now.getTime();

    for(int i=0; i<10; i++) {
        long ms = ThreadLocalRandom.current().nextLong(sixMonthsAgo, today);

        Date date = new Date(ms);

        System.out.println(date.toString());
    }

}
Spiff
  • 3,873
  • 4
  • 25
  • 50
1

If you don't mind a 3rd party library, the Utils library has a RandomDateUtils that generates random java.util.Dates and all the dates, times, instants, and durations from Java 8's date and time API

LocalDate birthDate = RandomDateUtils.randomPastLocalDate();
LocalDate today = LocalDate.now();
LocalDate under18YearsOld = RandomDateUtils.randomLocalDate(today.minus(18, YEARS), today);
LocalDate over18YearsOld = RandomDateUtils.randomLocalDateBefore(today.minus(18, YEARS));

It is in the Maven Central Repository at:

<dependency>
  <groupId>com.github.rkumsher</groupId>
  <artifactId>utils</artifactId>
  <version>1.3</version>
</dependency>
RKumsher
  • 2,787
  • 2
  • 14
  • 11
1

simplest method:

public static LocalDate randomDateOfBirth() {
    final int maxAge = 100 * 12 * 31;
    return LocalDate.now().minusDays(new Random().nextInt(maxAge));
}
Adam Silenko
  • 3,025
  • 1
  • 14
  • 30
1

Using the original answer and adapting it to the new java.time.* api and adding ways to generate n random dates -- the function will return a List.

// RandomBirthday.java
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class RandomBirthday {

    public static List<String> getRandomBirthday(int groupSize, int minYear, int maxYear) {
        /** Given a group size, this method will return `n` random birthday
         * between 1922-2022 where `n=groupSize`.
         * 
         * @param   groupSize   the number of random birthday to return
         * @param   minYear     the min year [lower bound]
         * @param   maxYear     the max year [upper bound]
         * @return              a list of random birthday with format YYYY-MM-DD
         */
        
        ArrayList<String> birthdays = new ArrayList<>();
        DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        for (int i = 0; i < groupSize; i++) {
            LocalDate baseDate = LocalDate.now();
            LocalDate baseYear = baseDate.withYear(ThreadLocalRandom.current().nextInt(minYear, maxYear));

            int dayOfYear = ThreadLocalRandom.current().nextInt(1, baseYear.lengthOfYear());

            LocalDate baseRandBirthday = baseYear.withDayOfYear(dayOfYear);

            LocalDate randDate = LocalDate.of(
                baseRandBirthday.getYear(),
                baseRandBirthday.getMonth(),
                baseRandBirthday.getDayOfMonth()
            );

            
            String formattedDate = dateFormat.format(randDate);
            birthdays.add(formattedDate);
        }

        return birthdays;
    }

    public static void main(String[] args) {
        // main method
        List<String> bDay = getRandomBirthday(40, 1960, 2022);
        System.out.println(bDay);
    }
}
Teddy
  • 633
  • 1
  • 8
  • 22
0

I am studying Scala and ended up Googling Java solutions for choosing a random date between range. I found this post super helpful and this is my final solution. Hope it can help future Scala and Java programmers.

import java.sql.Timestamp

def date_rand(ts_start_str:String = "2012-01-01 00:00:00", ts_end_str:String = "2015-01-01 00:00:00"): String = {
    val ts_start = Timestamp.valueOf(ts_start_str).getTime()
    val ts_end = Timestamp.valueOf(ts_end_str).getTime()
    val diff = ts_end - ts_start
    println(diff)
    val ts_rand = new Timestamp(ts_start + (Random.nextFloat() * diff).toLong)
    return ts_rand.toString
}                                         //> date_rand: (ts_start_str: String, ts_end_str: String)String

println(date_rand())                      //> 94694400000
                                              //| 2012-10-28 18:21:13.216

println(date_rand("2001-01-01 00:00:00", "2001-01-01 00:00:00"))
                                              //> 0
                                              //| 2001-01-01 00:00:00.0
println(date_rand("2001-01-01 00:00:00", "2010-01-01 00:00:00"))
                                              //> 283996800000
                                              //| 2008-02-16 23:15:48.864                    //> 2013-12-21 08:32:16.384
Community
  • 1
  • 1
B.Mr.W.
  • 18,910
  • 35
  • 114
  • 178
0
int num = 0;
char[] a={'a','b','c','d','e','f'};
String error = null;
try {
    num = Integer.parseInt(request.getParameter("num"));
    Random r = new Random();
    long currentDate = new Date().getTime();
    ArrayList<Student> list = new ArrayList<>();
    for (int i = 0; i < num; i++) {
        String name = "";
        for (int j = 0; j < 6; j++) {
            name += a[r.nextInt(5)];
        }

        list.add(new Student(i + 1, name, r.nextBoolean(), new Date(Math.abs(r.nextLong() % currentDate))));
    }

    request.setAttribute("list", list);
    request.setAttribute("num", num);
    request.getRequestDispatcher("student.jsp").forward(request, response);
} catch (NumberFormatException e) {
    error = "Please enter interger number";
    request.setAttribute("error", error);
    request.getRequestDispatcher("student.jsp").forward(request, response);
}
David Buck
  • 3,752
  • 35
  • 31
  • 35
zuyfun
  • 1
  • When answering an old question, your answer would be much more useful to other StackOverflow users if you included some context to explain how your answer helps, particularly for a question that already has an accepted answer. See: [How do I write a good answer](https://stackoverflow.com/help/how-to-answer). – David Buck Oct 28 '20 at 07:59