ฉันจะคำนวณอายุของใครบางคนใน Java ได้อย่างไร


147

ฉันต้องการคืนอายุในปีเป็น int ในวิธีการ Java สิ่งที่ฉันมีตอนนี้คือสิ่งต่อไปนี้ที่ getBirthDate () ส่งคืนวัตถุวันที่ (พร้อมกับวันเกิด ;-)):

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

    Date age = new Date(ageInMillis);

    return age.getYear();
}

แต่เนื่องจาก getYear () เลิกใช้แล้วฉันสงสัยว่ามีวิธีที่ดีกว่าในการทำเช่นนี้หรือไม่ ฉันไม่แน่ใจด้วยซ้ำว่าทำงานได้อย่างถูกต้องเนื่องจากยังไม่มีการทดสอบหน่วยในสถานที่


เปลี่ยนความคิดของฉันเกี่ยวกับเรื่องนั้น: คำถามอื่นมีเพียงประมาณปีระหว่างวันที่ไม่ใช่อายุที่ถูกต้องอย่างแท้จริง
cletus

ระบุว่าเขากลับมาเป็น int คุณสามารถอธิบายความหมายของอายุที่ถูกต้องได้หรือไม่?
Brian Agnew

2
Date vs Calendar เป็นแนวคิดพื้นฐานที่สามารถรวบรวมได้จากการอ่านเอกสาร Java ฉันไม่เข้าใจว่าทำไมสิ่งนี้ถึงถูกยกระดับขึ้นมาก
demongolem

@Demongolem ??? เข้าใจวันที่และปฏิทินได้ง่ายหรือไม่! ไม่เลย. มีคำถามหนึ่งล้านคำถามในเรื่องนี้ที่ Stack Overflow โครงการ Joda-Time ผลิตหนึ่งในห้องสมุดที่ได้รับความนิยมมากที่สุดเพื่อทดแทนชั้นเรียนตามวันเวลาที่ลำบาก ต่อมา Sun, Oracle และชุมชน JCP ยอมรับJSR 310 ( java.time ) โดยยอมรับว่าคลาสดั้งเดิมนั้นไม่เพียงพอ สำหรับข้อมูลเพิ่มเติมโปรดดูที่การสอนโดยออราเคิล
Basil Bourque

คำตอบ:


159

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

การทดสอบ 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);
    }
}

ทุกคนควรใช้ JDK 8 ในตอนนี้ เวอร์ชันก่อนหน้าทั้งหมดหมดอายุการสนับสนุนแล้ว


10
การเปรียบเทียบ DAY_OF_YEAR สามารถนำไปสู่ผลลัพธ์ที่ผิดพลาดเมื่อจัดการกับปีอธิกสุรทิน
sinuhepop

1
ตัวแปร dateOfBirth จะต้องเป็นวัตถุวันที่ ฉันจะสร้างวัตถุวันที่ด้วยวันเกิดได้อย่างไร
Erick

ด้วยความจริงที่ว่าเรามีอายุ 9 ปีและในกรณีที่ใช้ Java 8 สิ่งนี้ควรเป็นคำตอบที่จะใช้
nojevive

JDK 9 เป็นเวอร์ชันการผลิตปัจจุบัน จริงมากขึ้นกว่าเดิม
duffymo

2
@SteveOh ฉันไม่เห็นด้วย ผมค่อนข้างจะไม่ยอมรับnulls ที่ทุกคน Objects.requireNonNullแต่แทนที่จะใช้
MC Emperor

170

ตรวจสอบJodaซึ่งจะทำให้การคำนวณวันที่ / เวลาง่ายขึ้น (Joda ยังเป็นพื้นฐานของ API วันที่ / เวลามาตรฐานใหม่ของ Java ดังนั้นคุณจะได้เรียนรู้ API ที่เร็วขึ้นเพื่อเป็นมาตรฐาน)

แก้ไข: Java 8 มีบางสิ่งที่คล้ายกันมากและคุ้มค่าที่จะเช็คเอาท์

เช่น

LocalDate birthdate = new LocalDate (1970, 1, 20);
LocalDate now = new LocalDate();
Years age = Years.yearsBetween(birthdate, now);

ซึ่งเรียบง่ายอย่างที่คุณต้องการ สิ่ง pre-Java 8 คือ (ตามที่คุณระบุ) ค่อนข้างใช้งานง่าย


2
@ HoàngLong: จาก JavaDocs: "คลาสนี้ไม่ได้แสดงวัน แต่มิลลิวินาทีทันทีในเวลาเที่ยงคืนหากคุณต้องการคลาสที่แสดงถึงทั้งวันช่วงเวลาหรือ LocalDate อาจเหมาะสมกว่า" จริงๆเราไม่ต้องการแสดงวันที่ที่นี่
Jon Skeet

หากคุณต้องการทำตามวิธีที่ @JohnSkeet แนะนำให้เป็นเช่นนี้: Years age = Years.yearsB Between (LocalDate ใหม่ (getBirthDate ()), LocalDate ใหม่ ()
Fletch

ไม่ทราบว่าทำไมฉันถึงใช้ DateMidnight และฉันทราบว่าตอนนี้เลิกใช้แล้ว ตอนนี้เปลี่ยนเป็น LocalDate
Brian Agnew


2
@IgorGanapolsky จริงๆแล้วความแตกต่างที่สำคัญคือ: Joda-Time ใช้ตัวสร้างในขณะที่ Java-8 และ ThreetenBP ใช้วิธีการคงโรงงาน สำหรับข้อผิดพลาดที่ละเอียดอ่อนในวิธีที่ Joda-Time คำนวณอายุโปรดดูคำตอบของฉันที่ฉันให้ภาพรวมเกี่ยวกับพฤติกรรมของห้องสมุดต่างๆ
Meno Hochschild

43
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

ใช่คลาสปฏิทินนั้นแย่มาก น่าเสียดายที่ที่ทำงานบางครั้งฉันต้องใช้: / ขอบคุณ Cletus สำหรับการโพสต์สิ่งนี้
Steve

1
แทนที่ Calendar.MONTH และ Calendar.DAY_OF_MONTH ด้วย Calendar.DAY_OF_YEAR และอย่างน้อยก็จะสะอาดกว่าเดิมเล็กน้อย
Tobbbe

@Tobbbe หากคุณเกิดวันที่ 1 มีนาคมในปีอธิกสุรทินวันเกิดของคุณคือวันที่ 1 มีนาคมในปีต่อไปไม่ใช่วันที่ 2 DAY_OF_YEAR ไม่ทำงาน
Airsource Ltd

42

คำตอบและภาพรวมที่ทันสมัย

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

โปรดทราบว่าการแสดงออกLocalDate.now()ที่เกี่ยวข้องโดยปริยายกับเขตเวลาของระบบ (ซึ่งมักจะมองข้ามโดยผู้ใช้) เพื่อความชัดเจนจะดีกว่าหากใช้วิธีโอเวอร์โหลดที่now(ZoneId.of("Europe/Paris"))ระบุเขตเวลาที่ชัดเจน (ที่นี่ "ยุโรป / ปารีส" เป็นตัวอย่าง) หากมีการร้องขอเขตเวลาของระบบการตั้งค่าส่วนตัวของฉันคือการเขียนLocalDate.now(ZoneId.systemDefault())เพื่อให้ความสัมพันธ์กับเขตเวลาของระบบชัดเจนขึ้น นี่คือความพยายามในการเขียนที่มากขึ้น แต่ทำให้การอ่านง่ายขึ้น

b) Joda-Time

โปรดทราบว่าวิธีการแก้ปัญหาที่เสนอและยอมรับ Joda-Time-solution ให้ผลลัพธ์การคำนวณที่แตกต่างกันสำหรับวันที่แสดงข้างต้น (กรณีที่หายาก) คือ:

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

ฉันคิดว่านี่เป็นข้อผิดพลาดเล็ก ๆ แต่ทีม Joda มีมุมมองที่แตกต่างกันเกี่ยวกับพฤติกรรมแปลก ๆ นี้และไม่ต้องการแก้ไข (แปลกเพราะวันสิ้นเดือนมีขนาดเล็กกว่าวันที่เริ่มต้นดังนั้นปีควรจะเป็น หนึ่งน้อยกว่า) ดูเพิ่มเติมที่ปิดนี้ปัญหา

c) java.util.Calendar เป็นต้น

สำหรับการเปรียบเทียบดูคำตอบอื่น ๆ อีกมากมาย ฉันจะไม่แนะนำให้ใช้คลาสที่ล้าสมัยเหล่านี้เลยเพราะรหัสผลลัพธ์ยังคงเป็น errorprone ในบางกรณีที่แปลกใหม่และ / หรือวิธีที่ซับซ้อนเกินไปเมื่อพิจารณาจากข้อเท็จจริงที่ว่าคำถามดั้งเดิมฟังดูง่ายมาก ในปี 2558 เรามีห้องสมุดที่ดีกว่าจริงๆ

d) เกี่ยวกับ Date4J:

วิธีแก้ปัญหาที่เสนอนั้นง่าย แต่บางครั้งก็อาจล้มเหลวในกรณีของปีอธิกสุรทิน เพียงแค่การประเมินวันของปีไม่น่าเชื่อถือ

e) ห้องสมุดของฉัน Time4J :

สิ่งนี้ทำงานคล้ายกับ Java-8-solution เพียงแค่เปลี่ยนLocalDateจากPlainDateและโดยChronoUnit.YEARS 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

1
ขอบคุณสำหรับ Java 8 เวอร์ชัน! ช่วยฉันสักครู่ :) ตอนนี้ฉันต้องหาวิธีแยกเดือนที่เหลือ เช่น 1 ปีกับ 1 เดือน :)
thomas77

2
@ thomas77 ขอบคุณสำหรับการตอบกลับปีและเดือนที่รวมกัน (และอาจจะหลายวัน) สามารถทำได้โดยใช้ `java.time.Period 'ใน Java-8 หากคุณต้องการคำนึงถึงหน่วยอื่น ๆ เช่นชั่วโมง Java-8 ไม่ได้เสนอวิธีแก้ปัญหา
Meno Hochschild

ขอขอบคุณอีกครั้ง (และสำหรับการตอบกลับอย่างรวดเร็ว) :)
thomas77

1
ผมขอแนะนำให้ระบุโซนเวลาLocalDate.nowเมื่อใช้ หากไม่ได้ระบุเขตเวลาเริ่มต้นปัจจุบันของ JVM จะถูกนำไปใช้โดยปริยาย เริ่มต้นที่สามารถเปลี่ยนระหว่างเครื่อง / ระบบปฏิบัติการ / การตั้งค่าและยังสามารถในช่วงเวลาใดช่วง RuntimesetDefaultโดยการเรียกรหัสใด ๆ ฉันขอแนะนำให้เฉพาะเจาะจงเช่นLocalDate.now( ZoneId.for( "America/Montreal" ) )
Basil Bourque

1
@GoCrafter_LP ใช่คุณสามารถใช้ ThreetenABP จำลอง Java-8 หรือ Joda-Time-Android (จาก D. Lew) หรือ Time lib ของฉัน lib4A สำหรับเวอร์ชัน Android ที่เก่ากว่า
Meno Hochschild

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

2
จุดประสงค์ของการตรวจสอบ(birthDate.get(Calendar.DAY_OF_YEAR) - today.get(Calendar.DAY_OF_YEAR) > 3)คืออะไร? ดูเหมือนไม่มีจุดหมายกับการมีอยู่ของเดือนและวันเปรียบเทียบ
Jed Schaaf

13

ฉันใช้มิลลิวินาทีเป็นค่าคงที่ปีเพื่อประโยชน์ของฉัน:

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

2
นี่ไม่ใช่คำตอบที่ถูกต้อง ... ปีไม่ใช่ 3.156e + 10 แต่ 3.15576e + 10 (วันไตรมาส!)
Maher Abuthraa

1
สิ่งนี้ใช้ไม่ได้บางปีเป็นปีอธิกสุรทินและมีค่า msec ที่แตกต่างกัน
Greg Ennis

12

หากคุณใช้ 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;
}

5

คำตอบที่ถูกต้องโดยใช้JodaTimeคือ:

public int getAge() {
    Years years = Years.yearsBetween(new LocalDate(getBirthDate()), new LocalDate());
    return years.getYears();
}

คุณสามารถย่อให้สั้นลงเป็นหนึ่งบรรทัดได้หากต้องการ ฉันคัดลอกแนวคิดจากคำตอบของ BrianAgnewแต่ฉันเชื่อว่าสิ่งนี้ถูกต้องมากขึ้นตามที่คุณเห็นจากความคิดเห็นที่นั่น (และตอบคำถามอย่างแน่นอน)



4

นี่เป็นรุ่นที่ปรับปรุงแล้วของรุ่นด้านบน ... เนื่องจากคุณต้องการให้อายุเป็น '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;
}

4

อาจเป็นเรื่องที่น่าแปลกใจที่คุณไม่จำเป็นต้องรู้ว่ามีกี่วันหรือหลายเดือนในหนึ่งปีหรือกี่วันในเดือนนั้นเช่นเดียวกันคุณไม่จำเป็นต้องรู้เกี่ยวกับปีอธิกวินาทีวินาทีกระโดดหรืออะไรก็ตาม ของสิ่งนั้นโดยใช้วิธีที่เรียบง่ายและแม่นยำ 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;
}

ฉันกำลังมองหาวิธีแก้ปัญหาสำหรับ java 6 และ 5 นี้ง่าย แต่แม่นยำ
Jj Tuibeo

3

ลองคัดลอกรหัสนี้ในรหัสของคุณจากนั้นใช้วิธีการรับอายุ

public static int getAge(Date birthday)
{
    GregorianCalendar today = new GregorianCalendar();
    GregorianCalendar bday = new GregorianCalendar();
    GregorianCalendar bdayThisYear = new GregorianCalendar();

    bday.setTime(birthday);
    bdayThisYear.setTime(birthday);
    bdayThisYear.set(Calendar.YEAR, today.get(Calendar.YEAR));

    int age = today.get(Calendar.YEAR) - bday.get(Calendar.YEAR);

    if(today.getTimeInMillis() < bdayThisYear.getTimeInMillis())
        age--;

    return age;
}

คำตอบของรหัสเท่านั้นที่จะหมดกำลังใจ มันจะดีกว่าที่จะอธิบายว่าทำไมรหัสนี้สามารถตอบคำถาม OP
рüффп

จริง ๆ แล้วมันไม่ใช่เกมง่ายๆ แต่จะอัปเดตเพื่อแจ้งข้อกังวลของคุณ
Kevin

3

ฉันใช้โค้ดนี้สำหรับการคำนวณอายุหวังว่านี่จะช่วย .. ห้องสมุดที่ใช้

private static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());

public static int calculateAge(String date) {

    int age = 0;
    try {
        Date date1 = dateFormat.parse(date);
        Calendar now = Calendar.getInstance();
        Calendar dob = Calendar.getInstance();
        dob.setTime(date1);
        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);
        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--;
            }
        }
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return age ;
}

2

การเกิดฟิลด์และเอฟเฟกต์เป็นทั้งฟิลด์วันที่:

Calendar bir = Calendar.getInstance();
bir.setTime(birth);
int birthNm = bir.get(Calendar.DAY_OF_YEAR);
int birthYear = bir.get(Calendar.YEAR);
Calendar eff = Calendar.getInstance();
eff.setTime(effect);

สิ่งนี้เป็นการปรับเปลี่ยนโซลูชันของ John O โดยไม่ต้องใช้วิธีที่คิดค่าเสื่อมราคา ฉันใช้เวลาพอสมควรในการพยายามให้รหัสของเขาทำงานในรหัสของฉัน บางทีนี่อาจช่วยคนอื่นในเวลานั้น


2
คุณช่วยอธิบายสิ่งนี้ให้ดีขึ้นได้หรือไม่? สิ่งนี้คำนวณอายุได้อย่างไร
Jonathan S. Fisher

1

แล้วอันนี้หล่ะ?

public Integer calculateAge(Date date) {
    if (date == null) {
        return null;
    }
    Calendar cal1 = Calendar.getInstance();
    cal1.setTime(date);
    Calendar cal2 = Calendar.getInstance();
    int i = 0;
    while (cal1.before(cal2)) {
        cal1.add(Calendar.YEAR, 1);
        i += 1;
    }
    return i;
}

นี่เป็นข้อเสนอแนะที่น่ารักจริงๆ (เมื่อคุณไม่ได้ใช้ Joda และไม่สามารถใช้ Java 8 ได้) แต่อัลกอริทึมนั้นผิดเล็กน้อยเพราะคุณเป็น 0 จนกระทั่งครบทั้งปีแรก ดังนั้นคุณต้องเพิ่มปีไปยังวันที่ก่อนที่จะเริ่มห่วงขณะที่
Dagmar

1

String dateofbirthมีวันเดือนปีเกิด และรูปแบบเป็นสิ่งที่ (กำหนดไว้ในบรรทัดต่อไปนี้):

org.joda.time.format.DateTimeFormatter formatter =  org.joda.time.format.DateTimeFormat.forPattern("mm/dd/yyyy");

นี่คือวิธีการจัดรูปแบบ:

org.joda.time.DateTime birthdateDate = formatter.parseDateTime(dateofbirth );
org.joda.time.DateMidnight birthdate = new         org.joda.time.DateMidnight(birthdateDate.getYear(), birthdateDate.getMonthOfYear(), birthdateDate.getDayOfMonth() );
org.joda.time.DateTime now = new org.joda.time.DateTime();
org.joda.time.Years age = org.joda.time.Years.yearsBetween(birthdate, now);
java.lang.String ageStr = java.lang.String.valueOf (age.getYears());

ตัวแปรageStrจะมีหลายปี


1

รูปลักษณ์ที่แตกต่างและประทับเวลาตามความแตกต่างของโซลูชั่น Yaron Ronen ที่สง่างามและถูกต้อง

ฉันกำลังรวมทั้งการทดสอบหน่วยที่จะพิสูจน์ว่าเมื่อใดและทำไมมันไม่ถูกต้อง มันเป็นไปไม่ได้เนื่องจาก (อาจจะ) จำนวนวันอธิกวินาที (และวินาที) ที่แตกต่างกันในความแตกต่างของการประทับเวลาใด ๆ ความคลาดเคลื่อนควรสูงสุด + -1 วัน (และหนึ่งวินาที) สำหรับอัลกอริธึมนี้ดู test2 () ในขณะที่โซลูชัน Yaron Ronen ซึ่งตั้งอยู่บนสมมติฐานคงที่อย่างสมบูรณ์timeDiff / MILLI_SECONDS_YEARอาจแตกต่างกัน 10 วันสำหรับอายุ 40 ปี แต่ตัวแปรนี้ก็ไม่ถูกต้องเช่นกัน

มันเป็นเรื่องยากเนื่องจากตัวแปรที่ปรับปรุงนี้ซึ่งใช้สูตรdiffAsCalendar.get(Calendar.YEAR) - 1970จะให้ผลลัพธ์ที่ถูกต้องโดยส่วนใหญ่เป็นจำนวนปีอธิกสุรทินโดยเฉลี่ยระหว่างวันที่สองวัน

/**
 * Compute person's age based on timestamp difference between birth date and given date
 * and prove it is INCORRECT approach.
 */
public class AgeUsingTimestamps {

public int getAge(Date today, Date dateOfBirth) {
    long diffAsLong = today.getTime() - dateOfBirth.getTime();
    Calendar diffAsCalendar = Calendar.getInstance();
    diffAsCalendar.setTimeInMillis(diffAsLong);
    return diffAsCalendar.get(Calendar.YEAR) - 1970; // base time where timestamp=0, precisely 1/1/1970 00:00:00 
}

    final static DateFormat df = new SimpleDateFormat("dd.MM.yyy HH:mm:ss");

    @Test
    public void test1() throws Exception {
        Date dateOfBirth = df.parse("10.1.2000 00:00:00");
        assertEquals(87, getAge(df.parse("08.1.2088 23:59:59"), dateOfBirth));
        assertEquals(87, getAge(df.parse("09.1.2088 23:59:59"), dateOfBirth));
        assertEquals(88, getAge(df.parse("10.1.2088 00:00:01"), dateOfBirth));
    }

    @Test
    public void test2() throws Exception {
        // between 2000 and 2021 was 6 leap days
        // but between 1970 (base time) and 1991 there was only 5 leap days
        // therefore age is switched one day earlier
            // See http://www.onlineconversion.com/leapyear.htm
        Date dateOfBirth = df.parse("10.1.2000 00:00:00");
        assertEquals(20, getAge(df.parse("08.1.2021 23:59:59"), dateOfBirth));
        assertEquals(20, getAge(df.parse("09.1.2021 23:59:59"), dateOfBirth)); // ERROR! returns incorrect age=21 here
        assertEquals(21, getAge(df.parse("10.1.2021 00:00:01"), dateOfBirth));
    }
}

1
public class CalculateAge { 

private int age;

private void setAge(int age){

    this.age=age;

}
public void calculateAge(Date date){

    Calendar calendar=Calendar.getInstance();

    Calendar calendarnow=Calendar.getInstance();    

    calendarnow.getTimeZone();

    calendar.setTime(date);

    int getmonth= calendar.get(calendar.MONTH);

    int getyears= calendar.get(calendar.YEAR);

    int currentmonth= calendarnow.get(calendarnow.MONTH);

    int currentyear= calendarnow.get(calendarnow.YEAR);

    int age = ((currentyear*12+currentmonth)-(getyears*12+getmonth))/12;

    setAge(age);
}
public int getAge(){

    return this.age;

}

0
/**
 * Compute from string date in the format of yyyy-MM-dd HH:mm:ss the age of a person.
 * @author Yaron Ronen
 * @date 04/06/2012  
 */
private int computeAge(String sDate)
{
    // Initial variables.
    Date dbDate = null;
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");      

    // Parse sDate.
    try
    {
        dbDate = (Date)dateFormat.parse(sDate);
    }
    catch(ParseException e)
    {
        Log.e("MyApplication","Can not compute age from date:"+sDate,e);
        return ILLEGAL_DATE; // Const = -2
    }

    // Compute age.
    long timeDiff = System.currentTimeMillis() - dbDate.getTime();      
    int age = (int)(timeDiff / MILLI_SECONDS_YEAR);  // MILLI_SECONDS_YEAR = 31558464000L;

    return age; 
}

ไม่แน่ใจว่าคุณทำการทดสอบจริง ๆ หรือไม่ แต่สำหรับคนอื่น ๆ วิธีการนี้มีข้อบกพร่องหนึ่งข้อ หากวันนี้เป็นเดือนเดียวกันกับวันเดือนปีเกิดของคุณและวันนี้ <วันเกิดก็ยังแสดงอายุจริง + 1 เช่นสำหรับวัน bday ของคุณคือ 7 กันยายน 2529 และวันนี้คือ 1 กันยายน 2013 มันจะแสดง 27 แทน จาก 26.
srahul07

2
สิ่งนี้ไม่เป็นจริงเนื่องจากจำนวนมิลลิวินาทีในหนึ่งปีไม่คงที่ Leap ปีมีอีกหนึ่งวันนั่นคือมิลลิวินาทีมากกว่าคนอื่น ๆ สำหรับคนอายุ 40 ปีอัลกอริทึมของคุณอาจรายงานวันเกิด 9 - 10 วันก่อนหน้านี้ได้แล้วจริงๆ! นอกจากนี้ยังมีวินาทีกระโดด
Espinosa

0

นี่คือรหัส java ในการคำนวณอายุในปีเดือนและวัน

public static AgeModel calculateAge(long birthDate) {
    int years = 0;
    int months = 0;
    int days = 0;

    if (birthDate != 0) {
        //create calendar object for birth day
        Calendar birthDay = Calendar.getInstance();
        birthDay.setTimeInMillis(birthDate);

        //create calendar object for current day
        Calendar now = Calendar.getInstance();
        Calendar current = Calendar.getInstance();
        //Get difference between years
        years = now.get(Calendar.YEAR) - birthDay.get(Calendar.YEAR);

        //get months
        int currMonth = now.get(Calendar.MONTH) + 1;
        int birthMonth = birthDay.get(Calendar.MONTH) + 1;

        //Get difference between months
        months = currMonth - birthMonth;

        //if month difference is in negative then reduce years by one and calculate the number of months.
        if (months < 0) {
            years--;
            months = 12 - birthMonth + currMonth;
        } else if (months == 0 && now.get(Calendar.DATE) < birthDay.get(Calendar.DATE)) {
            years--;
            months = 11;
        }

        //Calculate the days
        if (now.get(Calendar.DATE) > birthDay.get(Calendar.DATE))
            days = now.get(Calendar.DATE) - birthDay.get(Calendar.DATE);
        else if (now.get(Calendar.DATE) < birthDay.get(Calendar.DATE)) {
            int today = now.get(Calendar.DAY_OF_MONTH);
            now.add(Calendar.MONTH, -1);
            days = now.getActualMaximum(Calendar.DAY_OF_MONTH) - birthDay.get(Calendar.DAY_OF_MONTH) + today;
        } else {
            days = 0;
            if (months == 12) {
                years++;
                months = 0;
            }
        }
    }

    //Create new Age object
    return new AgeModel(days, months, years);
}

0

วิธีที่ง่ายที่สุดโดยไม่มีห้องสมุด:

    long today = new Date().getTime();
    long diff = today - birth;
    long age = diff / DateUtils.YEAR_IN_MILLIS;

1
รหัสนี้ใช้คลาสวันที่และเวลาเก่าที่ลำบากซึ่งตอนนี้เป็นแบบดั้งเดิมแทนที่ด้วยคลาส java.time ให้ใช้คลาสที่ทันสมัยที่สร้างขึ้นใน Java ChronoUnit.YEARS.between( LocalDate.of( 1968 , Month.MARCH , 23 ) , LocalDate.now() )แทน ดูคำตอบที่ถูกต้อง
Basil Bourque

DateUtilsเป็นห้องสมุด
Terran

0

ด้วย Java 8 เราสามารถคำนวณอายุบุคคลด้วยรหัสหนึ่งบรรทัด:

public int calCAge(int year, int month,int days){             
    return LocalDate.now().minus(Period.of(year, month, days)).getYear();         
}

อายุปีหรือเดือน? แล้วเดือนล่ะ
gumuruh

-1
public int getAge(Date dateOfBirth) 
{
    Calendar now = Calendar.getInstance();
    Calendar dob = Calendar.getInstance();

    dob.setTime(dateOfBirth);

    if (dob.after(now)) 
    {
        throw new IllegalArgumentException("Can't be born in the future");
    }

    int age = now.get(Calendar.YEAR) - dob.get(Calendar.YEAR);

    if (now.get(Calendar.DAY_OF_YEAR) < dob.get(Calendar.DAY_OF_YEAR)) 
    {
        age--;
    }

    return age;
}

ตามที่ @sinuhepop สังเกตว่า "การเปรียบเทียบ DAY_OF_YEAR สามารถนำไปสู่ผลลัพธ์ที่ผิดพลาดเมื่อจัดการกับปีอธิกสุรทิน"
Krzysztof Kot

-1
import java.io.*;

class AgeCalculator
{
    public static void main(String args[])
    {
        InputStreamReader ins=new InputStreamReader(System.in);
        BufferedReader hey=new BufferedReader(ins);

        try
        {
            System.out.println("Please enter your name: ");
            String name=hey.readLine();

            System.out.println("Please enter your birth date: ");
            String date=hey.readLine();

            System.out.println("please enter your birth month:");
            String month=hey.readLine();

            System.out.println("please enter your birth year:");
            String year=hey.readLine();

            System.out.println("please enter current year:");
            String cYear=hey.readLine();

            int bDate = Integer.parseInt(date);
            int bMonth = Integer.parseInt(month);
            int bYear = Integer.parseInt(year);
            int ccYear=Integer.parseInt(cYear);

            int age;

            age = ccYear-bYear;
            int totalMonth=12;
            int yourMonth=totalMonth-bMonth;

            System.out.println(" Hi " + name + " your are " + age + " years " + yourMonth + " months old ");
        }
        catch(IOException err)
        {
            System.out.println("");
        }
    }
}

-1
public int getAge(String birthdate, String today){
    // birthdate = "1986-02-22"
    // today = "2014-09-16"

    // String class has a split method for splitting a string
    // split(<delimiter>)
    // birth[0] = 1986 as string
    // birth[1] = 02 as string
    // birth[2] = 22 as string
    // now[0] = 2014 as string
    // now[1] = 09 as string
    // now[2] = 16 as string
    // **birth** and **now** arrays are automatically contains 3 elements 
    // split method here returns 3 elements because of yyyy-MM-dd value
    String birth[] = birthdate.split("-");
    String now[] = today.split("-");
    int age = 0;

    // let us convert string values into integer values
    // with the use of Integer.parseInt(<string>)
    int ybirth = Integer.parseInt(birth[0]);
    int mbirth = Integer.parseInt(birth[1]);
    int dbirth = Integer.parseInt(birth[2]);

    int ynow = Integer.parseInt(now[0]);
    int mnow = Integer.parseInt(now[1]);
    int dnow = Integer.parseInt(now[2]);

    if(ybirth < ynow){ // has age if birth year is lesser than current year
        age = ynow - ybirth; // let us get the interval of birth year and current year
        if(mbirth == mnow){ // when birth month comes, it's ok to have age = ynow - ybirth if
            if(dbirth > dnow) // birth day is coming. need to subtract 1 from age. not yet a bday
                age--;
        }else if(mbirth > mnow){ age--; } // birth month is comming. need to subtract 1 from age            
    }

    return age;
}

หมายเหตุ: รูปแบบวันที่คือ: yyyy-MM-dd นี่เป็นรหัสทั่วไปที่ทดสอบใน jdk7 ...
Jhonie

1
มันจะช่วยถ้าคุณให้ความคิดเห็นหรืออธิบายวิธีการใช้รหัสนี้ เพียงแค่การทิ้งโค้ดมักจะหมดกำลังใจและผู้ถามคำถามอาจไม่เข้าใจตัวเลือกของคุณที่อยู่เบื้องหลังว่าทำไมคุณจึงตัดสินใจที่จะเขียนโค้ดวิธีการของคุณด้วยวิธีนี้
rayryeng

@rayryeng: Jhonie ได้เพิ่มความคิดเห็นในรหัสแล้ว นั่นเพียงพอที่จะเข้าใจ โปรดคิดและอ่านก่อนที่จะแสดงความคิดเห็น
akshay

@ Akshay ที่ไม่ชัดเจนสำหรับฉัน ในการเข้าใจย้อนหลังดูเหมือนว่าเขาทิ้งรหัส ฉันมักจะไม่อ่านความคิดเห็น มันคงจะดีถ้าสิ่งเหล่านั้นถูกลบออกจากร่างกายและแยกวางไว้เป็นคำอธิบาย นั่นเป็นความชอบของฉันและเราสามารถเห็นด้วยที่จะไม่เห็นด้วยที่นี่ .... ที่ถูกกล่าวว่าฉันลืมฉันยังเขียนความคิดเห็นนี้เพราะมันเกือบสองปีที่ผ่านมา
rayryeng

@rayryeng: เหตุผลที่อยู่เบื้องหลังความคิดเห็นนี้คือการเขียนความคิดเห็นเชิงลบทำให้คนไม่สามารถใช้ฟอรัมที่ดีได้ ดังนั้นเราควรสนับสนุนพวกเขาโดยให้ความเห็นเชิงบวก Bdw ไม่มีความผิด ไชโย !!!
akshay

-1
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.Period;

public class AgeCalculator1 {

    public static void main(String args[]) {
        LocalDate start = LocalDate.of(1970, 2, 23);
        LocalDate end = LocalDate.now(ZoneId.systemDefault());

        Period p = Period.between(start, end);
        //The output of the program is :
        //45 years 6 months and 6 days.
        System.out.print(p.getYears() + " year" + (p.getYears() > 1 ? "s " : " ") );
        System.out.print(p.getMonths() + " month" + (p.getMonths() > 1 ? "s and " : " and ") );
        System.out.print(p.getDays() + " day" + (p.getDays() > 1 ? "s.\n" : ".\n") );
    }//method main ends here.
}

3
ขอบคุณที่เข้าร่วม StackOverflow คำแนะนำสำหรับคุณ [A] โปรดรวมการสนทนากับคำตอบของคุณ StackOverflow.com มีความหมายมากกว่าเพียงแค่การรวบรวมข้อมูลโค้ด ตัวอย่างเช่นสังเกตว่าโค้ดของคุณใช้เฟรมเวิร์ก java.time ใหม่อย่างไรขณะที่คำตอบอื่น ๆ ส่วนใหญ่ใช้ java.util.Date และ Joda-Time [B] โปรดเปรียบเทียบคำตอบของคุณด้วยคำตอบที่คล้ายกันโดย Meno Hochschild ซึ่งใช้ java.time ด้วย อธิบายว่าคุณดีกว่าหรือโจมตีมุมต่าง ๆ ของปัญหาได้อย่างไร หรือถอยกลับของคุณถ้าไม่ดีกว่า
Basil Bourque

-1
public int getAge(Date birthDate) {
    Calendar a = Calendar.getInstance(Locale.US);
    a.setTime(date);
    Calendar b = Calendar.getInstance(Locale.US);
    int age = b.get(YEAR) - a.get(YEAR);
    if (a.get(MONTH) > b.get(MONTH) || (a.get(MONTH) == b.get(MONTH) && a.get(DATE) > b.get(DATE))) {
        age--;
    }
    return age;
}

-1

ฉันขอขอบคุณคำตอบที่ถูกต้องทั้งหมด แต่นี่คือคำตอบของ kotlin สำหรับคำถามเดียวกัน

ฉันหวังว่าจะเป็นประโยชน์กับนักพัฒนา kotlin

fun calculateAge(birthDate: Date): Int {
        val now = Date()
        val timeBetween = now.getTime() - birthDate.getTime();
        val yearsBetween = timeBetween / 3.15576e+10;
        return Math.floor(yearsBetween).toInt()
    }

ดูเหมือนว่าค่อนข้างโง่ที่จะทำคณิตศาสตร์เช่นนี้เมื่อเรามีชั้นเรียนjava.timeชั้นนำของอุตสาหกรรมเมื่อเราจัดการ
Basil Bourque

คำขอ OP ใน Java
Terran
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.