una - ¿Cómo calculo la edad de alguien en C#?
programa en c# que permita calcular la edad de una persona (30)
¿Qué tal esta solución?
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"; ;
}
Dado un
DateTime
representa el cumpleaños de una persona, ¿cómo calculo su edad en años?
Aquí hay una solución.
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);
El siguiente enfoque (extracto de Time Period Library para .NET clase DateDiff ) considera el calendario de la información cultural:
// ----------------------------------------------------------------------
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
Uso:
// ----------------------------------------------------------------------
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
Esta es una de las respuestas más precisas que pueden resolver el cumpleaños del 29 de febrero en comparación con cualquier año del 28 de febrero.
public int GetAge(DateTime birthDate)
{
int age = DateTime.Now.Year - birthDate.Year;
if (birthDate.DayOfYear > DateTime.Now.DayOfYear)
age--;
return age;
}
Esta no es una respuesta directa, sino más bien un razonamiento filosófico sobre el problema en cuestión desde un punto de vista casi científico.
Yo diría que la pregunta no especifica la unidad ni la cultura en la que medir la edad, la mayoría de las respuestas parecen asumir una representación anual entera.
La unidad SI para el tiempo es
second
, ergo, la respuesta genérica correcta debería ser (por supuesto, asumiendo que está normalizada
DateTime
y sin tener en cuenta en absoluto los efectos relativistas):
var lifeInSeconds = (DateTime.Now.Ticks - then.Ticks)/TickFactor;
En la forma cristiana de calcular la edad en años:
var then = ... // Then, in this case the birthday
var now = DateTime.UtcNow;
int age = now.Year - then.Year;
if (now.AddYears(-age) < then) age--;
En finanzas, existe un problema similar al calcular algo que a menudo se conoce como la fracción de recuento de días , que aproximadamente es un número de años para un período determinado. Y la cuestión de la edad es realmente una cuestión de medición del tiempo.
Ejemplo para la convención real / real (contando todos los días "correctamente"):
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;
Otra forma bastante común de medir el tiempo en general es mediante la "serialización" (el tipo que nombró esta fecha en la convención debe haber sido muy importante):
DateTime start, end = .... // Whatever, assume start is before end
int days = (end - start).Days;
Me pregunto cuánto tiempo tendremos que pasar antes de que una era relativista en segundos sea más útil que la aproximación aproximada de los ciclos de la Tierra alrededor del Sol durante la vida de uno hasta el momento :) O en otras palabras, cuando un período debe recibir una ubicación o una función que representa el movimiento por sí mismo para ser válido :)
Esta pregunta clásica merece una solución de 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;
}
Uso:
LocalDate dateOfBirth = new LocalDate(1976, 8, 27);
int age = GetAge(dateOfBirth);
También te pueden interesar las siguientes mejoras:
-
Pasar el reloj como
IClock
, en lugar de usarSystemClock.Instance
, mejoraría la capacidad de prueba. -
La zona horaria de destino probablemente cambiará, por lo que también querrá un
DateTimeZone
parámetro.
Véase también la publicación de mi blog sobre este tema: Manejo de cumpleaños y otros aniversarios
Tengo un método personalizado para calcular la edad, más un mensaje de validación de bonificación en caso de que ayude:
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
}
El método llama aquí y pasa el valor de fecha y hora (MM / dd / aaaa si el servidor está configurado a la configuración regional de los Estados Unidos). Reemplace esto con cualquier cosa en un buzón de mensajes o en cualquier contenedor para mostrar:
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
Recuerda que puedes formatear el mensaje como quieras.
Utilicé la solución de ScArcher2 para un cálculo preciso del año de la edad de una persona, pero necesitaba ir más allá y calcular los meses y días junto con los años.
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;
}
Versió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
¿Necesitamos considerar a personas menores de 1 año? Como cultura china, describimos la edad de los bebés pequeños como 2 meses o 4 semanas.
A continuación se muestra mi implementación, no es tan simple como lo que imaginé, especialmente para tratar con fechas como 2/28.
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";
}
}
Esta implementación ha pasado por debajo de los casos de prueba.
[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);
}
Espero que sea de ayuda.
2 Los principales problemas a resolver son:
1. Calcular la edad exacta - en años, meses, días, etc.
2. Calcular la edad generalmente percibida : a las personas generalmente no les importa la edad que tienen exactamente, solo les importa cuándo es su cumpleaños en el año en curso.
La solución para 1 es obvia:
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
La solución para 2 es la que no es tan precisa para determinar la edad total, pero la gente la percibe como precisa. Las personas también suelen usarlo cuando calculan su edad "manualmente":
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
}
Notas a 2 .:
- Esta es mi solución preferida
- No podemos usar DateTime.DayOfYear o TimeSpans, ya que cambian el número de días en años bisiestos
- He puesto poco más líneas para facilitar la lectura.
Solo una nota más ... Me gustaría crear 2 métodos estáticos sobrecargados para él, uno para uso universal, segundo para uso amigable:
public static int GetAge(DateTime bithDay, DateTime today)
{
//chosen solution method body
}
public static int GetAge(DateTime birthDay)
{
return GetAge(birthDay, DateTime.Now);
}
Aquí hay otra respuesta más:
public static int AgeInYears(DateTime birthday, DateTime today)
{
return ((today.Year - birthday.Year) * 372 + (today.Month - birthday.Month) * 31 + (today.Day - birthday.Day)) / 372;
}
Esto ha sido ampliamente probado en unidades. Se ve un poco "mágico". El número 372 es el número de días que habría en un año si cada mes tuviera 31 días.
La explicación de por qué funciona ( levantado de aquí ) es:
Vamos a configurar
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
Sabemos que lo que necesitamos es
Yn-Yb
si ya se ha alcanzado la fecha,Yn-Yb-1
si no lo ha hecho.a) Si
Mn<Mb
, tenemos-341 <= 31*(Mn-Mb) <= -31 and -30 <= Dn-Db <= 30
-371 <= 31*(Mn - Mb) + (Dn - Db) <= -1
Con división entera
(31*(Mn - Mb) + (Dn - Db)) / 372 = -1
b) Si
Mn=Mb
yDn<Db
, tenemos31*(Mn - Mb) = 0 and -30 <= Dn-Db <= -1
Con división entera, de nuevo
(31*(Mn - Mb) + (Dn - Db)) / 372 = -1
c) Si
Mn>Mb
, tenemos31 <= 31*(Mn-Mb) <= 341 and -30 <= Dn-Db <= 30
1 <= 31*(Mn - Mb) + (Dn - Db) <= 371
Con división entera
(31*(Mn - Mb) + (Dn - Db)) / 372 = 0
d) Si
Mn=Mb
yDn>Db
, tenemos31*(Mn - Mb) = 0 and 1 <= Dn-Db <= 3
0Con división entera, de nuevo
(31*(Mn - Mb) + (Dn - Db)) / 372 = 0
e) Si
Mn=Mb
yDn=Db
, tenemos31*(Mn - Mb) + Dn-Db = 0
y por lo tanto
(31*(Mn - Mb) + (Dn - Db)) / 372 = 0
Esta es la versión que usamos aquí. Funciona, y es bastante simple. Es la misma idea que la de Jeff, pero creo que es un poco más clara porque separa la lógica para restar una, por lo que es un poco más fácil de entender.
public static int GetAge(this DateTime dateOfBirth, DateTime dateAsAt)
{
return dateAsAt.Year - dateOfBirth.Year - (dateOfBirth.DayOfYear < dateAsAt.DayOfYear ? 0 : 1);
}
Podría expandir el operador ternario para hacerlo aún más claro, si cree que ese tipo de cosas no está claro.
Obviamente, esto se hace como un método de extensión en
DateTime
, pero claramente puedes tomar esa línea de código que hace el trabajo y ponerla en cualquier lugar.
Aquí tenemos otra sobrecarga del método de Extensión que pasa en
DateTime.Now
, solo para completar.
Esta es una forma extraña de hacerlo, pero si le da formato a la fecha para
yyyymmdd
y resta la fecha de nacimiento de la fecha actual, entonces elimine los últimos 4 dígitos que tiene la edad :)
No sé C #, pero creo que esto funcionará en cualquier idioma.
20080814 - 19800703 = 280111
Suelte los últimos 4 dígitos =
28
.
Código C #:
int now = int.Parse(DateTime.Now.ToString("yyyyMMdd"));
int dob = int.Parse(dateOfBirth.ToString("yyyyMMdd"));
int age = (now - dob) / 10000;
O alternativamente, sin toda la conversión de tipo en la forma de un método de extensión. Comprobación de error omitido:
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;
}
Esto da "más detalle" a esta pregunta. Tal vez esto es lo que estás buscando
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);
He creado una función definida por el usuario de SQL Server para calcular la edad de alguien, dada su fecha de nacimiento. Esto es útil cuando lo necesita como parte de una consulta:
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;
}
};
He pasado algún tiempo trabajando en esto y se me ocurrió calcular la edad de alguien en años, meses y días. He probado contra el problema del 29 de febrero y los años bisiestos y parece funcionar, agradecería cualquier comentario:
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++;
}
}
La forma más simple que he encontrado es esta. Funciona correctamente para las regiones de los Estados Unidos y Europa occidental. No puedo hablar con otros lugares, especialmente lugares como China. 4 comparaciones adicionales, como máximo, después del cálculo inicial de la edad.
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 ;
}
Estaba revisando las respuestas a esto y noté que nadie ha hecho referencia a las implicaciones reglamentarias / legales de los nacimientos en el día del salto. Por ejemplo, de acuerdo con Wikipedia , si nace el 29 de febrero en varias jurisdicciones, el año de su cumpleaños no variado varía:
- En el Reino Unido y Hong Kong: es el día ordinal del año, por lo que al día siguiente, el 1 de marzo es tu cumpleaños.
- En Nueva Zelanda: es el día anterior, el 28 de febrero para los fines de la licencia de conducir, y el 1 de marzo para otros fines.
- Taiwán: es el 28 de febrero.
Y por lo que puedo decir, en los EE. UU., Los estatutos guardan silencio sobre el asunto, dejándolo a la ley común y a cómo varios organismos reguladores definen las cosas en sus reglamentos.
Para ello, una mejora:
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;
}
Cabe señalar que este código asume:
- Un cálculo de edad occidental (europeo), y
- Un calendario, como el calendario gregoriano que inserta un solo día bisiesto al final de un mes.
La mejor manera que conozco por años bisiestos y todo es:
DateTime birthDate = new DateTime(2000,3,1);
int age = (int)Math.Floor((DateTime.Now - birthDate).TotalDays / 365.25D);
Espero que esto ayude.
La respuesta simple a esto es aplicar
AddYears
como se muestra a continuación porque este es el único método nativo para agregar años al 29 de febrero de años bisiestos y obtener el resultado correcto del 28 de febrero para los años comunes.
Algunos creen que el 1 de marzo es el cumpleaños de las fugas, pero ni .Net ni ninguna regla oficial lo respalda, ni la lógica común explica por qué algunos nacidos en febrero deberían tener el 75% de sus cumpleaños en otro mes.
Además, un método Age se presta para ser agregado como una extensión de
DateTime
.
De esta forma podrás obtener la edad de la forma más sencilla posible:
- Elemento de lista
int age = birthDate.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;
}
}
Ahora, ejecuta esta prueba:
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();
}
}
El ejemplo de la fecha crítica es este:
Fecha de nacimiento: 2000-02-29 Fecha posterior: 2011-02-28 Edad: 11
Salida:
{
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
}
Y para la fecha posterior 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
}
Llego tarde a la fiesta, pero aquí hay un resumen:
int age = new DateTime(DateTime.Now.Subtract(birthday).Ticks).Year-1;
Manteniéndolo simple (y posiblemente estúpido :)).
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.");
Mi sugerencia
int age = (int) ((DateTime.Now - bday).TotalDays/365.242199);
Eso parece tener el año cambiando en la fecha correcta. (Detecto pruebas hasta los 107 años)
No creo que ninguna de las respuestas proporcione culturas que calculen la edad de manera diferente. Véase, por ejemplo, el cálculo de la edad en el este de Asia versus el de Occidente.
Cualquier respuesta real tiene que incluir la localización. El patrón de estrategia probablemente estaría en orden en este ejemplo.
No sé cómo se puede aceptar la solución equivocada. El fragmento de C # correcto fue escrito por Michael Stum
Aquí hay un fragmento de prueba:
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
Aquí tienes los métodos:
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;
}
Otra función, no hecha por mí, pero encontrada en la web y refinada un poco:
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;
}
Solo dos cosas que me vienen a la mente: ¿Qué pasa con las personas de países que no usan el calendario gregoriano? DateTime.Now está en la cultura específica del servidor, creo. Tengo absolutamente 0 conocimientos sobre cómo trabajar realmente con calendarios asiáticos y no sé si hay una manera fácil de convertir fechas entre calendarios, pero en caso de que se estén preguntando sobre esos tipos chinos del año 4660 :-)
Una solución fácil de entender y simple.
// 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--;
Sin embargo, esto supone que usted está buscando la idea occidental de la edad y que no está usando la contabilidad del este asiático .
Yo uso esto:
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;
}
}
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;
}
TimeSpan diff = DateTime.Now - birthdayDateTime;
string age = String.Format("{0:%y} years, {0:%M} months, {0:%d}, days old", diff);
No estoy seguro de cómo exactamente te gustaría que te lo devolvieran, así que acabo de hacer una cadena legible