DateTime.Maintenant et culture / fuseau horaire spécifique

notre application a été conçue pour traiter les utilisateurs de différents lieux géographiques.

nous sommes incapables de détecter ce qui est l'heure locale actuelle de l'utilisateur final et fuseau horaire opérer sur elle. Ils sélectionnent différentes cultures comme sv-se, en-us, ta-In même ils accèdent du fuseau horaire Europe/Londres..

nous l'avons hébergé dans un serveur d'hébergement aux États-Unis, les utilisateurs de l'application sont de Norway/Denmark/Sweden/UK/USA/India

Le problème est que nous avons utilisé DateTime.Now pour stocker la date de création/mise à jour de l'enregistrement, etc.

depuis le le serveur tourne aux Etats-Unis toutes les données de l'utilisateur sont enregistrées en temps US: (

après des recherches dans SO, nous avons décidé de stocker toutes les dates de l'histoire en DB comme DateTime.UtcNow

problème:

enter image description here

il y a un enregistrement créé sur 29 Dec 2013, 3:15 P.M Swedish time .

 public ActionResult Save(BookingViewModel model)
    {
        Booking booking = new Booking();
        booking.BookingDateTime = model.BookingDateTime; //10 Jan 2014 2:00 P.M
        booking.Name = model.Name;
        booking.CurrentUserId = (User)Session["currentUser"].UserId;
        //USA Server runs in Pacific Time Zone, UTC-08:00
        booking.CreatedDateTime = DateTime.UtcNow; //29 Dec 2013, 6:15 A.M
        BookingRepository.Save(booking);
        return View("Index");
    }

nous voulons montrer le même temps d'histoire à l'utilisateur qui s'est connecté en Inde/Suède/USA.

à partir de Maintenant, nous utilisons l'utilisateur de culture actuelle connecté et de choisir le fuseau horaire à partir d'un fichier de configuration et en utilisant pour la conversion avec la classe TimeZoneInfo

<appSettings>
    <add key="sv-se" value="W. Europe Standard Time" />
    <add key="ta-IN" value="India Standard Time" />
</appSettings>

    private DateTime ConvertUTCBasedOnCuture(DateTime utcTime)
    {
        //utcTime is 29 Dec 2013, 6:15 A.M
        string TimezoneId =                  
                System.Configuration.ConfigurationManager.AppSettings
                [System.Threading.Thread.CurrentThread.CurrentCulture.Name];
        // if the user changes culture from sv-se to ta-IN, different date is shown
        TimeZoneInfo tZone = TimeZoneInfo.FindSystemTimeZoneById(TimezoneId);

        return TimeZoneInfo.ConvertTimeFromUtc(utcTime, tZone);
    }
    public ActionResult ViewHistory()
    {
        List<Booking> bookings = new List<Booking>();
        bookings=BookingRepository.GetBookingHistory();
        List<BookingViewModel> viewModel = new List<BookingViewModel>();
        foreach (Booking b in bookings)
        {
            BookingViewModel model = new BookingViewModel();
            model.CreatedTime = ConvertUTCBasedOnCuture(b.CreatedDateTime);
            viewModel.Add(model);
        }
        return View(viewModel);
    }

Afficher Le Code

   @Model.CreatedTime.ToString("dd-MMM-yyyy - HH':'mm")

NOTE: l'utilisateur peut changer le culture / Langue avant de se connecter. C'est une application basée sur la localisation, qui tourne dans un serveur américain.

j'ai vu NODATIME , mais je ne pouvais pas comprendre comment il peut aider avec multi culture application web hébergé dans un endroit différent.

Question

Comment puis-je afficher la même date de création d'un enregistrement 29 Dec 2013, 3:15 P.M pour les utilisateurs connectés en Inde/USA/N'importe où?

à partir de Maintenant ma logique dans ConvertUTCBasedOnCuture est basée utilisateur connecté dans la culture. Cela devrait être indépendamment de la culture, puisque l'utilisateur peut se connecter en utilisant n'importe quelle culture de L'Inde /USA

COLONNE DE LA BASE DE DONNÉES

CreatedTime: SMALLDATETIME

MISE À JOUR: TENTATIVE DE SOLUTION:

DATABASE COLUMN TYPE: DATETIMEOFFSET

UI

enfin j'envoie L'heure locale de l'utilisateur courant en utilisant le Momento ci-dessous.code js dans chaque requête

$.ajaxSetup({
    beforeSend: function (jqXHR, settings) {
        try {
      //moment.format gives current user date like 2014-01-04T18:27:59+01:00
            jqXHR.setRequestHeader('BrowserLocalTime', moment().format());
        }
        catch (e) {
        }
    }
});

APPLICATION

public static DateTimeOffset GetCurrentUserLocalTime()
{
    try
    {
      return 
      DateTimeOffset.Parse(HttpContext.Current.Request.Headers["BrowserLocalTime"]);
    }
    catch
    {
        return DateTimeOffset.Now;
    }
}

puis appelé

 model.AddedDateTime = WebAppHelper.GetCurrentUserLocalTime();

En Vue

@Model.AddedDateTime.Value.LocalDateTime.ToString("dd-MMM-yyyy - HH':'mm")

en vue il montre l'heure locale à l'utilisateur, cependant je veux voir comme dd-MMM-yyyy CET/PST (2 il y a quelques heures).

ce Il ya 2 heures devrait calculer à partir de l'heure locale de l'utilisateur final. Exactement le même que la question de débordement de la pile temps créé/modifié avec l'affichage du fuseau horaire et le calcul de l'utilisateur local.

exemple: answered Jan 25 '13 at 17:49 CST (6 hours/days/month ago) ainsi l'autre affichage de L'utilisateur USA/Inde peut vraiment comprendre ce disque a été créé exactement 6 heures de L'Inde / USA heure actuelle

presque je pense que j'ai tout accompli, sauf le format d'affichage et de calcul. Comment puis-je faire cela?

25
demandé sur Billa 2013-12-25 23:27:05

5 réponses

il semble que vous ayez besoin de stocker un DateTimeOffset au lieu d'un DateTime . Vous pourrait juste stocker le local DateTime à l'utilisateur créant la valeur, mais cela signifie que vous ne pouvez pas effectuer des opérations de commande etc Vous ne pouvez pas simplement utiliser DateTime.UtcNow , car cela ne stockera rien pour indiquer la date/heure locale de l'utilisateur lorsque le document a été créé.

Alternativement, vous pouvez stocker un instant dans le temps avec le temps de l'utilisateur zone - c'est plus difficile à réaliser, mais vous donnerait plus d'informations car alors vous seriez en mesure de dire des choses comme "Quelle est l'heure locale de l'utilisateur une heure plus tard?"

Le hébergement du serveur doit être hors de propos - vous ne devez jamais utiliser le fuseau horaire du serveur. Cependant, vous aurez besoin de connaître le décalage UTC approprié (ou fuseau horaire) pour l'utilisateur. Ce ne peut pas être fait sur la base juste de la culture - vous voudrez utiliser Javascript sur la machine de l'utilisateur pour déterminer le décalage UTC au moment qui vous intéresse (pas nécessairement "maintenant").

une fois que vous avez trouvé comment stocker la valeur, la récupérer est simple - si vous avez déjà stocké L'UTC instant et un offset, vous n'avez qu'à appliquer ce offset et vous reviendrez à l'heure locale de l'utilisateur d'origine. Vous n'avez pas dit comment vous convertissez les valeurs en texte, mais il devrait simplement abandonner simplement-juste formater la valeur, et vous devriez obtenir l'original local temps.

si vous décidez d'utiliser le temps Noda, vous n'utiliserez que OffsetDateTime au lieu de DateTimeOffset .

12
répondu Jon Skeet 2013-12-30 16:55:40

approche Standard est de toujours stocker des données de temps comme UTC si un moment particulier dans le temps est important. Ce temps n'est pas affecté par les changements de fuseaux horaires et les cultures.

l'approche la plus courante pour montrer le temps avec le fuseau horaire est de stocker le temps comme UTC et de passer à la combinaison culture/fuseau horaire de l'utilisateur courant quand vous affichez la valeur. Cette approche ne requiert qu'une seule date de dépôt dans l'entrepôt.

noter que pour les cas Web (comme ASP.Net) vous pouvez avoir besoin de comprendre la culture de l'utilisateur/le fuseau horaire d'abord et l'envoyer au serveur (cette information n'est pas nécessaire disponible sur les requêtes GET) ou faire formatage du temps dans le navigateur.

selon ce que "montrer la même heure d'histoire" vous pouvez avoir besoin de stocker des informations supplémentaires comme la culture actuelle et/ou l'offset actuel. Si vous avez besoin de montrer l'heure exactement comme l'utilisateur d'origine l'a vu, vous pouvez aussi enregistrer la représentation de chaîne (parce que les formats/traductions peuvent changer plus tard et la valeur paraîtra différente, aussi il est inhabituel).

Note: la culture et le fuseau horaire ne sont pas liés ensemble, donc vous aurez besoin de décider comment vous avez besoin de traiter les cas comme la culture IN-IN dans le fuseau horaire PST aux États-Unis.

11
répondu Alexei Levenkov 2013-12-25 19:54:43

je suis un peu confus par la formulation de votre question, mais il semble que vous voudriez déterminer le fuseau horaire de votre utilisateur.

  • avez-vous essayé leur demander ? De nombreuses applications ont à l'utilisateur de choisir son fuseau horaire dans les paramètres de l'utilisateur.

  • vous pouvez choisir à partir d'une liste déroulante, ou d'une paire de listes (pays, puis fuseau horaire à l'intérieur du pays), ou de une carte basée sur le temps de la zone de contrôle de sélecteur de .

  • on pourrait devinez et de l'utiliser comme valeur par défaut, à moins que vos modifications de l'utilisateur.

si vous empruntez cette route, vous devrez être en mesure d'utiliser les fuseaux horaires IANA/Olson, qui est l'endroit où Heure de Noda entre en jeu. Vous pouvez y accéder à partir de DateTimeZoneProviders.Tzdb .

le lieu d'hébergement n'est pas pertinent si vous utilisez UTC. C'est une bonne chose.

aussi, si vous utilisez Noda Time, alors vous devriez probablement utiliser SystemClock.Instance.Now au lieu de DateTime.UtcNow .

Voir aussi ici et ici .

aussi - une solution alternative serait de passer le temps UTC au navigateur et de le charger dans un objet JavaScript Date . Le navigateur peut convertir que pour l'utilisateur, heure locale. Vous pouvez également utiliser une bibliothèque comme moment.js pour faciliter les choses.


mise à Jour

concernant votre approche de la cartographie des codes de culture aux fuseaux horaires:

<appSettings>
    <add key="sv-se" value="W. Europe Standard Time" />
    <add key="ta-IN" value="India Standard Time" />
</appSettings>

que ne fonctionnera pas , pour plusieurs raisons:

  • beaucoup les gens d'utiliser un autre paramètre de culture sur leur ordinateur que la zone qu'ils sont physiquement dans. Par exemple, je pourrais être un anglophone américain vivant en Allemagne , mon code de culture est probablement encore en-US , pas de-DE .

  • un code de culture contenant un pays est utilisé pour distinguer les dialectes d'une langue. Quand vous voyez es-MX , cela signifie "espagnol, comme parlé au Mexique". Il ne signifie pas que l'utilisateur est en fait dans Mexique. Cela signifie simplement que l'utilisateur parle que le dialecte de l'espagnol, par rapport à es-ES qui signifie "espagnol parlé en Espagne".

  • même si la partie pays du code de culture pouvait être fiable, il y a beaucoup de pays qui ont de multiples fuseaux horaires! Par exemple, que mettriez-vous dans votre liste de mappage pour en-US ? Vous ne pouvez pas supposons que nous sommes tous à L'Heure de L'est.

Maintenant, j'ai expliqué pourquoi de votre approche ne fonctionne pas, je vous suggère fortement de prendre l'original de mes conseils. Très simplement:

  1. " Déterminez le fuseau horaire de l'utilisateur, de préférence en leur demandant, peut-être avec l'aide d'un des utilitaires que j'ai reliés ci-dessus.

  2. vous stockez UTC, donc convertissez-vous à ce fuseau horaire pour l'affichage.

    Utilisation Des Fuseaux Horaires De Microsoft
    TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
    DateTime localDatetime = TimeZoneInfo.ConvertTimeFromUtc(yourUTCDateTime, tz);
    
    Utilisation des fuseaux horaires IANA et de L'heure Noda
    DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Stockholm"];
    Instant theInstant = Instant.FromDateTimeUtc(yourUTCDateTime);
    LocalDateTime localDateTime = theInstant.InZone(tz);
    
7
répondu Matt Johnson 2017-05-23 11:54:03

nous avons eu un problème similaire avec une application sur laquelle j'ai travaillé récemment. Pendant le développement, tout le monde était dans le même fuseau horaire et le problème n'a pas été remarqué. Et dans tous les cas il y avait beaucoup de code d'héritage qui aurait été une douleur de changer pour ne pas mentionner la conversion de toutes les informations de date heure qui était déjà dans le DB. Ainsi, changer en DateTimeOffset n'était pas une option. Mais nous avons réussi à obtenir tout cohérent en convertissant du temps du serveur au temps de l'utilisateur sur le chemin de la sortie et en convertissant de temps de l'utilisateur au serveur en chemin. Il était également important de le faire avec toute comparaison de l'Heure de la date qui était une limite. Donc, si un utilisateur s'attendait à ce que quelque chose expire minuit leur heure, alors nous pourrions convertir cette heure en heure du serveur et faire toutes les comparaisons dans le temps du serveur. Cela ressemble à beaucoup de travail, mais était beaucoup moins de travail que la conversion de l'ensemble de L'application et de DB pour utiliser DateTimeOffsets.

entendre est un fil qui ressemble à a quelques bonnes solutions pour le temps question de la zone.

déterminer le fuseau horaire d'un utilisateur

1
répondu SzabV 2017-05-23 11:46:21

si vous voulez montrer l'historique de date/heure cohérente à l'utilisateur, quel que soit le lieu où ils regardent l'histoire de, puis:

  1. au cours de Save , stocker non seulement UTC" Date/Heure de création", mais aussi le lieu détecté
  2. utiliser stocké saved from locale pour calculer la date/heure originale et émettre une chaîne de caractères à afficher (c.-à-d. ne pas utiliser l'emplacement de l'utilisateur courant quand vous le diplayez)

si vous ne pas avoir la capacité de modifier votre stockage, alors peut-être que vous pouvez modifier votre Soumettre pour envoyer le "temps client actuel", le stocker littéralement (ne pas convertir en UTC) et ensuite afficher littéralement (ne pas convertir en culture détectée)

mais comme je l'ai dit dans mon commentaire sous votre question, Je ne suis pas certain d'avoir bien fait vos exigences.

0
répondu G. Stoynev 2013-12-30 16:39:27