Création d'une DateTime dans un fuseau horaire spécifique en c#

j'essaie de créer un test unitaire pour tester le cas où le fuseau horaire change sur une machine parce qu'il a été mal réglé puis corrigé.

dans le test, je dois être capable de créer des objets DateTime dans un fuseau horaire local pour m'assurer que les personnes qui exécutent le test peuvent le faire avec succès, indépendamment de l'endroit où ils se trouvent.

D'après ce que je vois à partir du constructeur DateTime, je peux définir le fuseau horaire soit fuseau horaire le fuseau horaire UTC ou non spécifié.

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

121
demandé sur Liam 2008-10-29 14:48:05

6 réponses

Jon's answer parle de TimeZone , mais je suggérerais d'utiliser TimeZoneInfo à la place.

personnellement, j'aime garder les choses en TUC lorsque c'est possible, donc 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 pouvez changer les noms" TimeZone "en" TimeZoneInfo " pour rendre les choses plus claires - je préfère les noms plus brefs moi-même.

170
répondu Jon Skeet 2017-05-23 12:34:36

la structure DateTimeOffset a été créée précisément pour ce type d'utilisation.

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

voici un exemple de création D'un objet DateTimeOffset avec un fuseau horaire spécifique:

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

41
répondu Clever Human 2009-08-15 02:32:07

les autres réponses ici sont utiles, mais elles ne couvrent pas la façon d'accéder à Pacific spécifiquement - ici vous allez:

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

assez curieusement, bien que" Heure normale du Pacifique "signifie normalement quelque chose de différent de" heure quotidienne du Pacifique", dans ce cas, il se réfère à L'heure du Pacifique en général. En fait, si vous utilisez FindSystemTimeZoneById pour la récupérer, l'une des propriétés est un bool vous informant que le fuseau horaire est actuellement en heure d'été ou pas.

vous pouvez voir des exemples plus généralisés de cela dans une bibliothèque que j'ai fini par jeter ensemble pour traiter les DateTimes dont j'ai besoin dans différents fuseaux horaires basés sur l'endroit où l'utilisateur demande, etc:

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

cela ne fonctionnera pas en dehors de Windows (par exemple Mono sur Linux) puisque la liste des heures provient du registre de Windows: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\

En dessous de cela, vous trouverez les clés (icônes de dossiers dans L'Éditeur du registre); les noms de ces clés sont ce que vous passez à FindSystemTimeZoneById . Sur Linux, vous devez utiliser un ensemble séparé de définitions de fuseaux horaires standard Linux, que je n'ai pas suffisamment exploré.

29
répondu Chris Moschini 2013-05-13 21:23:36

j'ai changé Jon Skeet réponse un peu pour le web avec l'extension de la méthode. Il fonctionne également sur l'Azur comme un charme.

public static class DateTimeWithZone
{

private static readonly TimeZoneInfo timeZone;

static DateTimeWithZone()
{
//I added web.config <add key="CurrentTimeZoneId" value="Central Europe Standard Time" />
//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);   
}
}
6
répondu Jernej Novak 2017-05-23 12:26:10

, Vous devez créer un objet personnalisé. Votre objet personnalisé contiendra deux valeurs:

Je ne sais pas s'il existe déjà un type de données fourni par CLR qui possède ce type, mais au moins la composante de fuseau horaire est déjà disponible.

2
répondu Jon Limjap 2008-10-29 11:51:21

j'aime la réponse de Jon Skeet, mais je voudrais ajouter une chose. Je ne suis pas sûr que 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 locale.

je suis en train de lire des valeurs à partir d'une base de données, et je sais Dans quel fuseau horaire se trouve cette base de données. Donc dans le ctor, je passe dans le fuseau horaire de la base de données. Mais alors je voudrais la valeur dans l'heure locale. Le LocalTime de Jon ne renvoie pas l'original date convertie en une date locale de fuseau horaire. Il renvoie la date convertie dans le fuseau horaire original (ce que vous avez passé dans le ctor).

je pense que ces noms de propriétés clarifient...

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);
}
2
répondu Gabe Halsmer 2013-12-10 20:13:18