J'écrivais un petit outil pour recevoir des informations, y compris l'heure d'une API externe et notifier Slack, mais je ne pouvais pas convertir le fuseau horaire de manière cohérente et stable, ce qui signifiait. Notez ce que vous avez appris au cours de l'enquête et les solutions possibles.
--Utilisez pytz.timezone.localize (datetime)
lorsque vous utilisez pytz pour la conversion du fuseau horaire.
--Il semble préférable de ne pas utiliser le datetime.replace
fourni avec datetime
--Il existe deux types de datetime: Timezeon aware / Offest native
--Si datetime est généré en Python sans en être conscient, le décalage natif est généré.
Dans mon cas, il y avait plusieurs types de pierres d'achoppement.
Enfin, je vais vous montrer ce que j'ai recherché à ce sujet et quel type de code j'ai écrit pour les surmonter.
Timezeon aware / Offest native
Il existe les deux types de date / heure ci-dessus.
La prise en charge du fuseau horaire est une date / heure avec un fuseau horaire explicitement spécifié, et Offset native est une heure sans fuseau horaire spécifié. Les deux ne peuvent être comparés.
Il faut les distinguer.
import os
from datetime import datetime
import pytz
# Offest native
d1 = datetime.utcnow()
print(d1)
>>> 2020-04-19 10:07:47.885883
# Timezone aware
d2 = pytz.utc.localize(d1)
print(d2)
>>> 2020-04-19 10:07:47.885883+00:00
#Les deux ne peuvent pas être comparés
d1 < d2
# >>> TypeError: can't compare offset-naive and offset-aware datetimes
Le fuseau horaire semble être déterminé par l'emplacement et ** l'heure **. Il semble y avoir un cas où la définition du décalage horaire est modifiée en raison de circonstances historiques, et notre Japon correspond également à cet exemple.
Il semble que le décalage horaire soit différent entre Tokyo jusqu'en 1888 et après cela, et avant 1888, il semble être ** + 09: 19 ** de UTC. Ainsi, pytz est strictement considéré, et il semble que cela soit pris en compte dans certaines méthodes du système de conversion de fuseau horaire (datetime.replace etc.).
import pytz
#Ici AFFICHER_TIMEZONE='Asia/Tokyo'Supposer
DISPLAY_TIMEZONE = os.environ.get('DISPLAY_TIMEZONE')
tz = pytz.timezone(DISPLAY_TIMEZONE)
tz
>>> <DstTzInfo 'Asia/Tokyo' LMT+9:19:00 STD>
C'est 19 minutes de repos. Cependant, cela semble être correct en raison d'une conformité appropriée.
Si votre programme traite de ** Offset native **, vous pouvez utiliser timezone.localize ()
fourni par l'objet timezone de pytz. Il sera converti correctement à +09: 00.
** Tant que vous utilisez la méthode localize
de pytz, la conversion du fuseau horaire se produira à +09: 00 comme vous le souhaitez, vous n'avez donc pas à vous soucier de cet écart. ** **
tz.localize(d1)
>>> datetime.datetime(2020, 4, 19, 10, 20, 3, 201190, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>)
localize ()
de pytz n'accepte pas les fuseaux horaires compatibles avec le fuseau horaire. Ce point mérite attention.
# localize offset ative
tz.localize(d1)
>>> datetime.datetime(2020, 4, 19, 10, 7, 47, 885883, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>)
# localize timezone aware (error)
tz.localize(d2)
# >>> ValueError: Not naive datetime (tzinfo is already set)
Par conséquent, quand il s'agit de ** l'heure consciente du fuseau horaire, localize
ne peut pas être utilisé tel quel, et il est nécessaire de le convertir en décalage natif une fois. ** Cela se produit souvent lorsque l'heure renvoyée, comme l'utilisation d'un wrapper pour une API externe, prend en compte le fuseau horaire.
Le contenu écrit ici mentionne les spécifications de pytz ont changé | Qiita @ higitune, vous devriez donc y jeter un coup d'œil. .. Ce sera très utile, y compris la section des commentaires.
Lors de l'utilisation d'un package développé par quelqu'un d'autre que vous-même, il appartient à l'implémenteur de savoir si l'heure renvoyée par le module de package est compatible avec le fuseau horaire ou offset native. Afin de les combiner et de mettre en œuvre vos propres exigences de développement, vous devrez gérer un mélange de ces derniers.
Par conséquent, il est préférable de le déposer une fois sur l'horodatage (bien qu'il soit sur Theory Street). Le code ci-dessous vous permet de convertir JST à la fois en fonction du décalage natif / du fuseau horaire. (Il n'est pas confirmé si des résultats similaires peuvent être obtenus dans d'autres pays)
import pytz
from datetime import datetime
DISPLAY_TIMEZONE = 'Asia/Tokyo'
tz = pytz.timezone(DISPLAY_TIMEZONE)
def localized_datetime(date: datetime):
return datetime.fromtimestamp(date.timestamp(), tz=tz)
if __name__ == '__main__':
# d1: native datetime
d1 = datetime.now()
print(f"d1: {d1}")
# d2: utc localize
d2 = tz.localize(d1)
print(f"d2: {d2}")
print(localized_datetime(d1))
print(localized_datetime(d2))
>>> d1: 2020-04-19 20:15:30.974272
>>> d2: 2020-04-19 20:15:30.974272+09:00
>>> 2020-04-19 20:15:30.974272+09:00
>>> 2020-04-19 20:15:30.974272+09:00
Le fuseau horaire est déroutant ...
Le code ci-dessus est publié comme une implémentation de référence, mais il semble que l'heure localisée réelle soit principalement requise pour la couche de présentation (c'est-à-dire l'apparence), donc dans la couche logique et la couche de persistance autant que possible avec datetime Je pense qu'il serait préférable d'utiliser plutôt l'horodatage.
Cependant, datetime est extrêmement pratique lors de l'écriture de code, et je pense qu'il existe de nombreux cas où les opérations de date doivent être effectuées fréquemment dans la couche logique.
Dans un tel cas, je pense qu'il vaut mieux unifier lequel des fuseaux horaires awre / offset natif est utilisé, au moins dans le code plus proche de la couche logique écrite par moi-même. Si les heures gérées par les packages externes ne sont pas cohérentes, vous pouvez créer votre propre calque qui enveloppe finement l'interface que vous souhaitez utiliser et absorbe l'incohérence dans le type de date / heure et le fuseau horaire. , Je pense que la logique principale sera plus propre.
Je ne peux pas décider lequel envoyer en fonction de mes connaissances actuelles, alors je vous serais reconnaissant si vous pouviez nous donner votre avis dans la section commentaires.
Il existe également des pièges subtils dans le code ci-dessus. Par exemple
"Le type datetime renvoyé par la fonction / méthode est un offset natif, mais l'heure est basée sur UTC."
Dans ce cas. Si l'API du service externe est conçue pour renvoyer de manière cohérente UTC et que l'implémentation du package externe qui l'encapsule n'est pas cool et ne génère pas de datetime compte tenu du fuseau horaire ... Je pense que ce sera. .. .. Dans ce cas, traitons-le individuellement.
Recommended Posts