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?
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?
Câu trả lời:
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 Á .
Đây là một cách kỳ lạ để làm điều đó, nhưng nếu bạn định dạng ngày yyyymmdd
và 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;
}
20180101 - 20171231 = 8870
. Thả 4 chữ số cuối và bạn có (ngụ ý) 0
cho độ tuổi. Làm thế nào bạn có được 1
?
Đâ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;
}
Câu trả lời đơn giản cho vấn đề này là áp dụng AddYears
như 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ể:
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
}
date.Age(other)
?
Đề 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.)
days in a year = 365.242199
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 :-)
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.:
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);
}
Đây là một lót:
int age = new DateTime(DateTime.Now.Subtract(birthday).Ticks).Year-1;
Đâ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.
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);
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;
}
}
Đ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);
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;
}
};
Đâ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-1
nế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=Mb
vàDn<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=Mb
vàDn>Db
, chúng ta có31*(Mn - Mb) = 0 and 1 <= Dn-Db <= 3
0Với phép chia số nguyên, một lần nữa
(31*(Mn - Mb) + (Dn - Db)) / 372 = 0
e) Nếu
Mn=Mb
vàDn=Db
, chúng ta có31*(Mn - Mb) + Dn-Db = 0
và do đó
(31*(Mn - Mb) + (Dn - Db)) / 372 = 0
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++;
}
}
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.
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.");
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:
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:
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.
Đâ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 DateTime
và 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ệ :)
Đâ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);
Đâ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;
}
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.
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"; ;
}
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;
}
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
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 DateTimeZone
tham 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
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;
}
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.