algorithm - una - como sacar la edad con meses y dias en excel
¿Cómo puedo calcular la edad de una persona en año, mes, días? (12)
Quiero calcular la edad de una persona dada la fecha de nacimiento y la fecha actual en años, meses y días con respecto a la fecha actual.
Por ejemplo:
>>> calculate_age(2008, 01, 01)
1 years, 0 months, 16 days
Se apreciará cualquier apuntador a un algoritmo que haga eso.
Supongo que las preguntas son más amplias que un solo lenguaje de programación. Si está usando C #, puede usar DateTimeOffset para calcular esto.
var offset = DateTimeOffset.MinValue;
var lastDate = DateTime.Today;
var firstDate = new DateTime(2006,11,19);
var diff = (lastDate- firstDate);
var resultWithOffset = DateTimeOffset.MinValue.AddDays(diff.TotalDays);
var result = resultWithOffset.AddDays(-offset.Day).AddMonths(-offset.Month).AddYears(-offset.Year);
result.Day
, result.Month
, result.Year
contendrá la información que necesita.
Dado que obviamente está usando Python: Cree objetos datetime, uno con "cumpleaños" y otro con "ahora", restelos y lea la edad del objeto timedelta resultante.
¿Por qué molestarse con cosas como los años bisiestos?
Hay una discusión en python-list sobre por qué calcular una edad no es una tarea tan sencilla .
De esa discusión encontré esta implementación (que no copiaré y pegaré aquí porque no es mía).
Sin embargo, no he encontrado ninguna gota en las bibliotecas.
Creo que debes especificar los requisitos un poco mejor.
Digamos que la fecha de nacimiento es 2008-02-01 y el día es 2009-01-31
Cual es el resultado?
- 0 años, 11 meses y 31 días?
- 0 años, 10 meses y 28 + 31 = 59 días?
- 0 años, 10 meses y 29 + 31 = 60 días?
Dado que los años, meses e incluso días pueden tener longitudes desiguales, no puede comenzar restando las dos fechas para obtener una duración simple. Si desea que el resultado coincida con la forma en que los seres humanos tratan las fechas, en su lugar debe trabajar con fechas reales, utilizando las funciones incorporadas de su idioma que comprenden las fechas mejor que nunca.
La forma en que se escriba ese algoritmo depende del idioma que use, porque cada idioma tiene un conjunto diferente de funciones. Mi propia implementación en Java, usando el incómodo pero técnicamente correcto GregorianCalendar:
Term difference (Date from, Date to) {
GregorianCalendar cal1 = new GregorianCalendar();
cal1.setTimeInMillis(from.getTime());
GregorianCalendar cal2 = new GregorianCalendar();
cal2.setTimeInMillis(to.getTime());
int years = cal2.get(Calendar.YEAR) - cal1.get(Calendar.YEAR);
int months = cal2.get(Calendar.MONTH) - cal1.get(Calendar.MONTH);
int days = cal2.get(Calendar.DAY_OF_MONTH) - cal1.get(Calendar.DAY_OF_MONTH);
if (days < 0) {
months--;
days += cal1.getActualMaximum(Calendar.DAY_OF_MONTH);
}
if (months < 0) {
years--;
months += 12;
}
return new Term(years, months, days);
}
Esto puede no ser perfecto, pero ofrece resultados legibles por humanos. El término es una clase propia para almacenar períodos de estilo humano, ya que las bibliotecas de fechas de Java no tienen una.
Para proyectos futuros, planeo pasar a la mejor biblioteca de fecha / hora de Joda, que sí tiene una clase de Período y probablemente tendrá que volver a escribir esta función.
Esa no es una pregunta fácil, ya que por encima de los días (si no tomamos en cuenta los segundos intercalares ) no hay fórmulas fáciles.
Los meses pueden constar de 28, 29, 30 o 31 días; los años pueden ser 365 o 366 días. Por lo tanto, surgen problemas cuando intenta calcular las unidades completas de tiempo durante meses y años.
Aquí hay un artículo interesante que toma en cuenta todos los aspectos complejos para resolver su pregunta en Java.
Otros aquí tienen la idea correcta: simplemente necesita poder extenderlo a otros idiomas. Muchos sistemas informáticos cuentan el tiempo en segundos desde un punto específico (la "época" o "fecha de referencia") y calculan la fecha a partir de ahí, además de ofrecer métodos para convertir segundos a fechas. Debería poder obtener la hora actual en segundos, convertir la fecha de nacimiento en segundos de la época, restar los dos valores y luego dividirlos por la cantidad de segundos en un día:
int timenow = time(0);
struct tm birthday = { tm_mday = 16 , .tm_mon = 1 , .tm_year = 1963 };
int timebirth = mktime( &birthday_tm );
int diff_sec = timenow - timebirth;
int days = diff_sec / ( 24 * 60 * 60);
printf("%d - %d = %d seconds, or %d days/n", timenow, timebirth, diff_sec, days);
El error en este código particular es que mktime () no puede tratar con fechas anteriores a la época, que es el 1 de enero de 1970 en sistemas basados en Unix. Problemas similares existirán en otros sistemas dependiendo de cómo cuenten el tiempo. El algoritmo general debería funcionar, solo tienes que conocer tus límites en sistemas específicos.
Aquí está esto usando la regla de préstamo de las matemáticas.
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);
La implementación Swift de la respuesta de Dreeves.
PD. en lugar de (y, m, d) (ynow, mnow, dnow) como entradas, utilizo dos NSDate, que pueden ser más útiles en los usos del mundo real.
extension NSDate {
convenience init(ageDateString:String) {
let dateStringFormatter = NSDateFormatter()
dateStringFormatter.dateFormat = "yyyy-MM-dd"
dateStringFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
let d = dateStringFormatter.dateFromString(ageDateString)!
self.init(timeInterval:0, sinceDate:d)
}
func ageFrom(date: NSDate) -> (Int, Int, Int) {
let cal = NSCalendar.currentCalendar()
let y = cal.component(NSCalendarUnit.Year, fromDate: date)
let m = cal.component(NSCalendarUnit.Month, fromDate: date)
let d = cal.component(NSCalendarUnit.Day, fromDate: date)
let ynow = cal.component(NSCalendarUnit.Year, fromDate: self)
let mnow = cal.component(NSCalendarUnit.Month, fromDate: self)
let dnow = cal.component(NSCalendarUnit.Day, fromDate: self)
let t0 = y * 12 + m - 1 // total months for birthdate.
var t = ynow * 12 + mnow - 1; // total months for Now.
var dm = t - t0; // delta months.
if(dnow >= d) {
return (Int(floor(Double(dm)/12)), dm % 12, dnow - d)
}
dm--
t--
return (Int(floor(Double(dm)/12)), dm % 12, Int((self.timeIntervalSince1970 - NSDate(ageDateString: "/(Int(floor(Double(t)/12)))-/(t%12 + 1)-/(d)").timeIntervalSince1970)/60/60/24))
}
}
// sample usage
let birthday = NSDate(ageDateString: "2012-7-8")
print(NSDate().ageFrom(birthday))
Sé que está un poco desactualizado, pero aquí hay un código simple que utilicé, con el poder de la biblioteca de Python (Python 3.5 para anotaciones, pero funciona sin).
from datetime import date, timedelta
def age(birth: date) -> (int, int, int):
"""
Get a 3-int tuple telling the exact age based on birth date.
"""
today_age = date(1, 1, 1) + (date.today() - birth)
# -1 because we start from year 1 and not 0.
return (today_age.year - 1, today_age.month - 1, today_age.day - 1)
Esta es una forma de hacerlo si está dispuesto a violar el principio de "debería ser un número entero de años en mi cumpleaños". Tenga en cuenta que ese principio no es estrictamente cierto, debido a los años bisiestos, por lo que el siguiente es realmente más preciso, aunque tal vez menos intuitivo. Si quieres saber el número exacto de años que alguien tiene, esta es la forma en que lo haría.
Primero convierta tanto la fecha de nacimiento como la hora actual en el tiempo de época (número de segundos desde el comienzo de los tiempos, es decir, 1970 en tierras de Unix) y reste sus datos. Vea, por ejemplo, esta pregunta sobre cómo hacer eso: ¿Cómo convierto una fecha / hora a hora de época (también conocida como tiempo de Unix, segundos desde 1970) en Perl? . Ahora tiene la edad exacta de la persona en segundos y necesita convertirla en una cadena como "36 años, 3 meses, 8 días".
Aquí hay un pseudocódigo para hacerlo. Debe ser sencillo eliminar las semanas u horas o las partes que no desee ...
daysInYear = 365.2425; # Average lengh of a year in the gregorian calendar.
# Another candidate for len of a year is a sidereal year,
# 365.2564 days. cf. http://en.wikipedia.org/wiki/Year
weeksInYear = daysInYear / 7;
daysInMonth = daysInYear / 12;
weeksInMonth = daysInMonth / 7;
sS = 1;
mS = 60*sS;
hS = 60*mS;
dS = 24*hS;
wS = 7*dS;
oS = daysInMonth*dS;
yS = daysInYear*dS;
# Convert a number of seconds to years,months,weeks,days,hrs,mins,secs.
seconds2str[secs]
{
local variables:
y, yQ= False, o, oQ= False, w, wQ= False,
d, dQ= False, h, hQ= False, m, mQ= False, s= secs;
if(secs<0) return "-" + seconds2str(-secs); # "+" is string concatenation.
y = floor(s/yS);
if(y>0) yQ = oQ = wQ = dQ = hQ = mQ = True;
s -= y * yS;
o = floor(s/oS);
if(o>0) oQ = wQ = dQ = hQ = mQ = True;
s -= o * oS;
w = floor(s/wS);
if(w>0) wQ = dQ = hQ = mQ = True;
s -= w * wS;
d = floor(s/dS);
if(d>0) dQ = hQ = mQ = True;
s -= d * dS;
h = floor(s/hS);
if(h>0) hQ = mQ = True;
s -= h * hS;
m = floor(s/mS);
if(m>0) mQ = True;
s -= m * mS;
return
(yQ ? y + " year" + maybeS(y) + " " : "") +
(oQ ? o + " month" + maybeS(o) + " " : "") +
(wQ ? w + " week" + maybeS(w) + " " : "") +
(dQ ? d + " day" + maybeS(d) + " " : "") +
(hQ ? dd(h) + ":" : "") +
(mQ ? dd(m) + ":" + dd(round(s)) + "s" : s + "s");
}
# Returns an "s" if n!=1 and "" otherwise.
maybeS(n) { return (n==1 ? "" : "s"); }
# Double-digit: takes a number from 0-99 and returns it as a 2-character string.
dd(n) { return (n<10 ? "0" + tostring(n) : tostring(n)); }
Primero, tenga en cuenta la suposición de que si, por ejemplo, nació el 1 de febrero y el 1 de marzo siguiente, tiene exactamente 1 mes, aunque su edad en días es solo 28, menos que la duración de un mes promedio . Los años también tienen una duración variable (debido a los años bisiestos), lo que significa que su edad en su cumpleaños generalmente no es un número entero exacto de años. Si desea expresar la cantidad exacta de tiempo que ha estado vivo en años / meses / días, consulte mi otra respuesta. Pero lo más probable es que quieras cambiarlo para que nazca el 1 de febrero significa que cada 1 de febrero tienes X años, 0 meses y 0 días, y el día 1 de cada mes tienes X años, Y meses, y 0 días.
En ese caso, sigue leyendo. (NB: lo siguiente solo funciona para las fechas en el pasado.)
Dada una fecha de nacimiento, (y,m,d)
, la fecha actual, (ynow,mnow,dnow)
, y una función tm()
que da unix / época de tiempo para una fecha determinada , lo siguiente dará como resultado un 3- lista de elementos que da la edad como {años, meses, días}:
t0 = y*12 + m - 1; # total months for birthdate.
t = ynow*12 + mnow - 1; # total months for Now.
dm = t - t0; # delta months.
if(dnow >= d) return [floor(dm/12), mod(dm,12), dnow-d];
dm--; t--;
return [floor(dm/12), mod(dm,12),
(tm({ynow,mnow,dnow}) - tm({floor(t/12), mod(t,12)+1, d}))/60/60/24];
Lo siguiente es un algoritmo equivalente si no te gustan todos los pisos y mods. Pero creo que lo anterior es mejor. Por un lado, evita llamar a tm()
cuando no es necesario.
{yl, ml} = {ynow, mnow};
if(mnow < m || mnow == m && dnow < d) yl--;
if(dnow < d) ml--;
years = yl - y;
months = ml + 12*(ynow - yl) - m;
yl = ynow;
if(ml == 0) { ml = 12; yl--; }
days = (tm({ynow, mnow, dnow}) - tm({yl, ml, d}))/60/60/24;
return [years, months, days];