Créer un DateTime dans un fuseau horaire spécifique dans c #

J’essaie de créer un test unitaire pour tester le cas lorsque le fuseau horaire change sur une machine car il a été mal défini et ensuite corrigé.

Dans le test, je dois pouvoir créer des objects DateTime dans un fuseau horaire local pour garantir que les personnes exécutant le test puissent le faire avec succès, quel que soit leur emplacement.

D’après ce que je peux voir du constructeur DateTime, je peux définir TimeZone comme étant le fuseau horaire local, le fuseau horaire UTC ou non spécifié.

Comment créer un DateTime avec un fuseau horaire spécifique comme PST?

La réponse de Jon parle de TimeZone , mais je suggère d’utiliser plutôt TimeZoneInfo .

Personnellement, j’aime garder les choses en UTC dans la mesure du possible, alors je suggère une structure comme celle-ci:

public struct DateTimeWithZone { private readonly DateTime utcDateTime; private readonly TimeZoneInfo timeZone; public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone) { var dateTimeUnspec = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified); utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTimeUnspec, timeZone); this.timeZone = timeZone; } public DateTime UniversalTime { get { return utcDateTime; } } public TimeZoneInfo TimeZone { get { return timeZone; } } public DateTime LocalTime { get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); } } } 

Vous voudrez peut-être changer les noms “TimeZone” en “TimeZoneInfo” pour rendre les choses plus claires – je préfère les noms plus brefs moi-même.

La structure DateTimeOffset a été créée pour exactement ce type d’utilisation.

Voir: http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx

Voici un exemple de création d’un object DateTimeOffset avec un fuseau horaire spécifique:

DateTimeOffset do1 = new DateTimeOffset(2008, 8, 22, 1, 0, 0, new TimeSpan(-5, 0, 0));

Les autres réponses ici sont utiles, mais elles ne couvrent pas la manière d’accéder spécifiquement à Pacific – voilà:

 public static DateTime GmtToPacific(DateTime dateTime) { return TimeZoneInfo.ConvertTimeFromUtc(dateTime, TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time")); } 

Assez curieusement, bien que «l’heure normale du Pacifique» signifie normalement quelque chose de différent de «l’heure quotidienne du Pacifique», dans ce cas, il fait référence à l’heure du Pacifique en général. En fait, si vous utilisez FindSystemTimeZoneById pour le récupérer, l’une des propriétés disponibles est une valeur booléenne indiquant si ce fuseau horaire est actuellement en heure avancée ou non.

Vous pouvez voir des exemples plus généralisés de ceci dans une bibliothèque que j’ai fini par assembler pour traiter les DateTimes dont j’ai besoin dans différentes TimeZones en fonction de l’endroit où l’utilisateur demande, etc.:

https://github.com/b9chris/TimeZoneInfoLib.Net

Cela ne fonctionnera pas en dehors de Windows (par exemple Mono sous Linux) car la liste des temps provient du registre Windows: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\

En dessous, vous trouverez des clés (icons de dossiers dans l’Éditeur du Registre); les noms de ces clés sont ceux que vous transmettez à FindSystemTimeZoneById . Sous Linux, vous devez utiliser un ensemble distinct de définitions de fuseaux horaires conformes à la norme Linux, que je n’ai pas exploré correctement.

J’ai modifié la réponse de Jon Skeet pour le web avec la méthode d’extension. Il fonctionne également sur l’azure comme un charme.

 public static class DateTimeWithZone { private static readonly TimeZoneInfo timeZone; static DateTimeWithZone() { //I added web.config  //You can add value directly into function. timeZone = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["CurrentTimeZoneId"]); } public static DateTime LocalTime(this DateTime t) { return TimeZoneInfo.ConvertTime(t, timeZone); } } 

Vous devrez créer un object personnalisé pour cela. Votre object personnalisé contiendra deux valeurs:

  • une valeur DateTime
  • un object TimeZone

Vous ne savez pas s’il existe déjà un type de données fourni par le CLR, mais au moins le composant TimeZone est déjà disponible.

J’aime la réponse de Jon Skeet, mais j’aimerais append une chose. Je ne suis pas sûr si Jon s’attendait à ce que le ctor soit toujours passé dans le fuseau horaire Local. Mais je veux l’utiliser pour les cas où c’est autre chose que local.

Je lis les valeurs d’une firebase database et je connais le fuseau horaire dans lequel se trouve la firebase database. Donc, dans le ctor, je passerai le fuseau horaire de la firebase database. Mais alors je voudrais la valeur en heure locale. Le LocalTime de Jon ne renvoie pas la date d’origine convertie en date de fuseau horaire local. Il renvoie la date convertie dans le fuseau horaire d’origine (peu importe ce que vous avez passé dans le ctor).

Je pense que ces noms de propriété clarifient les choses …

 public DateTime TimeInOriginalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); } } public DateTime TimeInLocalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, TimeZoneInfo.Local); } } public DateTime TimeInSpecificZone(TimeZoneInfo tz) { return TimeZoneInfo.ConvertTime(utcDateTime, tz); }