PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Obtenir l'heure avec le fuseau horaire à partir de l'heure sans fuseau horaire et le nom du fuseau horaire

ATTENTION :Débutant de PostgreSQL (voir les commentaires sur la question !). Je connais un peu les fuseaux horaires, donc je sais ce qui a du sens demander.

Il me semble que c'est fondamentalement une situation non prise en charge (malheureusement) en ce qui concerne AT TIME ZONE . En regardant le AT TIME ZONE documentation, il donne un tableau où les types de valeur "d'entrée" sont uniquement :

  • horodatage sans fuseau horaire
  • horodatage avec fuseau horaire
  • heure avec fuseau horaire

Il nous manque celui que vous vouliez :le temps sans fuseau horaire. Ce que vous demandez est un peu logique, même si cela dépend de la date... car différents fuseaux horaires peuvent avoir des décalages différents en fonction de la date. Par exemple, 12:00:00 Europe/Londres peut signifie 12:00:00 UTC, ou cela peut signifier 11:00:00 UTC, selon que c'est l'hiver ou l'été.

Sur mon système, après avoir défini le fuseau horaire du système sur America/Regina, la requête

SELECT ('2011-11-22T12:00:00'::TIMESTAMP WITHOUT TIME ZONE) 
                               AT TIME ZONE 'America/Vancouver'

me donne 2011-11-22 14:00:00-06 par conséquent. Ce n'est pas idéal , mais cela donne au moins le point instantané dans le temps (je pense). Je crois que si vous l'avez récupéré avec une bibliothèque cliente - ou si vous l'avez comparé avec un autre TIMESTAMP WITH TIME ZONE - vous obtiendrez le bon résultat. C'est juste la conversion de texte qui utilise ensuite le système fuseau horaire pour la sortie.

Cela vous suffirait-il ? Pouvez-vous soit modifier votre SCHEDULES.time le champ doit être un TIMESTAMP WITHOUT TIME ZONE ou (au moment de la requête) combiner l'heure du champ avec une date pour créer un horodatage sans fuseau horaire ?

EDIT :Si vous êtes satisfait de la "date actuelle", elle semble par exemple, vous pouvez simplement modifier votre requête en :

SELECT (current_date + SCHEDULES.time) AT TIME ZONE USERS.tz
from SCHEDULES JOIN USERS on USERS.ID=SCHEDULES.USERID

Bien sûr, le système actuel la date peut ne pas être la même que la date actuelle dans le fuseau horaire local . Je pense cela résoudra cette partie...

SELECT ((current_timestamp AT TIME ZONE USERS.tz)::DATE + schedules.time)
       AT TIME ZONE USERS.tz
from SCHEDULES JOIN USERS on USERS.ID=SCHEDULES.USERID

En d'autres termes :

  • Prenez l'instant courant
  • Trouvez la date/heure locale dans le fuseau horaire de l'utilisateur
  • Prenez la date de cela
  • Ajoutez l'heure du programme à cette date pour obtenir un TIMESTAMP WITHOUT TIME ZONE
  • Utilisez AT TIME ZONE pour appliquer le fuseau horaire à cette date/heure locale

Je suis sûr qu'il y a un meilleur moyen, mais je pense c'est logique.

Vous devez savoir que dans certains cas, cela peut échouer :

  • Que voulez-vous que le résultat soit pour une heure de 01h30 un jour où l'horloge saute de 01h00 à 02h00, donc 01h30 ne se produit pas du tout ?
  • Que voulez-vous que le résultat soit pour une heure de 01h30 un jour où l'horloge remonte de 02h00 à 01h00, donc 01h30 se produit deux fois ?