2008-12-06 9 views
20

Quelques problèmes avec les fuseaux horaires en PHP sont restés dans ma tête pendant un moment maintenant, et je me demandais s'il y avait de meilleures façons de les gérer que ce que je suis en train de faire.Traiter les fuseaux horaires en PHP

Toutes les questions tournent base de données autour reformatage dates stockées:

Lorsque vous traitez avec un site qui doit prendre en charge plusieurs fuseaux horaires (pour les utilisateurs), pour normaliser la offest de fuseau horaire de horodatages stockées je stocker toujours avec le serveur fuseau horaire en utilisant l'attribut CURRENT_TIMESTAMP ou la fonction NOW().

De cette façon, je n'ai pas à considérer quel fuseau horaire a été défini pour PHP lorsque l'horodatage a été entré (puisque les fonctions d'heure PHP sont sensibles au fuseau horaire). Pour chaque utilisateur, selon sa préférence, je mets le fuseau horaire quelque part dans mon fichier d'amorçage en utilisant:

date_default_timezone_set($timezone); 

Quand je suis à la recherche pour formater les dates avec le php fonction date(), une certaine forme de conversion doit avoir lieu depuis MySQL stocke actuellement l'horodatage au format Y-m-d H:i:s. Sans tenir compte de fuseau horaire, vous pouvez simplement lancer:

$date = date($format,strtotime($dbTimestamp)); 

Le problème est que date() et strtotime() sont les deux fuseaux horaires fonctions au courant, ce qui signifie que si le fuseau horaire PHP est défini différemment du fuseau horaire du serveur, le décalage horaire appliquera deux fois (au lieu d'une fois comme nous le voudrions). Pour traiter ceci, je récupère habituellement les horodatages MySQL en utilisant la fonction UNIX_TIMESTAMP() qui n'est pas consciente du fuseau horaire, ce qui me permet d'appliquer date() directement dessus - appliquant ainsi le décalage de fuseau horaire seulement une fois.

Je ne pas vraiment comme ça « hack » que je ne peux plus récupérer ces colonnes comme je le ferais normalement ou utiliser * pour récupérer toutes les colonnes (parfois, il simplifie les requêtes beaucoup). En outre, il n'est parfois pas possible d'utiliser UNIX_TIMESTAMP() (en particulier lorsque vous utilisez des paquets open-source sans beaucoup d'abstraction pour la composition des requêtes). Un autre problème est lors du stockage de l'horodatage, lorsque l'utilisation de CURRENT_TIMESTAMP ou NOW() n'est pas une option - stocker un horodatage généré par PHP le stockera avec le décalage de fuseau horaire que je voudrais éviter. Je manque probablement quelque chose de vraiment basique ici, mais jusqu'à présent, je n'ai pas été capable de trouver une solution générique pour gérer ces problèmes, donc je suis obligé de les traiter au cas par cas. Vos pensées sont les bienvenues

+1

Pour quiconque trouve cette question et veut lire sur le sujet: http://stackoverflow.com/questions/2532729/daylight-saving-time-and-timezone-best-practices – Industrial

Répondre

1

Vous pourriez essayer de forcer MySQL à utiliser UTC partout en utilisant SET time_zone.

Malheureusement je n'ai pas de réponse pour le truc strtotime/UNIX_TIMESTAMP, en fait j'ai le même problème avec Postgres.

+0

Peut-être que nous devrions faire appel à la SQL comité des normes à appliquer en utilisant un horodatage numérique? ;) –

+0

Non, je suis sûr que les colonnes datetime sont là pour une bonne raison. Je ne l'ai pas encore compris ... – flussence

11

Il y a quelques mois, nous avons passé un peu de temps à réfléchir à ce sujet. La technique avec laquelle nous nous sommes retrouvés est assez simple:

  1. Mémorisez les dates en GMT/UTC (par exemple 0 décalage horaire).
  2. Appliquez le décalage de fuseau horaire actuel de l'utilisateur après la récupération de la base de données (par exemple, avant de le montrer à l'utilisateur ou quand vous le souhaitez).

Nous utilisons le format d'horodatage Unix. Mais cela n'a pas d'importance.

+1

En fait, je préfère le stocker dans le fuseau horaire du serveur et laisser PHP timezone prendre en charge les fonctions de calcul de décalage. Mon problème est que l'horodatage n'est pas sauvegardé sous forme numérique que PHP veut pour la fonction date() –

+0

Nous utilisons aussi la même solution après quelques recherches. Voudrait ici des alternatives que les gens ont utilisées. – Sean

6

Depuis PHP 5.2 vous pouvez utiliser DateTime qui rend le travail avec timezones facile:

$datetime = new DateTime($dbTimestamp, $timezone); 
echo $datetime->format('Y-m-d H:i:s'); 
$datetime->setTimezone(new DateTimeZone('Pacific/Nauru')); 
echo $datetime->format('Y-m-d H:i:s'); 
0

Je n'ai pas trouvé une solution élégante je en ligne ainsi créé un script Timezone HTML select generator et voici le output directement. C'est quelque chose comme ceci:

<select name="timezone" id="timezone"> 
    <optgroup label="UTC -11:00"> 
     <option value="Pacific/Midway">UTC -11:00 Midway</option> 
     <option value="Pacific/Niue">UTC -11:00 Niue</option> 
     <option value="Pacific/Pago_Pago">UTC -11:00 Pago_Pago</option> 
    </optgroup> 
    <optgroup label="UTC -10:00"> 
     <option value="America/Adak">UTC -10:00 Adak</option> 
     <option value="Pacific/Honolulu">UTC -10:00 Honolulu</option> 
     <option value="Pacific/Johnston">UTC -10:00 Johnston</option> 
     <option value="Pacific/Rarotonga">UTC -10:00 Rarotonga</option> 
     <option value="Pacific/Tahiti">UTC -10:00 Tahiti</option> 
    </optgroup> 
    . . . . . . . . . . . . . . 
    <optgroup label="UTC +13:00"> 
     <option value="Pacific/Apia">UTC +13:00 Apia</option> 
     <option value="Pacific/Enderbury">UTC +13:00 Enderbury</option> 
     <option value="Pacific/Fakaofo">UTC +13:00 Fakaofo</option> 
     <option value="Pacific/Tongatapu">UTC +13:00 Tongatapu</option> 
    </optgroup> 
    <optgroup label="UTC +14:00"> 
     <option value="Pacific/Kiritimati">UTC +14:00 Kiritimati</option> 
    </optgroup> 
</select> 

Enjoy!

Questions connexes