create - timedelta python example
Obtener el nombre de Olson TZ para la zona horaria local? (11)
¿Cómo obtengo el nombre de la zona horaria de Olson (como Australia/Sydney
) correspondiente al valor dado por la llamada de localtime
de C?
Este es el valor anulado a través de TZ
, mediante la vinculación simbólica /etc/localtime
, o la configuración de una variable TIMEZONE
en los archivos de configuración del sistema relacionados con la hora.
Aquí hay otra posibilidad, usando PyICU en PyICU lugar; que está funcionando para mis propósitos:
>>> from PyICU import ICUtzinfo
>>> from datetime import datetime
>>> datetime(2012, 1, 1, 12, 30, 18).replace(tzinfo=ICUtzinfo.getDefault()).isoformat()
''2012-01-01T12:30:18-05:00''
>>> datetime(2012, 6, 1, 12, 30, 18).replace(tzinfo=ICUtzinfo.getDefault()).isoformat()
''2012-06-01T12:30:18-04:00''
Aquí se están interpretando los tiempos de datos niave (como serían devueltos por una consulta de base de datos) en la zona horaria local.
Cambié el script de tcurvelo para encontrar la forma correcta de zona horaria (Continente /..../ Ciudad), en la mayoría de los casos, pero devolverlos todos si falla
#!/usr/bin/env python
from hashlib import sha224
import os
from os import listdir
from os.path import join, isfile, isdir
infoDir = ''/usr/share/zoneinfo/''
def get_current_olsonname():
result = []
tzfile_digest = sha224(open(''/etc/localtime'').read()).hexdigest()
test_match = lambda filepath: sha224(open(filepath).read()).hexdigest() == tzfile_digest
def walk_over(dirpath):
for root, dirs, filenames in os.walk(dirpath):
for fname in filenames:
fpath = join(root, fname)
if test_match(fpath):
result.append(tuple(root.split(''/'')[4:]+[fname]))
for dname in listdir(infoDir):
if dname in (''posix'', ''right'', ''SystemV'', ''Etc''):
continue
dpath = join(infoDir, dname)
if not isdir(dpath):
continue
walk_over(dpath)
if not result:
walk_over(join(infoDir))
return result
if __name__ == ''__main__'':
print get_current_olsonname()
Creo que lo mejor es ir a través de todas las zonas horarias de pytz y verificar cuál coincide con la zona horaria local, cada objeto de zona horaria pytz contiene información sobre utcoffset y tzname como CDT, EST. La misma información sobre la hora local se puede obtener de time.timezone/altzone
y time.tzname
, y creo que es suficiente para hacer coincidir correctamente la zona horaria local en la base de datos pytz, por ejemplo
import time
import pytz
import datetime
local_names = []
if time.daylight:
local_offset = time.altzone
localtz = time.tzname[1]
else:
local_offset = time.timezone
localtz = time.tzname[0]
local_offset = datetime.timedelta(seconds=-local_offset)
for name in pytz.all_timezones:
timezone = pytz.timezone(name)
if not hasattr(timezone, ''_tzinfos''):
continue#skip, if some timezone doesn''t have info
# go thru tzinfo and see if short name like EDT and offset matches
for (utcoffset, daylight, tzname), _ in timezone._tzinfos.iteritems():
if utcoffset == local_offset and tzname == localtz:
local_names.append(name)
print local_names
salida:
[''America / Atikokan'', ''America / Bahia_Banderas'', ''America / Bahia_Banderas'', ''America / Belize'', ''America / Cambridge_Bay'', ''America / Cancun'', ''America / Chicago'', ''America / Chihuahua'', '' America / Coral_Harbour '','' America / Costa_Rica '','' America / El_Salvador '','' America / Fort_Wayne '','' America / Guatemala '','' America / Indiana / Indianapolis '','' America / Indiana / Knox '','' America / Indiana / Marengo '','' America / Indiana / Marengo '','' America / Indiana / Petersburg '','' America / Indiana / Tell_City '','' America / Indiana / Vevay '','' America / Indiana / Vincennes '','' America / Indiana / Winamac '' , ''America / Indianapolis'', ''America / Iqaluit'', ''America / Kentucky / Louisville'', ''America / Kentucky / Louisville'', ''America / Kentucky / Monticello'', ''America / Knox_IN'', ''America / Louisville'', '' America / Louisville '','' America / Managua '','' America / Matamoros '','' America / Menominee '','' America / Merida '','' America / Mexico_City '','' America / Monterrey '','' America / North_Dakota / Beulah '','' America / North_Dakota / Center '','' America / North_Dakota / New_Salem '','' America / Ojinaga '','' America / Pangnirtung '','' Am erica / Rainy_River '','' America / Rankin_Inlet '','' America / Resolute '','' America / Resolute '','' America / Tegucigalpa '','' America / Winnipeg '','' CST6CDT '','' Canada / Central '','' Mexico / General '' , ''US / Central'', ''US / East-Indiana'', ''US / Indiana-Starke'']
En producción, puede crear dicho mapeo de antemano y guardarlo en lugar de iterarlo siempre.
Prueba de script después de cambiar la zona horaria:
$ exportación TZ = ''Australia / Sydney''
$ python get_tz_names.py
[''Antarctica / Macquarie'', ''Australia / ACT'', ''Australia / Brisbane'', ''Australia / Canberra'', ''Australia / Currie'', ''Australia / Hobart'', ''Australia / Lindeman'', ''Australia / Melbourne'', '' Australia / NSW '','' Australia / Queensland '','' Australia / Sydney '','' Australia / Tasmania '','' Australia / Victoria '']
El módulo tzlocal para Python está dirigido exactamente a este problema. Produce resultados consistentes tanto en Linux como en Windows, convirtiendo correctamente las identificaciones de zona horaria de Windows a Olson usando las asignaciones de CLDR.
Esto es una especie de trampa, lo sé, ¿pero obtener de ''/etc/localtime''
no funciona para usted? Como siguiendo
>>> import os
>>> ''/''.join(os.readlink(''/etc/localtime'').split(''/'')[-2:])
''Australia/Sydney''
Espero eso ayude.
Edición : Me gustó la idea de @ AH, en caso de que ''/etc/localtime''
no sea un enlace simbólico. Traduciendo eso a Python:
#!/usr/bin/env python
from hashlib import sha224
import os
def get_current_olsonname():
tzfile = open(''/etc/localtime'')
tzfile_digest = sha224(tzfile.read()).hexdigest()
tzfile.close()
for root, dirs, filenames in os.walk("/usr/share/zoneinfo/"):
for filename in filenames:
fullname = os.path.join(root, filename)
f = open(fullname)
digest = sha224(f.read()).hexdigest()
if digest == tzfile_digest:
return ''/''.join((fullname.split(''/''))[-2:])
f.close()
return None
if __name__ == ''__main__'':
print get_current_olsonname()
Esto le dará el nombre de la zona horaria, de acuerdo con lo que está en la variable TZ, o el archivo de hora local si no está configurado:
#! /usr/bin/env python
import time
time.tzset
print time.tzname
Prefiero seguir un poco mejor que hurgando en los valores de _xxx
import time, pytz, os
cur_name=time.tzname
cur_TZ=os.environ.get("TZ")
def is_current(name):
os.environ["TZ"]=name
time.tzset()
return time.tzname==cur_name
print "Possible choices:", filter(is_current, pytz.all_timezones)
# optional tz restore
if cur_TZ is None: del os.environ["TZ"]
else: os.environ["TZ"]=cur_TZ
time.tzset()
Si la evaluación de /etc/localtime
está bien para usted, el siguiente truco podría funcionar, después de traducirlo a Python:
> md5sum /etc/localtime
abcdefabcdefabcdefabcdefabcdefab /etc/localtime
> find /usr/share/zoneinfo -type f |xargs md5sum | grep abcdefabcdefabcdefabcdefabcdefab
abcdefabcdefabcdefabcdefabcdefab /usr/share/zoneinfo/Europe/London
abcdefabcdefabcdefabcdefabcdefab /usr/share/zoneinfo/posix/Europe/London
...
Los duplicados podrían filtrarse usando solo los nombres de región oficiales "Europa", "América" ... Si todavía hay duplicados, puede tomar el nombre más corto :-)
Un problema es que hay varios "nombres bonitos", como "Australia / Sydney", que apuntan a la misma zona horaria (por ejemplo, CST).
Por lo tanto, deberá obtener todos los nombres posibles para la zona horaria local y luego seleccionar el nombre que desee.
Por ejemplo: para Australia, hay 5 zonas horarias, pero muchos más identificadores de zona horaria:
"Australia/Lord_Howe", "Australia/Hobart", "Australia/Currie",
"Australia/Melbourne", "Australia/Sydney", "Australia/Broken_Hill",
"Australia/Brisbane", "Australia/Lindeman", "Australia/Adelaide",
"Australia/Darwin", "Australia/Perth", "Australia/Eucla"
debe comprobar si hay una biblioteca que contenga TZinfo , para manejar la API de zona horaria.
Por ejemplo: para Python, verifique la biblioteca pytz
:
y
http://pypi.python.org/pypi/pytz/
En Python puedes hacer:
from pytz import timezone
import pytz
In [56]: pytz.country_timezones(''AU'')
Out[56]:
[u''Australia/Lord_Howe'',
u''Australia/Hobart'',
u''Australia/Currie'',
u''Australia/Melbourne'',
u''Australia/Sydney'',
u''Australia/Broken_Hill'',
u''Australia/Brisbane'',
u''Australia/Lindeman'',
u''Australia/Adelaide'',
u''Australia/Darwin'',
u''Australia/Perth'',
u''Australia/Eucla'']
pero la API para Python parece ser bastante limitada, por ejemplo, no parece tener una llamada como todos los nombres de zona de all_linked_zone_names
de Ruby, que pueden encontrar todos los nombres de sinónimos para una zona horaria determinada.
import pytz
import time
#import locale
import urllib2
yourOlsonTZ = None
#yourCountryCode = locale.getdefaultlocale()[0].split(''_'')[1]
yourCountryCode = urllib2.urlopen(''http://api.hostip.info/country.php'').read()
for olsonTZ in [pytz.timezone(olsonTZ) for olsonTZ in pytz.all_timezones]:
if (olsonTZ._tzname in time.tzname) and (str(olsonTZ) in pytz.country_timezones[yourCountryCode]):
yourOlsonTZ = olsonTZ
break
print yourOlsonTZ
Este código tomará la mejor decisión de adivinar en su Zona horaria de Olson tanto en su Nombre de zona horaria (según el módulo de time
de Python) como en su Código de país (según el módulo de del proyecto hostip.info , que hace referencia a su dirección IP). y te geolocaliza en consecuencia). locale
Por ejemplo, simplemente hacer coincidir los Nombres de la zona del tiempo podría resultar en America/Moncton
, America/Montreal
o America/New_York
para EST (GMT-5). Si su país es los EE. UU., Sin embargo, limitará la respuesta a America/New_York
.
Sin embargo, si su país es Canadá, el guión simplemente tomará como valor predeterminado el resultado canadiense más alto ( America/Moncton
). Si hay una manera de refinar esto aún más, no dude en dejar sugerencias en los comentarios.
Este proyecto de JavaScript intenta resolver el mismo problema en el lado del cliente del navegador. Funciona jugando "veinte preguntas" con la configuración regional, solicitando el desplazamiento UTC de ciertos tiempos pasados (para probar los límites del horario de verano, etc.) y usar esos resultados para deducir cuál debe ser la zona horaria local. Lamentablemente, no conozco ningún paquete Python equivalente, por lo que si alguien quisiera usar esta solución, tendría que ser portado a Python.
Si bien esta fórmula requerirá la actualización cada vez (en el peor de los casos) la base de datos TZ se actualizará, una combinación de este algoritmo y la solución propuesta por Anurag Uniyal (manteniendo solo las posibilidades devueltas por ambos métodos) me parece la forma más segura de calcular la eficacia. zona horaria local. Siempre que haya alguna diferencia entre el desplazamiento UTC de al menos una hora local en cualquiera de las dos zonas horarias, este sistema puede elegir correctamente entre ellas.