考虑闰年计算java中的年龄

时间:2016-09-14 08:04:26

标签: java datetime calendar

我想计算考虑闰年的确切年龄。我在网上研究过,找到了一些教程,但是闰年确切地计算了日期的差异,似乎是[1]中的那个:https://answers.yahoo.com/question/index?qid=20110629162003AAof4mT这个链接,这是“最佳答案”。我分析了代码但有两个问题:

1)为什么在“计算天数生活”部分下面写下“days = days + leapYears”和

2)最后,如何在主要方法中输入日期,月份和年份以及当前日期,月份和年份的生日日期,并在此代码中找到这两个日期的差异?我非常感谢你的帮助。提前谢谢!

PS:为方便起见,我已经包含了上面显示的链接中的代码:

    public class Days { 


      static int leapYear(int year) { 
int leap; 
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) { 
leap = 1; 
} 
else { 
leap = 0; 
} 
return leap; 
} 

static int daysBefore(int month, int day, int year){ 
int days = 0; 
int monthDays[] = new int[] {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 
if (leapYear(year) == 1){ 
monthDays[1] = 29; 
} 
for (int b = 0; b < month - 1; b++){ 
days = days + monthDays[b]; 
} 
days = days + day; 
return days; 
} 
public static void main(String[] args) { 
//Birth date 
int birthMonth = 0; 
int birthDay = 0; 
int birthYear = 0; 

//Due date 
int dueMonth = 0; 
int dueDay = 0; 
int dueYear = 0; 

//(1) Calculate years lived 
int yearsLived = dueYear - birthYear + 1; 

//(2) Calculate leap years 
int leapYears = 0; 
for (int year = birthYear; year < dueYear+1; year++) 
{ 
leapYears = leapYears + leapYear(year); 
} 

//(3) Calculate the number of days in your birth year before birth 
int daysBeforeBirth = daysBefore(birthMonth, birthDay, birthYear); 

//(4) Calculate the number of days remaining in the current year after the due date 
int daysRemaining = 365 - daysBefore(dueMonth, dueDay, dueYear); 

//Calculate days lived 
int days = 0; 
days = days + (365 * yearsLived); 
days = days + leapYears; 
days = days - daysBeforeBirth; 
days = days - daysRemaining; 
} 
}

3 个答案:

答案 0 :(得分:3)

执行此操作的正确方法是使用Period包中的LocalDatejava.time类。但是,您似乎正在尝试为自己重新计算。

我建议这样做的方法是编写一个类,让您计算给定日期的“日期编号” - 即指定日期和过去某个任意日期之间的天数。然后,当您想要查找两个指定日期之间的天数时,您可以使用两个日期计算“日期数”,然后减去它们。

我在这里完成了这个,纯粹的格里高利历。在Gregorian切换之前这个类是没有好处的 - 我没有尝试构建历史上准确的Julian / Gregorian混合日历,例如JDK提供的。并且它计算日期的过去的任意日期是12BC,12BC。当然,这个日期并不是格里高利历的一部分;但对于我们这里的目的,没关系。

由于您不太可能在格里高利转换之前遇到任何日期,因此本课程应该足以满足您的目的。对于生产代码,我仍然建议使用PeriodLocalDate类而不是此类。这就是这里所以你可以看到如何进行计算。

public class GregorianDate {

    private final int day;
    private final int month;
    private final int year;

    private static final int[] DAYS_PER_MONTH = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    public GregorianDate(int day, int month, int year) {
        this.day = day;
        this.month = month;
        this.year = year;
    }

    public boolean isValid() {
        return month >= 1 && month <= 12 && day >= 1 && day <= daysThisMonth();
    }

    public static int daysBetween(GregorianDate from, GregorianDate to) {
        return to.dayNumber() - from.dayNumber();
    }

    public static int daysBetween(int fromDay, int fromMonth, int fromYear, int toDay, int toMonth, int toYear) {
        return daysBetween(new GregorianDate(fromDay, fromMonth, fromYear), new GregorianDate(toDay, toMonth, toYear));
    }

    private int daysThisMonth() {
        return (isLeapYear() && month == 2) ? 29 : DAYS_PER_MONTH[month];
    }

    private int dayNumber() {
        return year * 365 + leapYearsBefore() + daysInMonthsBefore() + day;
    }

    private boolean isLeapYear() {
        return ( year % 4 == 0 &&  year % 100 != 0 ) || year % 400 == 0;  
    }

    private int leapYearsBefore() {
        return year / 4 - year / 100 + year / 400;
    }

    private int daysInMonthsBefore() {
        switch(month) {
        case 1: 
            return 0;
        case 2:
            return 31;
        default:
            // Start with the number in January and February combined
            int toReturn = isLeapYear() ? 60 : 59; 
            for (int monthToConsider = 3; monthToConsider < month; monthToConsider++) {
                toReturn += DAYS_PER_MONTH[monthToConsider];
            }
            return toReturn;
        }
    }

}

答案 1 :(得分:1)

回答问题1。 你每年增加1天的每一年。作者使用这些知识,首先计算如果所有年份都正常,已经过了多少天:

 days = days + (365 * yearsLived);

然后添加了一些leapyears(记住1个leapyear = 1个额外的一天)。

关于第二个问题: 代码寻找birthDate(读取:startDate)和dueDate(读取endDate)之间的区别。因此,要计算开始和结束之间的差异,您必须为这些整数提供日期输入,代码将完成剩下的工作。

答案 2 :(得分:1)

TL;博士

long ageInDays = 
    ChronoUnit.DAYS.between( 
        LocalDate.of( 1960 , 1 , 2 ) , 
        LocalDate.now( ZoneId.of( "America/Montreal" ) )
    );

使用java.time

如果您正在探索该算法,请参阅correct Answer by David Wallace

如果您正在为高效工作而这样做,那么滚动您自己的日期时间类。避免旧的日期时间类(.Date.Calendar等)并使用java.time类。

ChronoUnit枚举具有惊人的效用,包括计算经过时间。在我们的案例Temporal对象中传递几个LocalDate个对象。

LocalDate start = LocalDate.of( 1960 , 1 , 2 ) ;
LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) ) ;
long ageInDays = ChronoUnit.DAYS.between( start , today ) ;

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧日期时间类,例如java.util.Date.Calendar和&amp; java.text.SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。

大部分java.time功能都被反向移植到Java 6&amp; ThreeTen-Backport中的7,并进一步适应Android中的ThreeTenABP(见How to use…)。

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuarter等。