Trabajando con Datetime y Time


Photo by Pixabay on Pexels.com

Comenzamos…

Dejamos ya importadas las librerías que vamos a necesitar:

import datetime
import time
import numpy as np
from datetime import datetime,timedelta
from zoneinfo import ZoneInfo, available_timezones
import calendar
%matplotlib inline
import pandas as pd
import sys

A raiz de la actualización del código que soporta al @elgalloaurora he estado jugando y probando con el tratamiento y gestión de horas con sus diferentes versiones “naive” y “no naive” y el cambio entre UTC, referenciadas a diferentes timezones y en modo segundos desde un determinado epoch. He escrito este pqueño doc para que me sirva de memoria para futuros trabajos

Vemos cosas básicas, como :

Horal actual local

datetime.now(ZoneInfo('Europe/Madrid'))
datetime.datetime(2024, 5, 26, 11, 50, 47, 425942, tzinfo=zoneinfo.ZoneInfo(key='Europe/Madrid'))
datetime.now(ZoneInfo('US/Hawaii'))
datetime.datetime(2024, 5, 25, 23, 50, 47, 666428, tzinfo=zoneinfo.ZoneInfo(key='US/Hawaii'))

y aquí se puede encontrar todas las zonas disponibles:

available_timezones()
{'Africa/Abidjan',
 'Africa/Accra',
 'Africa/Addis_Ababa',
 'Africa/Algiers',
 'Africa/Asmara',
 'Africa/Asmera',
 'Africa/Bamako',
 'Africa/Bangui',
 'Africa/Banjul',
 'Africa/Bissau',
 'Africa/Blantyre',
 'Africa/Brazzaville',
 'Africa/Bujumbura',
 'Africa/Cairo',
 'Africa/Casablanca',
 'Africa/Ceuta',
 'Africa/Conakry',
 .....
 'US/Samoa',
 'UTC',
 'Universal',
 'W-SU',
 'WET',
 'Zulu',
 'build/etc/localtime'}

Otra manera de conseguir la hora actual en otra zona horaría es con astimezone

datetime.now(ZoneInfo('Europe/Madrid')).astimezone(ZoneInfo('Europe/Lisbon'))
datetime.datetime(2024, 5, 26, 10, 50, 49, 27417, tzinfo=zoneinfo.ZoneInfo(key='Europe/Lisbon'))

o directamente:

datetime.now().astimezone(ZoneInfo('Europe/Lisbon'))
datetime.datetime(2024, 5, 26, 10, 50, 49, 474078, tzinfo=zoneinfo.ZoneInfo(key='Europe/Lisbon'))

Como caso especial tenemos la hora UTC, muy útil pues es la que nos devuelven, y aceptan, muchas librerías:

datetime.now(ZoneInfo('UTC'))
datetime.datetime(2024, 5, 26, 9, 50, 50, 453552, tzinfo=zoneinfo.ZoneInfo(key='UTC'))

Hora naive y no naive:

fecha = datetime(year=2024,month=5,day=1,hour=10,minute=10)

Esa hora no tiene asociao ningún timezone, y lo podemos confirmar llamando a la función tzinfo:

fecha.tzinfo

Sin embargo esta fecha sí está asociada, en particular a Lisboa:

fecha_lisboa = datetime(year=2024,month=5,day=1,hour=10,minute=10,tzinfo=ZoneInfo(key='Europe/Lisbon'))

en efecto:

fecha_lisboa.tzinfo
zoneinfo.ZoneInfo(key='Europe/Lisbon')

Y que impacto tiene esa diferencia?: por ejemplo, que no puedes restarlas. No puedes calcular la diferencia en tiempo entre una fecha naive y no naive

fecha-fecha_lisboa
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

Cell In[114], line 1
----> 1 fecha-fecha_lisboa


TypeError: can't subtract offset-naive and offset-aware datetimes

Sin embargo esto si funciona al estar comparando dos naives :

fecha_1 = datetime(year=2024,month=5,day=1,hour=10,minute=10,tzinfo= ZoneInfo('Europe/Lisbon'))
fecha_2 = datetime(year=2024,month=5,day=1,hour=11,minute=10,tzinfo= ZoneInfo('Europe/Madrid'))

qué resultado dará la resta anterior?

(fecha_1-fecha_2).seconds
0

efectivamente, la 11:10 hora local en Madrid corresponden con las 11:10 en Lisboa

Horas medidas en segundos

Este resultado nos da los segundos desde un epoch en particular. Y qué es eso de un epoch?..es una referencia, tal como se define en la documentacion oficial de la librería time : > The epoch is the point where the time starts, the return value of time.gmtime(0). It is January 1, 1970, 00:00:00 (UTC) on all platforms.

time.time()
1716717063.091218

y como conseguimos esa referencia?. La conseguimos con la ordent:

time.gmtime(0)
time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)

que podemos convertir a formato ´datetime`

datetime.fromtimestamp(time.mktime(time.gmtime(0)))
datetime.datetime(1970, 1, 1, 0, 0)

ese time.time() nos da un resultado en hora UTC. Para comprobarlo vamos a usar la función gmtime

time.gmtime(time.time())
time.struct_time(tm_year=2024, tm_mon=5, tm_mday=26, tm_hour=9, tm_min=51, tm_sec=5, tm_wday=6, tm_yday=147, tm_isdst=0)

y para conseguirla en hora actual:

time.localtime(time.time())
time.struct_time(tm_year=2024, tm_mon=5, tm_mday=26, tm_hour=11, tm_min=51, tm_sec=5, tm_wday=6, tm_yday=147, tm_isdst=1)

Y podemos conseguir esa hora en formato datetime tal como lo veíamos anteriormente

datetime.fromtimestamp(time.time()) #ojo...en local, aunque no naive
datetime.datetime(2024, 5, 26, 11, 51, 7, 303250)
datetime.fromtimestamp(time.time()).replace(tzinfo=ZoneInfo('Europe/Madrid'))
datetime.datetime(2024, 5, 26, 11, 51, 7, 536789, tzinfo=zoneinfo.ZoneInfo(key='Europe/Madrid'))

ojo, que replace tan solo cambia la timezone pero no recalcula la hora de acuerdo a ese cambio.

datetime.fromtimestamp(time.time()).replace(tzinfo=ZoneInfo('Europe/Madrid')).replace(tzinfo=ZoneInfo('Europe/Lisbon'))
datetime.datetime(2024, 5, 26, 11, 51, 7, 950463, tzinfo=zoneinfo.ZoneInfo(key='Europe/Lisbon'))

y para generar una hora en segundos desde una estructurada:

time.time()
1716717068.888389
time.gmtime(time.time())
time.struct_time(tm_year=2024, tm_mon=5, tm_mday=26, tm_hour=9, tm_min=51, tm_sec=9, tm_wday=6, tm_yday=147, tm_isdst=0)
calendar.timegm(time.gmtime(time.time()))
1716717069

que es dentro de una hora (los 3600 segundos sumados)

Y para pasar a un formato no naive desde segundos:

datetime.fromtimestamp(time.time()+3600,tz=ZoneInfo('Europe/Madrid'))
datetime.datetime(2024, 5, 26, 12, 51, 10, 228910, tzinfo=zoneinfo.ZoneInfo(key='Europe/Madrid'))
datetime.fromtimestamp(time.time(),tz=ZoneInfo('Europe/Lisbon'))
datetime.datetime(2024, 5, 26, 10, 51, 10, 435502, tzinfo=zoneinfo.ZoneInfo(key='Europe/Lisbon'))

Así como resumen, y replicando el cuadro de la documentación de la librería:

  • Cambio de segundos desde epoch a struc_time en UTC : gmtime()

  • Cambio de segundos desde epoch a struct_time en LocatTime : localtime()

  • Cambio de struct_time en UTC a segundos : calendar.timegm()

  • Cambio de struct_time local time a segundos: mktime()

    y añado dos más:

  • Cambo de datetime a time_struct : datetime.timetuple()

  • Cambio de time_struct a datetime : datetime.fromtimestamp(mktime(time_struc))


Deja un comentario

Este sitio utiliza Akismet para reducir el spam. Conoce cómo se procesan los datos de tus comentarios.