生成随机出生日期

71

我正在使用Java程序为我的数据库中的人生成随机出生日期。 我该如何实现呢?


3
请将文本从英语翻译成中文:请不要使用谜语缩写;) - Danubian Sailor
15个回答

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

3
这不是一个均匀分布,因为比如在二月份的时候应该会有较少的人。 - lbalazscs
2
@lbalazscs - 确实。我更新了示例,现在应该更好一些了。 - Saul
7
为了完整起见,您应该通过Calendar类(Calendar.YEARCalendar.DAY_OF_YEAR)使用访问常量,而不是通过实例gc - mareckmareck
1
这个答案有些老了,但是月份是从0开始计算的。所以一月的结果是0。要打印实际日期,您必须打印 (gc.get(gc.MONTH)+1) - Maze
1
@Maze - 有些答案即使过去了几年仍然有用和相关,但你的观察完全正确。已修复。 - Saul

43

java.util.Date有一个接受自纪元以来的毫秒数的构造函数,而java.util.Random一个方法可以给你一个随机的毫秒数。根据你想要的出生日期范围设置随机值的范围,但这些就足够了。

大致上来说:

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

1
这正是我第一次阅读问题时所想的。 - AJMansfield
1
这个答案也非常符合我的喜好。当一个数字可以确定月份、日期和年份时,就不需要进行单独的随机调用了。 - ewall
1
这是一个不错且简单的解决方案,但我更愿意使用apache lang3中的RandomUtils.nextLong(0, 70L * 365 * 24 * 60 * 60 * 1000); - Alissa

41

Java 8解决方案的示例代码:

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

注意:这会生成一个在1Jan1900(包含)和1Jan2015(不包含)之间的随机日期。

注意:它基于时代日,即相对于1Jan1970(EPOCH)的天数 - 正数表示EPOCH之后,负数表示EPOCH之前。


您还可以创建一个小实用程序类:

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 +
                '}';
    }
}

并且像这样使用它:

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

4
这是一个不错的答案,但是通过在构造函数中为最小值和最大值进行toEpochDay()转换并保存int结果而不是LocalDates,可以使实用类更加高效。这样只需一次完成它,而不是每次调用nextDate()都需要完成一次。 - L. Blanc
你可以通过调用 ThreadLocalRandom.current().nextLong(n) 来避免将时代日转换为 int - jaco0646
这将被加入我的测试工具箱,以生成模拟报告。感谢您的贡献。 - Edward J Beckett

21

你需要定义一个随机日期,对吗?

一种简单的方法是生成一个新的Date对象,使用一个long(自1970年1月1日以来的毫秒数)并减去一个随机的long

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

RandomUtils是从Apache Commons Lang中获取的。

当然,这远远不是一个真正的随机日期(例如,您不会得到1970年之前的日期),但我认为这已经足够满足您的需求了。

否则,您可以使用Calendar类创建自己的日期:

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

5
使用标准随机数生成器真的很繁琐吗? - AJMansfield
1
这个答案有点过时了。当我输入 new Date(Math.abs(System.currentTimeMillis() - RandomUtils.nextLong())); 时,它显示该方法已被弃用。然而我无法在其他地方找到相应的替代方法。 - Ren

10

对于Java8 -> 假设出生日期必须在当前日期之前:

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

3
考虑使用ThreadLocalRandom而不是每次实例化一个新的Random - Basil Bourque
真。更好的实践。 - Witold Kaczurba

3
如果您不介意在代码中添加新的库,您可以使用MockNeat(声明:我是其中之一的作者)。
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);

2
您可以查看randomizer来生成随机数据。该库可帮助从给定的Model类创建随机数据。请查看下面的示例代码。
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);                          

由于许多内置的数据生成器可通过注释访问,您还可以构建自定义数据生成器。我建议您阅读库页面上提供的文档。


2
我认为这会起到作用:

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

}

2
生成随机出生日期:
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;
  }
}

2

看看这个方法:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接