Jak obsługiwać daty przy międzynarodowych aplikacjach?

Jak obsługiwać daty przy międzynarodowych aplikacjach?
G1
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 14 godzin
  • Postów:506
0

Witam. Potrzebuję pomocy w zrozumieniu, jak działa konwertowanie dat w ASP .Net CORE. Dla przykładu Klient pochodzi z Polski, a serwer stoi w strefie czasowej -2h względem Polski.
Teraz klient w formularzu klika dodaj subskrypcję i przesyła dane do serwera. U klienta jest teraz 10:00, a data utworzenia subskrypcji zapisuje się na serwerze o 08:00

Kopiuj
DateTime now = DateTime.Now;
Subscription subscription = new Subscription()
{
    Id = Guid.NewGuid(),
    ApplicationUserId = currentUser.Id,
    IsDeleted = false,
    CreatingTime = now,
    AvailableBuildingsToCreate = foundedSubscriptionTemplate.AvailableBuildingsToCreate,
    SubscriptionTemplateId = input.SubscriptionTemplateId,

    BeginSubscriptionTime = now,
    EndSubscriptionTime = now,
    DisableSubscriptionTimeIfNotPayed = now.AddDays(0).AddMinutes(10),
    TrialExpireTime = null,

    SubscriptionName = input.SubscriptionName,
};

Użytkownik opłacił subskrypcję i przekierowuje go do jego subskrypcji, pobieranej:

Kopiuj
var currentUser = await _userManager.GetUserAsync(User);
if (currentUser == null)
    return new List<SubscriptionDto>();

var now = DateTime.Now;
var activeSubscriptions = await _applicationDbContext.Subscriptions
    .Where(x => !x.IsDeleted)
    .Where(x => x.ApplicationUserId == currentUser.Id)
    .Where(x => x.BeginSubscriptionTime < now)
    .Where(x =>
        (x.BeginSubscriptionTime < now && (!x.DisableSubscriptionTimeIfNotPayed.HasValue || x.DisableSubscriptionTimeIfNotPayed > now) && (!x.EndSubscriptionTime.HasValue || x.EndSubscriptionTime > now))
    )
    .OrderBy(x => x.CreatingTime)
    .ToListAsync();

var subscriptionDtos = activeSubscriptions.Select(x => x.ToDto()).ToList();
return subscriptionDtos;

Niestety w widoku użytkownik widzi datę utworzenia subskrypcji na godzinę 08:00. Jest możliwość sprawienia, aby daty wysyłane od klienta do serwera i od serwera do klienta automatycznie konwertowały się na odpowiednią strefę czasową?

Nie wiem, czy dobrze to wyjaśniłem. W razie co powiedzcie, jakich informacji potrzeba

edytowany 1x, ostatnio: gswidwa1
markone_dev
  • Rejestracja:ponad 3 lata
  • Ostatnio:około 17 godzin
  • Postów:822
8

Daty (niezależnie od platformy) zapisujesz w UTC czyli DateTime.UtcNow Równocześnie z datą w UTC przechowujesz informację o strefie czasowej użytkownika i w trakcie prezentowania informacji konwertujesz datę z UTC na strefę czasową użytkownika var userDateTime = TimeZoneInfo.ConvertTimeFromUtc(dateTimeUtc, userTimeZone);

Jak masz dużo logiki opartej o date, czas i strefy czasowe to najlepiej skorzystaj z Noda Time żeby zaoszczędzić sobie roboty https://github.com/nodatime/nodatime


Programujący korpo architekt chmurowy.
Udzielam konsultacji i szkoleń w obszarze szeroko pojętego cloud computingu (Azure, AWS) i architektury systemów IT. Dla firm i prywatnie.
DevOps to proces nie stanowisko.
G1
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 14 godzin
  • Postów:506
0

@markone_dev: Czyli aby przekazać datę z serwera do klienta muszę z poziomu serwera odczytać lokalizacje klienta i przekonwertować DateTime do strefy czasowej klienta?
Czy na odwrót?: Serwer wysyła swój czas UTC a klient go sobie w js przekonwertuje?

SO
To już IMHO zależy do czego wykorzystujesz te daty. W najprostszych scenariuszach wystarczy jak serwer zwróci UTC i skonwertujesz na froncie.
G1
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 14 godzin
  • Postów:506
1

jak powiedzieliście zamieniłem DateTime.Now na DateTime.UtcNow oraz dodałem:

Kopiuj
builder.Services.AddMvc().AddNewtonsoftJson(options =>
{
    options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
});
builder.Services.AddControllersWithViews().AddNewtonsoftJson(options =>
{
    options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
});

aby json przesyłany do widoku był w formacie UTC. Wszystko działa pięknie. Dziękuję Wam!

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 11 godzin
  • Lokalizacja:Wrocław
6

Używanie DateTime to chyba największy błąd, jaki można popełnić w takiej sytuacji.
Zmień to na DateTimeOffset, aby uniknąć wszelkich problemów związanych z zastanawianiem się, co insertujący dane do bazy miał na myśli.

G1
Nigdy z tego nie korzystałem, potrzebuję czasu aby przerobić kilka artykułów na google. W razie problemów odświeżę wątek :) Dzięki!
snowflake2137
fascynujące, jak jasno dokumentacja ms każe używać DateTimeOffset do realnego czasu i jak mało ludzi o tym słyszało
somekind
Przyzwyczajenie, czy tam kult cargo. Sam widzisz ile w tym wątku całkowicie błędna odpowiedź dostała punktów, i nawet akcepta.
SO
Czemu całkowicie błędna? Jak wiesz, że w danym przypadku nie potrzebujesz przechowywać dat z różnymi offsetami to DateTime.UtcNow zadziała tak samo dobrze. Rzeczywiście może być trochę zastanawiania, co to pole oznacza, no ale nazwiesz sobie w modelu CośtamUtc i będzie wiadomo ;) Wzmiankę o strefie czasowej natomiast uważam za przydatną (prawda, że niekoniecznie do tego przypadku...), bo z drugiej strony zadziwiające jest jak wiele osób twierdzi, że przechowywanie Utc/Offsetu jest wystarczające w 100% przypadków :]
somekind
Jeżeli chcesz jednoznacznie określić moment w czasie, to używasz DateTimeOffset. Robienie tego inaczej, to tylko utrudnianie sobie życia.
jurek1980
  • Rejestracja:ponad 8 lat
  • Ostatnio:35 minut
  • Postów:3513
0

Z ciekawości jak jest z obsługą Timestamp w .netCore? W końcu ten system daty został wymyślony właśnie celem rozwiązania takich probelmów jak timezone.
Czy dostosowanie do obsługi SQL Serwer jest na tyle duże, że jedyny sensowny sposób działań to powyższe formaty?

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 11 godzin
  • Lokalizacja:Wrocław
0
jurek1980 napisał(a):

Z ciekawości jak jest z obsługą Timestamp w .netCore? W końcu ten system daty został wymyślony właśnie celem rozwiązania takich probelmów jak timezone.
Czy dostosowanie do obsługi SQL Serwer jest na tyle duże, że jedyny sensowny sposób działań to powyższe formaty?

@jurek1980: Masz na myśli linuksowy timestamp, w sensie liczbę milisekund od 1970? To są metody FromUnixTime i ToUnixTime w typach czasowych.
A SQL Server składuje to sobie jeszcze inaczej, w zależności od typu danych kolumny. Ale jedno jest pewne - zakres dat ma znacznie większy niż epoch, bo jednak w bazie często trzyma się np. datę urodzenia, a istnieją ludzie, którzy mają więcej niż 53 lata. :P

G8
To są jeszcze jacyś ludzie starsi od Unixa?
jurek1980
  • Rejestracja:ponad 8 lat
  • Ostatnio:35 minut
  • Postów:3513
1

@somekind: ale jeśli jest data poniżej 1970 to po prostu jest to liczba ujemna.
Unix Timestamp -2156097167 GMT Thu Sep 05 1901 04:07:13 GMT+0000
Coś jak 100 lat p.n.e.

SA
  • Rejestracja:ponad 12 lat
  • Ostatnio:3 minuty
  • Postów:1435
0
jurek1980 napisał(a):

@somekind: ale jeśli jest data poniżej 1970 to po prostu jest to liczba ujemna.
Unix Timestamp -2156097167 GMT Thu Sep 05 1901 04:07:13 GMT+0000
Coś jak 100 lat p.n.e.

Żeby było śmieszniej to ani DateTime ani DateTimeOffset nie obsługują dat przed naszą erą :P

obscurity
wystarczy przechowywać dodatkowy bit na znak, ale raczej mało aplikacji potrzebuje takich dat, a daty przed naszą erą zazwyczaj są mało dokładne i potrzebujemy jedynie rok lub nawet stulecie
SL
  • Rejestracja:około 7 lat
  • Ostatnio:4 minuty
  • Postów:901
0
jurek1980 napisał(a):

Z ciekawości jak jest z obsługą Timestamp w .netCore? W końcu ten system daty został wymyślony właśnie celem rozwiązania takich probelmów jak timezone.

Tak i nie. Timestampy są dobre, jeśli dostajemy je od klienta lub je generujemy. W innych wypadkach jest różnie. Przykładowo, jeśli otrzymasz informację o locie, że wylatuje danego dnia o danej godzine z danego lotniska bez podanej strefy czasowej. W takim wypadku wyrokowanie jaka jest tam strefa czasowa może być ciężkie a czasami niemożliwe np. wtedy jak zegar się cofa wraz ze zmianą czasu zimowego na letni.

Oczywiście timestampy to dobre rozwiąznie do praktycznie każdego problemu ale trzeba pamiętać, że mierzenie czasu to bardzo skomplikowany temat

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.