Trong C #, làm cách nào để tính tuổi của ai đó dựa trên ngày sinh của loại DateTime?


1868

Cho một DateTimeđại diện cho sinh nhật của một người, làm thế nào để tính toán tuổi của họ trong những năm?


147
điều mà tất cả các câu trả lời cho đến nay đã bỏ lỡ là nó phụ thuộc vào nơi người đó được sinh ra và họ đang ở đâu.
Yaur

40
@Yaur: Chỉ cần chuyển đổi thời gian bây giờ + sinh thành GMT / UTC, tuổi chỉ là một giá trị tương đối, do đó múi giờ là không liên quan. Để xác định múi giờ hiện tại của người dùng, bạn có thể sử dụng GeoLocating.
Stefan Steiger

Tại sao không xem xét [Ngày Julian] [1]? [1]: stackoverflow.com/questions/7103064/ từ
Muhammad Hewedy

5
Nếu chúng tôi đang xem xét đề xuất của @Yaur về tính toán giữa các múi giờ, Thời gian tiết kiệm ánh sáng ban ngày có ảnh hưởng đến việc tính toán theo bất kỳ cách nào không?
DDM

6
Bị từ chối vì đây rõ ràng là một câu hỏi bài tập về nhà và không có nỗ lực nào được cung cấp.
Marie

Câu trả lời:


2122

Một giải pháp dễ hiểu và đơn giản.

// Save today's date.
var today = DateTime.Today;
// Calculate the age.
var age = today.Year - birthdate.Year;
// Go back to the year the person was born in case of a leap year
if (birthdate.Date > today.AddYears(-age)) age--;

Tuy nhiên, điều này giả định rằng bạn đang tìm kiếm ý tưởng phương Tây về tuổi tác và không sử dụng tính toán Đông Á .


252
Chỉ muốn nhận xét về hiệu suất DateTime. Bây giờ. Nếu bạn không cần một giá trị múi giờ chính xác, hãy sử dụng DateTime.UtcNow nó nhanh hơn nhiều.
JAG

104
Vì chúng ta đang nói chuyện sinh nhật, bạn chỉ có thể sử dụng DateTime. Hôm nay, phần thời gian không có liên quan.
Tristan Warner-Smith

78
Câu trả lời này không hoạt động với tất cả các địa phương và mọi lứa tuổi. Một số quốc gia đã bỏ qua ngày sau khi sinh của những người sống hiện tại, bao gồm Nga (1918), Hy Lạp (1924) và Thổ Nhĩ Kỳ (1926).
Lars D

30
Trên thực tế, nó vẫn không hoàn toàn chính xác. Mã này giả định rằng 'bday' là phần ngày của DateTime. Đó là một trường hợp cạnh (tôi đoán hầu hết mọi người sẽ chỉ vượt qua ngày tháng chứ không phải ngày tháng), nhưng nếu bạn vượt qua trong ngày sinh nhật như một ngày và thời gian trong đó thời gian lớn hơn 00:00:00 thì bạn ' Sẽ gặp phải lỗi Danvil đã chỉ ra. Đặt bday = bday.Date sửa lỗi này.
yvind

119
Dòng cuối cùng làm tôi suy nghĩ quá nhiều. Thay vào đó là về: if (bday.AddYears (age)> now) age--; Đây dường như là một biểu hiện trực quan hơn.
cdiggins

1015

Đây là một cách kỳ lạ để làm điều đó, nhưng nếu bạn định dạng ngày yyyymmddvà trừ ngày sinh từ ngày hiện tại thì hãy bỏ 4 chữ số cuối cùng mà bạn có tuổi :)

Tôi không biết C #, nhưng tôi tin rằng nó sẽ hoạt động với bất kỳ ngôn ngữ nào.

20080814 - 19800703 = 280111 

Thả 4 chữ số cuối = 28.

Mã C #:

int now = int.Parse(DateTime.Now.ToString("yyyyMMdd"));
int dob = int.Parse(dateOfBirth.ToString("yyyyMMdd"));
int age = (now - dob) / 10000;

Hoặc thay thế mà không có tất cả các chuyển đổi loại dưới dạng một phương thức mở rộng. Kiểm tra lỗi bị bỏ qua:

public static Int32 GetAge(this DateTime dateOfBirth)
{
    var today = DateTime.Today;

    var a = (today.Year * 100 + today.Month) * 100 + today.Day;
    var b = (dateOfBirth.Year * 100 + dateOfBirth.Month) * 100 + dateOfBirth.Day;

    return (a - b) / 10000;
}

5
Trên thực tế, điều này rất tốt cho việc sử dụng trên MS-SQL với các trường dữ liệu (tổng số ngày kể từ ngày 01-011900)
Patrik

5
@numerek Vui lòng gửi các sửa đổi được đề xuất của bạn dưới dạng câu trả lời của riêng họ. Đối với giá trị của nó, năm hiện tại 10000 không ở gần mức tràn số nguyên, theo hai bậc độ lớn. 20.150.000 so với 2.147.483.648
GalacticCowboy

7
@LongChalk 20180101 - 20171231 = 8870. Thả 4 chữ số cuối và bạn có (ngụ ý) 0cho độ tuổi. Làm thế nào bạn có được 1?
Rufus L

4
Tôi biết đây là một câu trả lời cũ nhưng tôi sẽ không tạo ra một phương pháp mở rộng từ đó, nó không phải là nơi thích hợp để xác định các logic như vậy.
Lucca Ferri

1
Những loại ma thuật này là?
Muleskinner

391

Đây là một đoạn kiểm tra:

DateTime bDay = new DateTime(2000, 2, 29);
DateTime now = new DateTime(2009, 2, 28);
MessageBox.Show(string.Format("Test {0} {1} {2}",
                CalculateAgeWrong1(bDay, now),      // outputs 9
                CalculateAgeWrong2(bDay, now),      // outputs 9
                CalculateAgeCorrect(bDay, now),     // outputs 8
                CalculateAgeCorrect2(bDay, now)));  // outputs 8

Ở đây bạn có các phương pháp:

public int CalculateAgeWrong1(DateTime birthDate, DateTime now)
{
    return new DateTime(now.Subtract(birthDate).Ticks).Year - 1;
}

public int CalculateAgeWrong2(DateTime birthDate, DateTime now)
{
    int age = now.Year - birthDate.Year;

    if (now < birthDate.AddYears(age))
        age--;

    return age;
}

public int CalculateAgeCorrect(DateTime birthDate, DateTime now)
{
    int age = now.Year - birthDate.Year;

    if (now.Month < birthDate.Month || (now.Month == birthDate.Month && now.Day < birthDate.Day))
        age--;

    return age;
}

public int CalculateAgeCorrect2(DateTime birthDate, DateTime now)
{
    int age = now.Year - birthDate.Year;

    // For leap years we need this
    if (birthDate > now.AddYears(-age)) 
        age--;
    // Don't use:
    // if (birthDate.AddYears(age) > now) 
    //     age--;

    return age;
}

33
Trong khi mã này hoạt động, nó khẳng định rằng một người sinh vào ngày nhuận sẽ đạt được năm tiếp theo vào ngày 1 tháng 3 vào những năm không nhảy vọt, thay vì vào ngày 28 tháng 2. Trong thực tế, một trong hai lựa chọn có thể đúng . Wikipedia có một cái gì đó để nói về điều này . Vì vậy, trong khi mã của bạn không "sai", thì giải pháp cũng không được chấp nhận.
Matt Johnson-Pint

18
@MattJohnson Tôi nghĩ điều đó thực sự chính xác. Nếu ngày của tôi là ngày 29 tháng 2, thì ngày 28 tháng 2, ngày của tôi không trôi qua, và tôi vẫn nên bằng tuổi vào ngày 27 tháng 2. Tuy nhiên, vào ngày 1 tháng 3, chúng tôi đã qua ngày của tôi và tôi sẽ ở tuổi tiếp theo. Ở Mỹ, một doanh nghiệp bán rượu sẽ có một dấu hiệu cho biết đại loại như "Nếu bạn được sinh ra sau ngày này ở YYYY, bạn không thể mua rượu" (nơi YYYY thay đổi hàng năm). Điều đó có nghĩa là ai đó sinh ngày 29 tháng 2 không thể mua rượu vào ngày 28 tháng 2 trong năm họ 21 tuổi (hầu hết các địa điểm) và cho vay hỗ trợ cho ý tưởng rằng họ không được một tuổi cho đến ngày 1 tháng 3
jfren484

4
@ jfren484 - đọc bài viết Wikipedia. Nó thay đổi đáng kể giữa các khu vực pháp lý.
Matt Johnson-Pint

9
@ jfren484 Yêu cầu của bạn hoàn toàn không liên quan gì đến triết học; nhưng tất cả mọi thứ để làm với cảm giác cá nhân của riêng bạn . Khi một người sinh vào ngày 29 tháng 2 "tuổi" phần lớn không quan trọng trừ khi độ tuổi hình thành "ranh giới tuổi hợp pháp" (ví dụ: Có thể mua rượu, bỏ phiếu, nhận lương hưu, tham gia quân đội, lấy bằng lái xe). Xem xét tuổi uống rượu của Hoa Kỳ (21 tuổi): Đối với hầu hết mọi người là 7670 ngày. Đó là 7671 ngày nếu sinh trước ngày 29 tháng 2 năm nhuận hoặc từ ngày 1 tháng 3 trước năm nhuận. Nếu sinh ngày 29 tháng 2: 28 tháng 2 là 7670 ngày và 1 tháng 3 là 7671 ngày. Sự lựa chọn là tùy ý nó có thể đi một trong hai cách.
vỡ mộng

4
@CraigYoung Bạn không hiểu ý của tôi về mặt triết học. Tôi đã sử dụng thuật ngữ đó như một sự tương phản với pháp lý. Nếu một người đang viết một ứng dụng cần biết tuổi hợp pháp của một người, thì tất cả những gì họ cần biết là cách các khu vực pháp lý mà ứng dụng của họ được sử dụng trong / để đối xử với những người sinh vào ngày 29 tháng 2. Tuy nhiên, nếu chúng ta nói về cách mà nên được đối xử, sau đó là theo định nghĩa, triết lý. Và vâng, ý kiến ​​tôi đưa ra là ý kiến ​​của riêng tôi, nhưng như tôi đã nói, tôi nghĩ sẽ dễ tranh luận vào ngày 1 tháng 3 hơn là vào ngày 28 tháng 2
jfren484

110

Câu trả lời đơn giản cho vấn đề này là áp dụng AddYearsnhư hình dưới đây vì đây là phương pháp gốc duy nhất để thêm năm vào ngày 29 tháng 2 năm nhuận và có được kết quả chính xác vào ngày 28 tháng 2 cho các năm chung.

Một số người cảm thấy rằng ngày 1 tháng 3 là ngày sinh nhật của tờ rơi nhưng cả .Net và bất kỳ quy tắc chính thức nào cũng không hỗ trợ điều này, cũng như logic thông thường không giải thích được tại sao một số người sinh vào tháng Hai nên có 75% sinh nhật của họ trong một tháng khác.

Hơn nữa, một phương thức Age cho vay để được thêm vào như một phần mở rộng DateTime. Bằng cách này, bạn có thể có được tuổi theo cách đơn giản nhất có thể:

  1. Danh sách mục

int age = birthdayDate.Age ();

public static class DateTimeExtensions
{
    /// <summary>
    /// Calculates the age in years of the current System.DateTime object today.
    /// </summary>
    /// <param name="birthDate">The date of birth</param>
    /// <returns>Age in years today. 0 is returned for a future date of birth.</returns>
    public static int Age(this DateTime birthDate)
    {
        return Age(birthDate, DateTime.Today);
    }

    /// <summary>
    /// Calculates the age in years of the current System.DateTime object on a later date.
    /// </summary>
    /// <param name="birthDate">The date of birth</param>
    /// <param name="laterDate">The date on which to calculate the age.</param>
    /// <returns>Age in years on a later day. 0 is returned as minimum.</returns>
    public static int Age(this DateTime birthDate, DateTime laterDate)
    {
        int age;
        age = laterDate.Year - birthDate.Year;

        if (age > 0)
        {
            age -= Convert.ToInt32(laterDate.Date < birthDate.Date.AddYears(age));
        }
        else
        {
            age = 0;
        }

        return age;
    }
}

Bây giờ, chạy thử nghiệm này:

class Program
{
    static void Main(string[] args)
    {
        RunTest();
    }

    private static void RunTest()
    {
        DateTime birthDate = new DateTime(2000, 2, 28);
        DateTime laterDate = new DateTime(2011, 2, 27);
        string iso = "yyyy-MM-dd";

        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                Console.WriteLine("Birth date: " + birthDate.AddDays(i).ToString(iso) + "  Later date: " + laterDate.AddDays(j).ToString(iso) + "  Age: " + birthDate.AddDays(i).Age(laterDate.AddDays(j)).ToString());
            }
        }

        Console.ReadKey();
    }
}

Ví dụ về ngày quan trọng là đây:

Ngày sinh: 2000-02-29 Ngày sau: 2011 / 02-28 Tuổi: 11

Đầu ra:

{
    Birth date: 2000-02-28  Later date: 2011-02-27  Age: 10
    Birth date: 2000-02-28  Later date: 2011-02-28  Age: 11
    Birth date: 2000-02-28  Later date: 2011-03-01  Age: 11
    Birth date: 2000-02-29  Later date: 2011-02-27  Age: 10
    Birth date: 2000-02-29  Later date: 2011-02-28  Age: 11
    Birth date: 2000-02-29  Later date: 2011-03-01  Age: 11
    Birth date: 2000-03-01  Later date: 2011-02-27  Age: 10
    Birth date: 2000-03-01  Later date: 2011-02-28  Age: 10
    Birth date: 2000-03-01  Later date: 2011-03-01  Age: 11
}

Và cho ngày sau đó 2012 / 02-28:

{
    Birth date: 2000-02-28  Later date: 2012-02-28  Age: 12
    Birth date: 2000-02-28  Later date: 2012-02-29  Age: 12
    Birth date: 2000-02-28  Later date: 2012-03-01  Age: 12
    Birth date: 2000-02-29  Later date: 2012-02-28  Age: 11
    Birth date: 2000-02-29  Later date: 2012-02-29  Age: 12
    Birth date: 2000-02-29  Later date: 2012-03-01  Age: 12
    Birth date: 2000-03-01  Later date: 2012-02-28  Age: 11
    Birth date: 2000-03-01  Later date: 2012-02-29  Age: 11
    Birth date: 2000-03-01  Later date: 2012-03-01  Age: 12
}

4
Một bình luận liên quan đến việc có ngày sinh nhật 29 tháng 2 vào ngày 1 tháng 3, về mặt kỹ thuật, có nó vào ngày 28 là quá sớm (thực tế là sớm 1 ngày). Ngày 1 là một ngày quá muộn. Nhưng vì sinh nhật là giữa, nên sử dụng ngày 1 để tính tuổi trong những năm không có ý nghĩa đối với tôi, vì người đó thực sự già vào ngày 1 tháng 3 (và thứ 2 và thứ 3) hàng năm, nhưng không phải vào ngày 28 tháng 2.
CyberClaw

1
Từ quan điểm thiết kế phần mềm, viết nó như một phương pháp mở rộng không có ý nghĩa gì với tôi. date.Age(other)?
soái ca

90

Đề xuất của tôi

int age = (int) ((DateTime.Now - bday).TotalDays/365.242199);

Điều đó dường như có năm thay đổi vào đúng ngày. (Tôi đã kiểm tra đến tuổi 107.)


26
Tôi không nghĩ Harry Patch sẽ đánh giá cao phương pháp kiểm tra tại chỗ của bạn: latimes.com/news/obituaries/iêu
MusiGenesis

3
Google cho biếtdays in a year = 365.242199
mở cửa

12
Độ dài trung bình của một năm trong Lịch Gregorian là 365,2425 ngày.
dan04

4
Tôi có thể nói, đây là một trong những giải pháp đơn giản nhất và nó đủ tốt . Ai quan tâm nếu tôi nửa ngày trước sinh nhật thứ X của tôi và chương trình nói rằng tôi X tuổi. Chương trình này ít nhiều đúng, mặc dù không phải là toán học. Tôi thực sự thích giải pháp này.
Peter Perháč

13
^^ Bởi vì đôi khi nó quan trọng. Trong thử nghiệm của tôi, điều này không thành công vào ngày sinh nhật của mọi người, nó báo cáo họ trẻ hơn họ.
ChadT

76

Một chức năng khác, không phải bởi tôi nhưng được tìm thấy trên web và tinh chỉnh nó một chút:

public static int GetAge(DateTime birthDate)
{
    DateTime n = DateTime.Now; // To avoid a race condition around midnight
    int age = n.Year - birthDate.Year;

    if (n.Month < birthDate.Month || (n.Month == birthDate.Month && n.Day < birthDate.Day))
        age--;

    return age;
}

Chỉ có hai điều xuất hiện trong đầu tôi: Còn những người từ các quốc gia không sử dụng lịch Gregorian thì sao? DateTime. Bây giờ tôi nghĩ là trong văn hóa dành riêng cho máy chủ. Tôi hoàn toàn không có kiến ​​thức về việc thực sự làm việc với lịch châu Á và tôi không biết có cách nào dễ dàng để chuyển đổi ngày giữa các lịch không, nhưng chỉ trong trường hợp bạn đang tự hỏi về những người Trung Quốc từ năm 4660 :-)


Điều này xuất hiện để xử lý các khu vực khác nhau (định dạng ngày) tốt nhất.
webdad3

53

2 vấn đề chính cần giải quyết là:

1. Tính tuổi chính xác - tính theo năm, tháng, ngày, v.v.

2. Tính tuổi nhận thức chung - mọi người thường không quan tâm chính xác họ bao nhiêu tuổi, họ chỉ quan tâm khi sinh nhật của họ trong năm hiện tại.


Giải pháp cho 1 là rõ ràng:

DateTime birth = DateTime.Parse("1.1.2000");
DateTime today = DateTime.Today;     //we usually don't care about birth time
TimeSpan age = today - birth;        //.NET FCL should guarantee this as precise
double ageInDays = age.TotalDays;    //total number of days ... also precise
double daysInYear = 365.2425;        //statistical value for 400 years
double ageInYears = ageInDays / daysInYear;  //can be shifted ... not so precise

Giải pháp cho 2 là giải pháp không chính xác trong việc xác định tổng tuổi, nhưng được mọi người cảm nhận là chính xác. Mọi người cũng thường sử dụng nó, khi họ tính tuổi "thủ công":

DateTime birth = DateTime.Parse("1.1.2000");
DateTime today = DateTime.Today;
int age = today.Year - birth.Year;    //people perceive their age in years

if (today.Month < birth.Month ||
   ((today.Month == birth.Month) && (today.Day < birth.Day)))
{
  age--;  //birthday in current year not yet reached, we are 1 year younger ;)
          //+ no birthday for 29.2. guys ... sorry, just wrong date for birth
}

Ghi chú đến 2.:

  • Đây là giải pháp ưa thích của tôi
  • Chúng tôi không thể sử dụng DateTime.DayOfYear hoặc TimeSpans, vì chúng thay đổi số ngày trong năm nhuận
  • Tôi đã đặt ở đó ít dòng hơn để dễ đọc

Chỉ một lưu ý nữa ... Tôi sẽ tạo 2 phương thức quá tải tĩnh cho nó, một phương pháp sử dụng phổ biến, thứ hai là thân thiện với việc sử dụng:

public static int GetAge(DateTime bithDay, DateTime today) 
{ 
  //chosen solution method body
}

public static int GetAge(DateTime birthDay) 
{ 
  return GetAge(birthDay, DateTime.Now);
}

50

Đây là một lót:

int age = new DateTime(DateTime.Now.Subtract(birthday).Ticks).Year-1;

23
Nó bị hỏng. Đã kiểm tra: public static int CompateAge (DateTime dateOfBirth, DateTime dateToCalculateAge) {return new DateTime (dateToCalculateAge.Subtract (dateOfBirth) .Ticks) .Year - 1; } ... Cung cấp tuổi 14 khi tôi nhập 1990-06-01 và tính tuổi vào ngày TRƯỚC sinh nhật thứ 14 của anh ấy (1990-05-31).
Kjensen

43

Đây là phiên bản chúng tôi sử dụng ở đây. Nó hoạt động, và nó khá đơn giản. Đó là ý tưởng tương tự như của Jeff nhưng tôi nghĩ nó rõ ràng hơn một chút vì nó tách ra logic để trừ đi một thứ, vì vậy nó dễ hiểu hơn một chút.

public static int GetAge(this DateTime dateOfBirth, DateTime dateAsAt)
{
    return dateAsAt.Year - dateOfBirth.Year - (dateOfBirth.DayOfYear < dateAsAt.DayOfYear ? 0 : 1);
}

Bạn có thể mở rộng toán tử ternary để làm cho nó rõ ràng hơn nữa, nếu bạn nghĩ rằng điều đó không rõ ràng.

Rõ ràng điều này được thực hiện như một phương thức mở rộng DateTime, nhưng rõ ràng bạn có thể lấy một dòng mã đó thực hiện công việc và đặt nó ở bất cứ đâu. Ở đây chúng ta có một sự quá tải khác của phương thức Tiện ích mở rộng DateTime.Now, chỉ để hoàn thiện.


6
Tôi nghĩ rằng điều này có thể được tắt trong một ngày khi chính xác một ngày dateOfBirth hoặc dateAsAt rơi vào một năm nhuận. Xem xét tuổi của một người sinh vào ngày 1 tháng 3 năm 2003 vào ngày 29 tháng 2 năm 2004. Để khắc phục điều này, bạn cần thực hiện so sánh từ vựng của các cặp (Tháng, DayOfMonth) và sử dụng điều đó cho điều kiện.
Doug McClean

1
nó cũng sẽ không hiển thị đúng tuổi vào ngày sinh nhật của bạn.
dotjoe

43

Cách tốt nhất mà tôi biết vì năm nhuận và mọi thứ là:

DateTime birthDate = new DateTime(2000,3,1);
int age = (int)Math.Floor((DateTime.Now - birthDate).TotalDays / 365.25D);

34

Tôi sử dụng cái này:

public static class DateTimeExtensions
{
    public static int Age(this DateTime birthDate)
    {
        return Age(birthDate, DateTime.Now);
    }

    public static int Age(this DateTime birthDate, DateTime offsetDate)
    {
        int result=0;
        result = offsetDate.Year - birthDate.Year;

        if (offsetDate.DayOfYear < birthDate.DayOfYear)
        {
              result--;
        }

        return result;
    }
}

32

Điều này cung cấp "chi tiết hơn" cho câu hỏi này. Có lẽ đây là những gì bạn đang tìm kiếm

DateTime birth = new DateTime(1974, 8, 29);
DateTime today = DateTime.Now;
TimeSpan span = today - birth;
DateTime age = DateTime.MinValue + span;

// Make adjustment due to MinValue equalling 1/1/1
int years = age.Year - 1;
int months = age.Month - 1;
int days = age.Day - 1;

// Print out not only how many years old they are but give months and days as well
Console.Write("{0} years, {1} months, {2} days", years, months, days);

1
Điều này không hoạt động tất cả các thời gian. Thêm Span vào DateTime.MinValue có thể hoạt động vì điều này không tính đến năm nhuận, v.v. Nếu bạn thêm Năm, tháng và ngày vào Tuổi bằng cách sử dụng hàm AddYears (), AddMonths và AddDays (), nó sẽ không luôn trả về Ngày .Bây giờ.
Athanasios Kataras

3
timespan tự động tính đến năm nhuận giữa 2 ngày, vì vậy tôi không chắc bạn sẽ làm gì. Tôi đã hỏi trên các diễn đàn microsoft và microsoft đã xác nhận rằng nó sẽ tính đến năm nhuận giữa 2 ngày.
Jacqueline Loriault

2
Hãy xem xét các kịch bản HAI sau. Ngày thứ 1. Bây giờ là 1/1/2001 và một đứa trẻ được sinh ra vào ngày 1/1/2000. Năm 2000 là một năm nhuận và kết quả sẽ là 1 năm, 0 tháng và 1 ngày. Trong senarion thứ hai DateTime. Bây giờ là 1/1/2002 và đứa trẻ được sinh ra vào 1/1/2001. Trong trường hợp này, kết quả sẽ là 1 năm, 0 tháng và 0 ngày. Điều đó sẽ xảy ra bởi vì bạn đang thêm thời gian vào một năm không nhảy vọt. Nếu DateTime.MinValue là một năm nhuận thì kết quả sẽ là 1 năm đầu tiên và 0 năm 11 tháng và 30 ngày. (Hãy thử nó trong mã của bạn).
Athanasios Kataras

1
Upvote! Tôi đã đưa ra một giải pháp khá giống nhau (tôi đã sử dụng DateTime.MinValue.AddTicks (span.Ticks) thay vì +, nhưng kết quả là như nhau và bạn có ít mã ký tự hơn).
Makotosan 17/03/2015

4
Bạn hoàn toàn đúng phải không. Nhưng NẾU đó là kết quả. Tại sao nó quan trọng? Nó không. Trong cả hai trường hợp nhảy vọt hoặc không thì có những ví dụ mà điều này không hoạt động. Đó là những gì tôi muốn thể hiện. DIFF là chính xác. Span tính đến năm nhuận. Nhưng THÊM vào một ngày cơ sở thì không. Hãy thử các ví dụ trong mã và bạn sẽ thấy tôi đúng.
Athanasios Kataras

28

Tôi đã tạo Hàm SQL do người dùng xác định để tính tuổi của ai đó, được cung cấp ngày sinh của họ. Điều này hữu ích khi bạn cần nó như một phần của truy vấn:

using System;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public partial class UserDefinedFunctions
{
    [SqlFunction(DataAccess = DataAccessKind.Read)]
    public static SqlInt32 CalculateAge(string strBirthDate)
    {
        DateTime dtBirthDate = new DateTime();
        dtBirthDate = Convert.ToDateTime(strBirthDate);
        DateTime dtToday = DateTime.Now;

        // get the difference in years
        int years = dtToday.Year - dtBirthDate.Year;

        // subtract another year if we're before the
        // birth day in the current year
        if (dtToday.Month < dtBirthDate.Month || (dtToday.Month == dtBirthDate.Month && dtToday.Day < dtBirthDate.Day))
            years=years-1;

        int intCustomerAge = years;
        return intCustomerAge;
    }
};

28

Đây là một câu trả lời khác:

public static int AgeInYears(DateTime birthday, DateTime today)
{
    return ((today.Year - birthday.Year) * 372 + (today.Month - birthday.Month) * 31 + (today.Day - birthday.Day)) / 372;
}

Điều này đã được thử nghiệm rộng rãi đơn vị. Nó trông hơi "ma thuật". Số 372 là số ngày sẽ có trong một năm nếu mỗi tháng có 31 ngày.

Giải thích tại sao nó hoạt động ( được nâng lên từ đây ) là:

Hãy đặt Yn = DateTime.Now.Year, Yb = birthday.Year, Mn = DateTime.Now.Month, Mb = birthday.Month, Dn = DateTime.Now.Day, Db = birthday.Day

age = Yn - Yb + (31*(Mn - Mb) + (Dn - Db)) / 372

Chúng tôi biết rằng những gì chúng tôi cần là hoặc Yn-Ybđã đạt được ngày, Yn-Yb-1nếu nó chưa đạt được.

a) Nếu Mn<Mb, chúng ta có-341 <= 31*(Mn-Mb) <= -31 and -30 <= Dn-Db <= 30

-371 <= 31*(Mn - Mb) + (Dn - Db) <= -1

Với phép chia số nguyên

(31*(Mn - Mb) + (Dn - Db)) / 372 = -1

b) Nếu Mn=MbDn<Db, chúng ta có31*(Mn - Mb) = 0 and -30 <= Dn-Db <= -1

Với phép chia số nguyên, một lần nữa

(31*(Mn - Mb) + (Dn - Db)) / 372 = -1

c) Nếu Mn>Mb, chúng ta có31 <= 31*(Mn-Mb) <= 341 and -30 <= Dn-Db <= 30

1 <= 31*(Mn - Mb) + (Dn - Db) <= 371

Với phép chia số nguyên

(31*(Mn - Mb) + (Dn - Db)) / 372 = 0

d) Nếu Mn=MbDn>Db, chúng ta có 31*(Mn - Mb) = 0 and 1 <= Dn-Db <= 30

Với phép chia số nguyên, một lần nữa

(31*(Mn - Mb) + (Dn - Db)) / 372 = 0

e) Nếu Mn=MbDn=Db, chúng ta có31*(Mn - Mb) + Dn-Db = 0

và do đó (31*(Mn - Mb) + (Dn - Db)) / 372 = 0


3
Tôi vấp vào cuộc thảo luận dài và khó chịu này, và giải pháp của bạn là một cách tiếp cận thực sự tốt và nhỏ. Cảm ơn vì đã giữ cho nó đơn giản
nabuchodonossor

25

Tôi đã dành một chút thời gian để làm việc này và nghĩ ra điều này để tính tuổi của ai đó theo năm, tháng và ngày. Tôi đã thử nghiệm chống lại vấn đề ngày 29 tháng 2 và năm nhuận và nó dường như hoạt động, tôi đánh giá cao bất kỳ phản hồi nào:

public void LoopAge(DateTime myDOB, DateTime FutureDate)
{
    int years = 0;
    int months = 0;
    int days = 0;

    DateTime tmpMyDOB = new DateTime(myDOB.Year, myDOB.Month, 1);

    DateTime tmpFutureDate = new DateTime(FutureDate.Year, FutureDate.Month, 1);

    while (tmpMyDOB.AddYears(years).AddMonths(months) < tmpFutureDate)
    {
        months++;

        if (months > 12)
        {
            years++;
            months = months - 12;
        }
    }

    if (FutureDate.Day >= myDOB.Day)
    {
        days = days + FutureDate.Day - myDOB.Day;
    }
    else
    {
        months--;

        if (months < 0)
        {
            years--;
            months = months + 12;
        }

        days +=
            DateTime.DaysInMonth(
                FutureDate.AddMonths(-1).Year, FutureDate.AddMonths(-1).Month
            ) + FutureDate.Day - myDOB.Day;

    }

    //add an extra day if the dob is a leap day
    if (DateTime.IsLeapYear(myDOB.Year) && myDOB.Month == 2 && myDOB.Day == 29)
    {
        //but only if the future date is less than 1st March
        if (FutureDate >= new DateTime(FutureDate.Year, 3, 1))
            days++;
    }

}

21

Chúng ta có cần xem xét những người nhỏ hơn 1 năm không? như văn hóa Trung Quốc, chúng tôi mô tả tuổi của trẻ nhỏ là 2 tháng hoặc 4 tuần.

Dưới đây là cách thực hiện của tôi, nó không đơn giản như những gì tôi tưởng tượng, đặc biệt là để đối phó với ngày như 28/11.

public static string HowOld(DateTime birthday, DateTime now)
{
    if (now < birthday)
        throw new ArgumentOutOfRangeException("birthday must be less than now.");

    TimeSpan diff = now - birthday;
    int diffDays = (int)diff.TotalDays;

    if (diffDays > 7)//year, month and week
    {
        int age = now.Year - birthday.Year;

        if (birthday > now.AddYears(-age))
            age--;

        if (age > 0)
        {
            return age + (age > 1 ? " years" : " year");
        }
        else
        {// month and week
            DateTime d = birthday;
            int diffMonth = 1;

            while (d.AddMonths(diffMonth) <= now)
            {
                diffMonth++;
            }

            age = diffMonth-1;

            if (age == 1 && d.Day > now.Day)
                age--;

            if (age > 0)
            {
                return age + (age > 1 ? " months" : " month");
            }
            else
            {
                age = diffDays / 7;
                return age + (age > 1 ? " weeks" : " week");
            }
        }
    }
    else if (diffDays > 0)
    {
        int age = diffDays;
        return age + (age > 1 ? " days" : " day");
    }
    else
    {
        int age = diffDays;
        return "just born";
    }
}

Việc thực hiện này đã vượt qua các trường hợp thử nghiệm.

[TestMethod]
public void TestAge()
{
    string age = HowOld(new DateTime(2011, 1, 1), new DateTime(2012, 11, 30));
    Assert.AreEqual("1 year", age);

    age = HowOld(new DateTime(2011, 11, 30), new DateTime(2012, 11, 30));
    Assert.AreEqual("1 year", age);

    age = HowOld(new DateTime(2001, 1, 1), new DateTime(2012, 11, 30));
    Assert.AreEqual("11 years", age);

    age = HowOld(new DateTime(2012, 1, 1), new DateTime(2012, 11, 30));
    Assert.AreEqual("10 months", age);

    age = HowOld(new DateTime(2011, 12, 1), new DateTime(2012, 11, 30));
    Assert.AreEqual("11 months", age);

    age = HowOld(new DateTime(2012, 10, 1), new DateTime(2012, 11, 30));
    Assert.AreEqual("1 month", age);

    age = HowOld(new DateTime(2008, 2, 28), new DateTime(2009, 2, 28));
    Assert.AreEqual("1 year", age);

    age = HowOld(new DateTime(2008, 3, 28), new DateTime(2009, 2, 28));
    Assert.AreEqual("11 months", age);

    age = HowOld(new DateTime(2008, 3, 28), new DateTime(2009, 3, 28));
    Assert.AreEqual("1 year", age);

    age = HowOld(new DateTime(2009, 1, 28), new DateTime(2009, 2, 28));
    Assert.AreEqual("1 month", age);

    age = HowOld(new DateTime(2009, 2, 1), new DateTime(2009, 3, 1));
    Assert.AreEqual("1 month", age);

    // NOTE.
    // new DateTime(2008, 1, 31).AddMonths(1) == new DateTime(2009, 2, 28);
    // new DateTime(2008, 1, 28).AddMonths(1) == new DateTime(2009, 2, 28);
    age = HowOld(new DateTime(2009, 1, 31), new DateTime(2009, 2, 28));
    Assert.AreEqual("4 weeks", age);

    age = HowOld(new DateTime(2009, 2, 1), new DateTime(2009, 2, 28));
    Assert.AreEqual("3 weeks", age);

    age = HowOld(new DateTime(2009, 2, 1), new DateTime(2009, 3, 1));
    Assert.AreEqual("1 month", age);

    age = HowOld(new DateTime(2012, 11, 5), new DateTime(2012, 11, 30));
    Assert.AreEqual("3 weeks", age);

    age = HowOld(new DateTime(2012, 11, 1), new DateTime(2012, 11, 30));
    Assert.AreEqual("4 weeks", age);

    age = HowOld(new DateTime(2012, 11, 20), new DateTime(2012, 11, 30));
    Assert.AreEqual("1 week", age);

    age = HowOld(new DateTime(2012, 11, 25), new DateTime(2012, 11, 30));
    Assert.AreEqual("5 days", age);

    age = HowOld(new DateTime(2012, 11, 29), new DateTime(2012, 11, 30));
    Assert.AreEqual("1 day", age);

    age = HowOld(new DateTime(2012, 11, 30), new DateTime(2012, 11, 30));
    Assert.AreEqual("just born", age);

    age = HowOld(new DateTime(2000, 2, 29), new DateTime(2009, 2, 28));
    Assert.AreEqual("8 years", age);

    age = HowOld(new DateTime(2000, 2, 29), new DateTime(2009, 3, 1));
    Assert.AreEqual("9 years", age);

    Exception e = null;

    try
    {
        age = HowOld(new DateTime(2012, 12, 1), new DateTime(2012, 11, 30));
    }
    catch (ArgumentOutOfRangeException ex)
    {
        e = ex;
    }

    Assert.IsTrue(e != null);
}

Hy vọng nó hữu ích.


20

Giữ cho nó đơn giản (và có thể ngu ngốc :)).

DateTime birth = new DateTime(1975, 09, 27, 01, 00, 00, 00);
TimeSpan ts = DateTime.Now - birth;
Console.WriteLine("You are approximately " + ts.TotalSeconds.ToString() + " seconds old.");

TimeSpan là lựa chọn đầu tiên của tôi, nhưng thấy rằng nó không cung cấp thuộc tính TotalYears. Bạn có thể thử (ts.TotalDays / 365) - nhưng nó không tính đến năm nhuận, v.v.
Lazlow

19

Cách đơn giản nhất tôi từng tìm thấy là đây. Nó hoạt động chính xác cho các địa phương Hoa Kỳ và Tây Âu. Không thể nói chuyện với các địa phương khác, đặc biệt là những nơi như Trung Quốc. 4 so sánh thêm, nhiều nhất, theo tính toán ban đầu của tuổi.

public int AgeInYears(DateTime birthDate, DateTime referenceDate)
{
  Debug.Assert(referenceDate >= birthDate, 
               "birth date must be on or prior to the reference date");

  DateTime birth = birthDate.Date;
  DateTime reference = referenceDate.Date;
  int years = (reference.Year - birth.Year);

  //
  // an offset of -1 is applied if the birth date has 
  // not yet occurred in the current year.
  //
  if (reference.Month > birth.Month);
  else if (reference.Month < birth.Month) 
    --years;
  else // in birth month
  {
    if (reference.Day < birth.Day)
      --years;
  }

  return years ;
}

Tôi đã xem qua các câu trả lời cho điều này và nhận thấy rằng không ai có liên quan đến ý nghĩa pháp lý / pháp lý của việc sinh ngày nhuận. Chẳng hạn, trên Wikipedia , nếu bạn sinh vào ngày 29 tháng 2 ở nhiều khu vực pháp lý khác nhau, thì sinh nhật của bạn không phải là năm nhuận khác nhau:

  • Tại Vương quốc Anh và Hồng Kông: đó là ngày thứ năm trong năm, vì vậy ngày hôm sau, ngày 1 tháng 3 là sinh nhật của bạn.
  • Ở New Zealand: đó là ngày hôm trước, ngày 28 tháng 2 cho các mục đích cấp giấy phép lái xe và ngày 1 tháng 3 cho các mục đích khác.
  • Đài Loan: đó là ngày 28 tháng 2.

Và gần như tôi có thể nói, ở Mỹ, các đạo luật im lặng về vấn đề này, để nó tuân theo luật chung và cách các cơ quan quản lý khác nhau định nghĩa mọi thứ trong quy định của họ.

Cuối cùng, một cải tiến:

public enum LeapDayRule
{
  OrdinalDay     = 1 ,
  LastDayOfMonth = 2 ,
}

static int ComputeAgeInYears(DateTime birth, DateTime reference, LeapYearBirthdayRule ruleInEffect)
{
  bool isLeapYearBirthday = CultureInfo.CurrentCulture.Calendar.IsLeapDay(birth.Year, birth.Month, birth.Day);
  DateTime cutoff;

  if (isLeapYearBirthday && !DateTime.IsLeapYear(reference.Year))
  {
    switch (ruleInEffect)
    {
      case LeapDayRule.OrdinalDay:
        cutoff = new DateTime(reference.Year, 1, 1)
                             .AddDays(birth.DayOfYear - 1);
        break;

      case LeapDayRule.LastDayOfMonth:
        cutoff = new DateTime(reference.Year, birth.Month, 1)
                             .AddMonths(1)
                             .AddDays(-1);
        break;

      default:
        throw new InvalidOperationException();
    }
  }
  else
  {
    cutoff = new DateTime(reference.Year, birth.Month, birth.Day);
  }

  int age = (reference.Year - birth.Year) + (reference >= cutoff ? 0 : -1);
  return age < 0 ? 0 : age;
}

Cần lưu ý rằng mã này giả định:

  • Một tính toán phương tây (châu Âu) của tuổi, và
  • Một lịch, giống như lịch Gregorian chèn một ngày nhuận vào cuối tháng.

19
TimeSpan diff = DateTime.Now - birthdayDateTime;
string age = String.Format("{0:%y} years, {0:%M} months, {0:%d}, days old", diff);

Tôi không chắc chính xác bạn muốn nó trả lại cho bạn như thế nào, vì vậy tôi chỉ tạo một chuỗi có thể đọc được.


18

Đây không phải là một câu trả lời trực tiếp, mà nhiều hơn một lý luận triết học về vấn đề trong tầm tay từ quan điểm gần như khoa học.

Tôi sẽ lập luận rằng câu hỏi không chỉ định đơn vị cũng như văn hóa để đo tuổi, hầu hết các câu trả lời dường như giả sử một đại diện hàng năm nguyên. Đơn vị SI cho thời gian là second, ergo câu trả lời chung chính xác phải là (tất nhiên giả sử đã được chuẩn hóa DateTimevà không liên quan gì đến các hiệu ứng tương đối tính):

var lifeInSeconds = (DateTime.Now.Ticks - then.Ticks)/TickFactor;

Theo cách tính tuổi của Kitô hữu theo năm:

var then = ... // Then, in this case the birthday
var now = DateTime.UtcNow;
int age = now.Year - then.Year;
if (now.AddYears(-age) < then) age--;

Trong tài chính có một vấn đề tương tự khi tính toán một cái gì đó thường được gọi là Phân số đếm ngày , mà đại khái là một số năm trong một khoảng thời gian nhất định. Và vấn đề tuổi tác thực sự là một vấn đề đo lường thời gian.

Ví dụ cho quy ước thực tế / thực tế (đếm tất cả các ngày "chính xác"):

DateTime start, end = .... // Whatever, assume start is before end

double startYearContribution = 1 - (double) start.DayOfYear / (double) (DateTime.IsLeapYear(start.Year) ? 366 : 365);
double endYearContribution = (double)end.DayOfYear / (double)(DateTime.IsLeapYear(end.Year) ? 366 : 365);
double middleContribution = (double) (end.Year - start.Year - 1);

double DCF = startYearContribution + endYearContribution + middleContribution;

Một cách khá phổ biến khác để đo thời gian nói chung là "xê-ri hóa" (anh chàng đặt tên cho quy ước ngày này phải nghiêm túc bị trippin '):

DateTime start, end = .... // Whatever, assume start is before end
int days = (end - start).Days;

Tôi tự hỏi chúng ta phải đi bao lâu trước một thời đại tương đối tính bằng giây trở nên hữu ích hơn so với xấp xỉ thô của chu kỳ trái đất trong suốt cuộc đời của một người cho đến nay :) Hay nói cách khác, khi một khoảng thời gian phải được đặt một vị trí hoặc một hàm đại diện cho chuyển động cho chính nó là hợp lệ :)


TickFactor là gì?
Bảo vệ

@Protiguity Ticks mỗi giây, được sử dụng để bình thường hóa bọ ve thành giây.
flindeberg

17

Đây là một giải pháp.

DateTime dateOfBirth = new DateTime(2000, 4, 18);
DateTime currentDate = DateTime.Now;

int ageInYears = 0;
int ageInMonths = 0;
int ageInDays = 0;

ageInDays = currentDate.Day - dateOfBirth.Day;
ageInMonths = currentDate.Month - dateOfBirth.Month;
ageInYears = currentDate.Year - dateOfBirth.Year;

if (ageInDays < 0)
{
    ageInDays += DateTime.DaysInMonth(currentDate.Year, currentDate.Month);
    ageInMonths = ageInMonths--;

    if (ageInMonths < 0)
    {
        ageInMonths += 12;
        ageInYears--;
    }
}

if (ageInMonths < 0)
{
    ageInMonths += 12;
    ageInYears--;
}

Console.WriteLine("{0}, {1}, {2}", ageInYears, ageInMonths, ageInDays);

Với chuỗi concat, điều này có thể xảy ra: 47 Yrs 11 Mo 7 ngày
JoshYates1980

16

Đây là một trong những câu trả lời chính xác nhất có thể giải quyết ngày sinh nhật của 29 tháng 2 so với bất kỳ năm nào của ngày 28 tháng 2.

public int GetAge(DateTime birthDate)
{
    int age = DateTime.Now.Year - birthDate.Year;

    if (birthDate.DayOfYear > DateTime.Now.DayOfYear)
        age--;

    return age;
}




Đó là ngày hôm nay! (Lần tiếp theo là bốn năm kể từ bây giờ.)
Peter Mortensen

15

Tôi có một phương pháp tùy chỉnh để tính tuổi, cộng với thông báo xác thực tiền thưởng chỉ trong trường hợp nó giúp:

public void GetAge(DateTime dob, DateTime now, out int years, out int months, out int days)
{
    years = 0;
    months = 0;
    days = 0;

    DateTime tmpdob = new DateTime(dob.Year, dob.Month, 1);
    DateTime tmpnow = new DateTime(now.Year, now.Month, 1);

    while (tmpdob.AddYears(years).AddMonths(months) < tmpnow)
    {
        months++;
        if (months > 12)
        {
            years++;
            months = months - 12;
        }
    }

    if (now.Day >= dob.Day)
        days = days + now.Day - dob.Day;
    else
    {
        months--;
        if (months < 0)
        {
            years--;
            months = months + 12;
        }
        days += DateTime.DaysInMonth(now.AddMonths(-1).Year, now.AddMonths(-1).Month) + now.Day - dob.Day;
    }

    if (DateTime.IsLeapYear(dob.Year) && dob.Month == 2 && dob.Day == 29 && now >= new DateTime(now.Year, 3, 1))
        days++;

}   

private string ValidateDate(DateTime dob) //This method will validate the date
{
    int Years = 0; int Months = 0; int Days = 0;

    GetAge(dob, DateTime.Now, out Years, out Months, out Days);

    if (Years < 18)
        message =  Years + " is too young. Please try again on your 18th birthday.";
    else if (Years >= 65)
        message = Years + " is too old. Date of Birth must not be 65 or older.";
    else
        return null; //Denotes validation passed
}

Phương thức gọi ở đây và chuyển ra giá trị datetime (MM / dd / yyyy nếu máy chủ được đặt thành ngôn ngữ Hoa Kỳ). Thay thế nó bằng bất cứ thứ gì một hộp thông báo hoặc bất kỳ thùng chứa nào để hiển thị:

DateTime dob = DateTime.Parse("03/10/1982");  

string message = ValidateDate(dob);

lbldatemessage.Visible = !StringIsNullOrWhitespace(message);
lbldatemessage.Text = message ?? ""; //Ternary if message is null then default to empty string

Hãy nhớ rằng bạn có thể định dạng tin nhắn theo bất kỳ cách nào bạn muốn.


14

Làm thế nào về giải pháp này?

static string CalcAge(DateTime birthDay)
{
    DateTime currentDate = DateTime.Now;         
    int approximateAge = currentDate.Year - birthDay.Year;
    int daysToNextBirthDay = (birthDay.Month * 30 + birthDay.Day) - 
        (currentDate.Month * 30 + currentDate.Day) ;

    if (approximateAge == 0 || approximateAge == 1)
    {                
        int month =  Math.Abs(daysToNextBirthDay / 30);
        int days = Math.Abs(daysToNextBirthDay % 30);

        if (month == 0)
            return "Your age is: " + daysToNextBirthDay + " days";

        return "Your age is: " + month + " months and " + days + " days"; ;
    }

    if (daysToNextBirthDay > 0)
        return "Your age is: " + --approximateAge + " Years";

    return "Your age is: " + approximateAge + " Years"; ;
}

12
private int GetAge(int _year, int _month, int _day
{
    DateTime yourBirthDate= new DateTime(_year, _month, _day);

    DateTime todaysDateTime = DateTime.Today;
    int noOfYears = todaysDateTime.Year - yourBirthDate.Year;

    if (DateTime.Now.Month < yourBirthDate.Month ||
        (DateTime.Now.Month == yourBirthDate.Month && DateTime.Now.Day < yourBirthDate.Day))
    {
        noOfYears--;
    }

    return  noOfYears;
}

10

Cách tiếp cận sau đây (trích từ Thư viện thời gian cho lớp .NET DateDiff ) xem xét lịch của thông tin văn hóa:

// ----------------------------------------------------------------------
private static int YearDiff( DateTime date1, DateTime date2 )
{
  return YearDiff( date1, date2, DateTimeFormatInfo.CurrentInfo.Calendar );
} // YearDiff

// ----------------------------------------------------------------------
private static int YearDiff( DateTime date1, DateTime date2, Calendar calendar )
{
  if ( date1.Equals( date2 ) )
  {
    return 0;
  }

  int year1 = calendar.GetYear( date1 );
  int month1 = calendar.GetMonth( date1 );
  int year2 = calendar.GetYear( date2 );
  int month2 = calendar.GetMonth( date2 );

  // find the the day to compare
  int compareDay = date2.Day;
  int compareDaysPerMonth = calendar.GetDaysInMonth( year1, month1 );
  if ( compareDay > compareDaysPerMonth )
  {
    compareDay = compareDaysPerMonth;
  }

  // build the compare date
  DateTime compareDate = new DateTime( year1, month2, compareDay,
    date2.Hour, date2.Minute, date2.Second, date2.Millisecond );
  if ( date2 > date1 )
  {
    if ( compareDate < date1 )
    {
      compareDate = compareDate.AddYears( 1 );
    }
  }
  else
  {
    if ( compareDate > date1 )
    {
      compareDate = compareDate.AddYears( -1 );
    }
  }
  return year2 - calendar.GetYear( compareDate );
} // YearDiff

Sử dụng:

// ----------------------------------------------------------------------
public void CalculateAgeSamples()
{
  PrintAge( new DateTime( 2000, 02, 29 ), new DateTime( 2009, 02, 28 ) );
  // > Birthdate=29.02.2000, Age at 28.02.2009 is 8 years
  PrintAge( new DateTime( 2000, 02, 29 ), new DateTime( 2012, 02, 28 ) );
  // > Birthdate=29.02.2000, Age at 28.02.2012 is 11 years
} // CalculateAgeSamples

// ----------------------------------------------------------------------
public void PrintAge( DateTime birthDate, DateTime moment )
{
  Console.WriteLine( "Birthdate={0:d}, Age at {1:d} is {2} years", birthDate, moment, YearDiff( birthDate, moment ) );
} // PrintAge

10

Câu hỏi kinh điển này xứng đáng với giải pháp Noda Time .

static int GetAge(LocalDate dateOfBirth)
{
    Instant now = SystemClock.Instance.Now;

    // The target time zone is important.
    // It should align with the *current physical location* of the person
    // you are talking about.  When the whereabouts of that person are unknown,
    // then you use the time zone of the person who is *asking* for the age.
    // The time zone of birth is irrelevant!

    DateTimeZone zone = DateTimeZoneProviders.Tzdb["America/New_York"];

    LocalDate today = now.InZone(zone).Date;

    Period period = Period.Between(dateOfBirth, today, PeriodUnits.Years);

    return (int) period.Years;
}

Sử dụng:

LocalDate dateOfBirth = new LocalDate(1976, 8, 27);
int age = GetAge(dateOfBirth);

Bạn cũng có thể quan tâm đến các cải tiến sau:

  • Đi qua trong đồng hồ như một IClock, thay vì sử dụng SystemClock.Instance, sẽ cải thiện testability.

  • Múi giờ mục tiêu có thể sẽ thay đổi, vì vậy bạn cũng muốn có một DateTimeZonetham số.

Xem thêm bài đăng trên blog của tôi về chủ đề này: Xử lý sinh nhật và các ngày kỷ niệm khác


Bạn có liên kết với Noda Time không?
Zimano

Tôi đã đóng góp cho nó, nhưng chủ yếu là của Jon Skeet.
Matt Johnson-Pint

9

Tôi đã sử dụng giải pháp của ScArcher2 để tính toán Năm chính xác cho độ tuổi của một người nhưng tôi cần đưa nó đi xa hơn và tính Tháng và Ngày của họ cùng với Năm.

    public static Dictionary<string,int> CurrentAgeInYearsMonthsDays(DateTime? ndtBirthDate, DateTime? ndtReferralDate)
    {
        //----------------------------------------------------------------------
        // Can't determine age if we don't have a dates.
        //----------------------------------------------------------------------
        if (ndtBirthDate == null) return null;
        if (ndtReferralDate == null) return null;

        DateTime dtBirthDate = Convert.ToDateTime(ndtBirthDate);
        DateTime dtReferralDate = Convert.ToDateTime(ndtReferralDate);

        //----------------------------------------------------------------------
        // Create our Variables
        //----------------------------------------------------------------------
        Dictionary<string, int> dYMD = new Dictionary<string,int>();
        int iNowDate, iBirthDate, iYears, iMonths, iDays;
        string sDif = "";

        //----------------------------------------------------------------------
        // Store off current date/time and DOB into local variables
        //---------------------------------------------------------------------- 
        iNowDate = int.Parse(dtReferralDate.ToString("yyyyMMdd"));
        iBirthDate = int.Parse(dtBirthDate.ToString("yyyyMMdd"));

        //----------------------------------------------------------------------
        // Calculate Years
        //----------------------------------------------------------------------
        sDif = (iNowDate - iBirthDate).ToString();
        iYears = int.Parse(sDif.Substring(0, sDif.Length - 4));

        //----------------------------------------------------------------------
        // Store Years in Return Value
        //----------------------------------------------------------------------
        dYMD.Add("Years", iYears);

        //----------------------------------------------------------------------
        // Calculate Months
        //----------------------------------------------------------------------
        if (dtBirthDate.Month > dtReferralDate.Month)
            iMonths = 12 - dtBirthDate.Month + dtReferralDate.Month - 1;
        else
            iMonths = dtBirthDate.Month - dtReferralDate.Month;

        //----------------------------------------------------------------------
        // Store Months in Return Value
        //----------------------------------------------------------------------
        dYMD.Add("Months", iMonths);

        //----------------------------------------------------------------------
        // Calculate Remaining Days
        //----------------------------------------------------------------------
        if (dtBirthDate.Day > dtReferralDate.Day)
            //Logic: Figure out the days in month previous to the current month, or the admitted month.
            //       Subtract the birthday from the total days which will give us how many days the person has lived since their birthdate day the previous month.
            //       then take the referral date and simply add the number of days the person has lived this month.

            //If referral date is january, we need to go back to the following year's December to get the days in that month.
            if (dtReferralDate.Month == 1)
                iDays = DateTime.DaysInMonth(dtReferralDate.Year - 1, 12) - dtBirthDate.Day + dtReferralDate.Day;       
            else
                iDays = DateTime.DaysInMonth(dtReferralDate.Year, dtReferralDate.Month - 1) - dtBirthDate.Day + dtReferralDate.Day;       
        else
            iDays = dtReferralDate.Day - dtBirthDate.Day;             

        //----------------------------------------------------------------------
        // Store Days in Return Value
        //----------------------------------------------------------------------
        dYMD.Add("Days", iDays);

        return dYMD;
}

9

Phiên bản SQL:

declare @dd smalldatetime = '1980-04-01'
declare @age int = YEAR(GETDATE())-YEAR(@dd)
if (@dd> DATEADD(YYYY, -@age, GETDATE())) set @age = @age -1

print @age  

8

Tôi đã thực hiện một thay đổi nhỏ đối với câu trả lời của Mark Soen : Tôi đã viết lại dòng thứ ba để biểu thức có thể được phân tích cú pháp dễ dàng hơn một chút.

public int AgeInYears(DateTime bday)
{
    DateTime now = DateTime.Today;
    int age = now.Year - bday.Year;            
    if (bday.AddYears(age) > now) 
        age--;
    return age;
}

Tôi cũng đã biến nó thành một chức năng vì mục đích rõ ràng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.