如何用Java计算某人的年龄?

noj*_*ive 137 java calendar date

我想在Java方法中将一个年龄作为int返回.我现在有以下内容:getBirthDate()返回Date对象(出生日期;-)):

public int getAge() {
    long ageInMillis = new Date().getTime() - getBirthDate().getTime();

    Date age = new Date(ageInMillis);

    return age.getYear();
}
Run Code Online (Sandbox Code Playgroud)

但是因为getYear()被弃用了,我想知道是否有更好的方法来做到这一点?我甚至不确定这是否正常,因为我还没有进行单元测试.

Bri*_*new 167

查看Joda,它简化了日期/时间计算(Joda也是新标准Java日期/时间apis的基础,因此您将学习一个即将成为标准的API).

编辑:Java 8有一些非常相似的东西,值得一试.

例如

LocalDate birthdate = new LocalDate (1970, 1, 20);
LocalDate now = new LocalDate();
Years age = Years.yearsBetween(birthdate, now);
Run Code Online (Sandbox Code Playgroud)

这就是你想要的那么简单.Java 8之前的东西(正如你所确定的那样)有点不直观.

  • @HoàngLong:来自JavaDocs:"这个类不代表一天,而是午夜的毫秒时刻.如果你需要一个代表一整天的类,那么Interval或LocalDate可能更合适." 我们真的*想要在这里代表一个约会. (2认同)
  • @Bor - http://joda-time.sourceforge.net/apidocs/org/joda/time/Years.html#toString%28%29 (2认同)
  • @IgorGanapolsky确实主要区别在于:Joda-Time使用构造函数而Java-8和ThreetenBP使用静态工厂方法.对于Joda-Time计算年龄的方式中的一个微妙的错误,请查看[我的答案](http://stackoverflow.com/a/27738766/2491410),其中我已经概述了不同库的行为. (2认同)

duf*_*ymo 148

JDK 8使这简单而优雅:

public class AgeCalculator {

    public static int calculateAge(LocalDate birthDate, LocalDate currentDate) {
        if ((birthDate != null) && (currentDate != null)) {
            return Period.between(birthDate, currentDate).getYears();
        } else {
            return 0;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

一个JUnit测试来演示它的用途:

public class AgeCalculatorTest {

    @Test
    public void testCalculateAge_Success() {
        // setup
        LocalDate birthDate = LocalDate.of(1961, 5, 17);
        // exercise
        int actual = AgeCalculator.calculateAge(birthDate, LocalDate.of(2016, 7, 12));
        // assert
        Assert.assertEquals(55, actual);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在每个人都应该使用JDK 8.所有早期版本都已经过了他们的支持生命.

  • 在处理闰年时,DAY_OF_YEAR比较可能导致错误的结果. (10认同)
  • @SteveOh我不同意。我宁愿完全不接受`null`,而是使用`Objects.requireNonNull`。 (2认同)

cle*_*tus 42

Calendar now = Calendar.getInstance();
Calendar dob = Calendar.getInstance();
dob.setTime(...);
if (dob.after(now)) {
  throw new IllegalArgumentException("Can't be born in the future");
}
int year1 = now.get(Calendar.YEAR);
int year2 = dob.get(Calendar.YEAR);
int age = year1 - year2;
int month1 = now.get(Calendar.MONTH);
int month2 = dob.get(Calendar.MONTH);
if (month2 > month1) {
  age--;
} else if (month1 == month2) {
  int day1 = now.get(Calendar.DAY_OF_MONTH);
  int day2 = dob.get(Calendar.DAY_OF_MONTH);
  if (day2 > day1) {
    age--;
  }
}
// age is now correct
Run Code Online (Sandbox Code Playgroud)


Men*_*ild 39

现代答案和概述

a)Java-8(java.time-package)

LocalDate start = LocalDate.of(1996, 2, 29);
LocalDate end = LocalDate.of(2014, 2, 28); // use for age-calculation: LocalDate.now()
long years = ChronoUnit.YEARS.between(start, end);
System.out.println(years); // 17
Run Code Online (Sandbox Code Playgroud)

请注意,表达式LocalDate.now()与系统时区(用户经常忽略)隐式相关.为清楚起见,通常最好使用now(ZoneId.of("Europe/Paris"))指定显式时区的重载方法(此处以"Europe/Paris"为例).如果请求系统时区,那么我个人的首选是写入LocalDate.now(ZoneId.systemDefault())以使与系统时区的关系更清晰.这是更多的写作努力,但使阅读更容易.

b)Joda-Time

请注意,建议和接受的Joda-Time解决方案会产生上述日期的不同计算结果(极少数情况),即:

LocalDate birthdate = new LocalDate(1996, 2, 29);
LocalDate now = new LocalDate(2014, 2, 28); // test, in real world without args
Years age = Years.yearsBetween(birthdate, now);
System.out.println(age.getYears()); // 18
Run Code Online (Sandbox Code Playgroud)

我认为这是一个小错误,但Joda团队对这种奇怪的行为有不同的看法并且不想修复它(很奇怪,因为结束日期的日期小于开始日期所以年份应该是少一个).另见这个封闭的问题.

c)java.util.Calendar等.

为了比较,请参阅其他各种答案.我不建议使用这些过时的类,因为在一些奇特的情况下,结果代码仍然是错误的和/或考虑到原始问题听起来如此简单的事实而过于复杂.在2015年,我们拥有更好的图书馆.

d)关于Date4J:

建议的解决方案很简单,但有时在闰年的情况下会失败.仅评估一年中的某一天并不可靠.

e)我自己的图书馆Time4J:

这类似于Java-8解决方案.只需替换LocalDateby PlainDateChronoUnit.YEARSby CalendarUnit.YEARS.但是,获取"今天"需要明确的时区参考.

PlainDate start = PlainDate.of(1996, 2, 29);
PlainDate end = PlainDate.of(2014, 2, 28);
// use for age-calculation (today): 
// => end = SystemClock.inZonalView(EUROPE.PARIS).today();
// or in system timezone: end = SystemClock.inLocalView().today();
long years = CalendarUnit.YEARS.between(start, end);
System.out.println(years); // 17
Run Code Online (Sandbox Code Playgroud)

  • @ thomas77感谢您的回复,在Java-8中使用`java.time.Period'可以完成数年和数月(也许是几天).如果您还想考虑其他单位,如小时,那么Java-8不提供解决方案. (2认同)
  • 我建议在使用“LocalDate.now”时**指定时区**。如果省略,则隐式应用 JVM 当前的默认时区。该默认值可以在机器/操作系统/设置之间更改,并且也可以在任何时刻*在运行时*通过调用 [`setDefault`](http://docs.oracle.com/javase/8/docs/api/java /util/TimeZone.html#setDefault-java.util.TimeZone-)。我建议具体一些,例如 `LocalDate.now( ZoneId.for( "America/Montreal" ) )` (2认同)

小智 17

/**
 * This Method is unit tested properly for very different cases , 
 * taking care of Leap Year days difference in a year, 
 * and date cases month and Year boundary cases (12/31/1980, 01/01/1980 etc)
**/

public static int getAge(Date dateOfBirth) {

    Calendar today = Calendar.getInstance();
    Calendar birthDate = Calendar.getInstance();

    int age = 0;

    birthDate.setTime(dateOfBirth);
    if (birthDate.after(today)) {
        throw new IllegalArgumentException("Can't be born in the future");
    }

    age = today.get(Calendar.YEAR) - birthDate.get(Calendar.YEAR);

    // If birth date is greater than todays date (after 2 days adjustment of leap year) then decrement age one year   
    if ( (birthDate.get(Calendar.DAY_OF_YEAR) - today.get(Calendar.DAY_OF_YEAR) > 3) ||
            (birthDate.get(Calendar.MONTH) > today.get(Calendar.MONTH ))){
        age--;

     // If birth date and todays date are of same month and birth day of month is greater than todays day of month then decrement age
    }else if ((birthDate.get(Calendar.MONTH) == today.get(Calendar.MONTH )) &&
              (birthDate.get(Calendar.DAY_OF_MONTH) > today.get(Calendar.DAY_OF_MONTH ))){
        age--;
    }

    return age;
}
Run Code Online (Sandbox Code Playgroud)

  • 检查的目的是什么`(birthDate.get(Calendar.DAY_OF_YEAR) - today.get(Calendar.DAY_OF_YEAR)> 3)`?对于月份和日期比较的存在似乎毫无意义. (2认同)

Lou*_*rda 12

我只是使用一年中常量值的毫秒数来获得优势:

Date now = new Date();
long timeBetween = now.getTime() - age.getTime();
double yearsBetween = timeBetween / 3.15576e+10;
int age = (int) Math.floor(yearsBetween);
Run Code Online (Sandbox Code Playgroud)

  • 这不是准确的答案......年份不是3.156e + 10而是3.15576e + 10(季度日!) (2认同)
  • 这不起作用,有些年份是闰年并且具有不同的毫秒值 (2认同)

Cra*_*igo 11

如果您正在使用GWT,您将被限制使用java.util.Date,这是一个将日期作为整数但仍使用java.util.Date的方法:

public int getAge(int year, int month, int day) {
    Date now = new Date();
    int nowMonth = now.getMonth()+1;
    int nowYear = now.getYear()+1900;
    int result = nowYear - year;

    if (month > nowMonth) {
        result--;
    }
    else if (month == nowMonth) {
        int nowDay = now.getDate();

        if (day > nowDay) {
            result--;
        }
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)


wes*_*ton 7

注意到您不需要知道一年中有多少天或月或这些月有多少天,这可能令人惊讶,同样,您也不需要知道闰年、闰秒或任何使用这个简单的、100% 准确的方法来分析那些东西:

public static int age(Date birthday, Date date) {
    DateFormat formatter = new SimpleDateFormat("yyyyMMdd");
    int d1 = Integer.parseInt(formatter.format(birthday));
    int d2 = Integer.parseInt(formatter.format(date));
    int age = (d2-d1)/10000;
    return age;
}
Run Code Online (Sandbox Code Playgroud)

  • 我正在寻找 java 6 和 5 的解决方案。这很简单但准确。 (3认同)

Joh*_*n O 5

使用date4j库:

int age = today.getYear() - birthdate.getYear();
if(today.getDayOfYear() < birthdate.getDayOfYear()){
  age = age - 1; 
}
Run Code Online (Sandbox Code Playgroud)


fau*_*r21 5

这是上述版本的改进版本......考虑到您希望年龄为“int”。因为有时你不想用一堆库来填充你的程序。

public int getAge(Date dateOfBirth) {
    int age = 0;
    Calendar born = Calendar.getInstance();
    Calendar now = Calendar.getInstance();
    if(dateOfBirth!= null) {
        now.setTime(new Date());
        born.setTime(dateOfBirth);  
        if(born.after(now)) {
            throw new IllegalArgumentException("Can't be born in the future");
        }
        age = now.get(Calendar.YEAR) - born.get(Calendar.YEAR);             
        if(now.get(Calendar.DAY_OF_YEAR) < born.get(Calendar.DAY_OF_YEAR))  {
            age-=1;
        }
    }  
    return age;
}
Run Code Online (Sandbox Code Playgroud)


Fle*_*tch 5

使用JodaTime的正确答案是:

public int getAge() {
    Years years = Years.yearsBetween(new LocalDate(getBirthDate()), new LocalDate());
    return years.getYears();
}
Run Code Online (Sandbox Code Playgroud)

如果您愿意,您甚至可以将其缩短为一行。我从BrianAgnew 的回答中复制了这个想法,但我相信这更正确,正如您从那里的评论中看到的那样(并且它准确地回答了问题)。