2011-06-23 13 views
7

Estoy buscando una forma de convertir objetos de fecha y hora al año decimal. A continuación se muestra un ejemplopython cómo convertir fechas de fecha y hora a años decimales

>>> obj = SomeObjet() 
>>> obj.DATE_OBS 
datetime.datetime(2007, 4, 14, 11, 42, 50) 

¿Cómo convierto datetime.datetime (2007, 4, 14, 11, 42, 50) al año decimales? Desde este formato dd/mm/aaaa hasta este tipo de formato aaaa.aaaa

+0

¿Puedes dar algún ejemplo? ¿Qué quieres decir con "años decimales"? –

+0

De este formato dd/mm/aaaa a este tipo de formato aaaa.aaaa – user739807

+0

¿Quiere decir, para convertirlo en un número de coma flotante? Me gusta: ¿convierte día/mes/hora/etc. en un número? Si es así, entonces necesita calcularlo usted mismo. –

Respuesta

18
from datetime import datetime as dt 
import time 

def toYearFraction(date): 
    def sinceEpoch(date): # returns seconds since epoch 
     return time.mktime(date.timetuple()) 
    s = sinceEpoch 

    year = date.year 
    startOfThisYear = dt(year=year, month=1, day=1) 
    startOfNextYear = dt(year=year+1, month=1, day=1) 

    yearElapsed = s(date) - s(startOfThisYear) 
    yearDuration = s(startOfNextYear) - s(startOfThisYear) 
    fraction = yearElapsed/yearDuration 

    return date.year + fraction 

Demostración:

>>> toYearFraction(dt.today()) 
2011.47447514 

Este método es probablemente una precisión de la segunda (o la hora si el horario de verano u otras cosas extrañas regionales están en vigor). También funciona correctamente durante leapyears. Si necesita una resolución drástica (como debido a cambios en la rotación de la Tierra), es mejor que consulte un servicio de red.

+0

Mi respuesta es mucho más simple y ofrece una flotación igualmente comparable. Ninguna de nuestras soluciones es exacta, pero no existe una forma estándar generalmente aceptable de convertir un cierto momento en el tiempo en una representación decimal de un año, ¿verdad? – Kimvais

+0

@Kimvais sí, hay; es una cantidad bien definida. Esta es una precisión de una hora, más si las bibliotecas se ocupan de los ahorros de luz diurna (que no creo que tengan). – ninjagecko

+0

Lo sentimos, significa 'estándar generalmente aceptado' no 'generalmente aceptable ...' – Kimvais

2

Supongo que está utilizando esto para comparar valores de fecha y hora. Para hacer eso, utilice los objetos timedelta en lugar de reiniciar la rueda.

Ejemplo:

>>> from datetime import timedelta 
>>> from datetime import datetime as dt 
>>> d = dt.now() 
>>> year = timedelta(days=365) 
>>> tomorrow = d + timedelta(days=1) 
>>> tomorrow + year > d + year 
True 

Si por alguna razón usted realmente necesidad años decimales, datetime objetos método strftime() le puede dar una representación entera de día del año si se le pide %j - si se trata de lo que está buscando, vea a continuación una muestra simple (solo con resolución de 1 día):

>>> from datetime import datetime 
>>> d = datetime(2007, 4, 14, 11, 42, 50) 
>>> (float(d.strftime("%j"))-1)/366 + float(d.strftime("%Y")) 
2007.2814207650274 
+0

Este método es inexacto en aproximadamente 1-2 días dependiendo del año y no funciona para años bisiestos. También estoy confundido por qué está asumiendo 367 días por año. – ninjagecko

+0

367 para que el último día del año bisiesto no sea exactamente el próximo año. – Kimvais

+1

que no es lo correcto. Además, tienes otro error: siempre saltas '2010.0' y' 2011.0' y todos esos otros números, porque datetime (year = 2011, month = 1, day = 1) .strftime ("% j") es 1 no 0. La solución es restar 1, pero eso todavía es inexacto por día durante leapyears. – ninjagecko

0

Esto es un poco más simple que las otras soluciones:

import datetime 
def year_fraction(date): 
    start = datetime.date(date.year, 1, 1).toordinal() 
    year_length = datetime.date(date.year+1, 1, 1).toordinal() - start 
    return date.year + float(date.toordinal() - start)/year_length 

>>> print year_fraction(datetime.datetime.today()) 
2016.32513661 

Tenga en cuenta que este calcula la fracción basada en el principio de la jornada, por lo que 31 de diciembre será de 0,997, no 1.0.

0

Sorprendido, nadie ha mencionado esto ... pero los objetos datetime.timedelta que resultan de sustraer objetos datetime.datetime tienen un método de división. Por lo tanto, se puede utilizar la función simple

from datetime import datetime 
def datetime2year(dt): 
    year_part = dt - datetime(year=dt.year, month=1, day=1) 
    year_length = datetime(year=dt.year+1, month=1, day=1) - datetime(year=dt.year, month=1, day=1) 
    return dt.year + year_part/year_length 

donde la división es entre datetime.timedelta objetos.

0

Es posible calcular la fecha decimal usando la fecha juliana de Pandas y las siguientes fórmulas.

En el caso de que su trama de datos pandas tiene un índice que es de fecha y hora:

JD=dat.index.to_julian_date() #create julian date 
L= JD+68569 
N= 4*L/146097 
L= L-(146097*N+3)/4 
I= 4000*(L+1)/1461001 
L= L-1461*I/4+31 
J= 80*L/2447 
K= L-2447*J/80 
L= J/11 
J= J+2-12*L 
decimal_date= 100*(N-49)+I+L 

decimal_date es una serie de la fecha (en el mismo TZ como el índice de trama de datos) en forma de algo así como 2007.123452 .

Adapted from this post.

0

Después de implementar la solución aceptada, tuve la revelación de que esta versión moderna pandas es idéntico, y mucho más simple:

dat['decimal_date']=dat.index.year+ (dat.index.dayofyear -1)/365 

debe usarse en un índice de fecha y hora pandas trama de datos.Agregar esta publicación de solución aparece en la parte superior de mi búsqueda de Google para este problema.

Cuestiones relacionadas