Dlaczego nie istnieje prawdziwy typ danych „Tylko data”?

24

Jestem tak śmiesznie sfrustrowany, że muszę używać wartości DateTime dla zestawów danych, które są naprawdę „tylko jeden dzień”. Urodziny są najczęstszym przykładem, ale cały czas pojawia się w aplikacjach biznesowych.

Przyzwyczaiłem się do ustawiania części Time rekordów „tylko data” na „południe” (co pozwala uniknąć zmiany daty bez względu na strefę czasową). To wygląda na włamanie i zawsze znajduję błędy od młodszych deweloperów, które potknęły się o ten problem.

Czas zawsze zależy od stałego punktu. 16.00 to 4 godziny po południku lub w południe. Obserwowany jest najwyższy punkt tranzytowy Słońca i pozwala nam ustawić układ współrzędnych. 3 godziny przed południem (Ante Meridian), 2 godziny po południu, 1441899402938 milisekund od 1 stycznia 1970 r. Dla ludzi wychowanych w kartezjańskim świecie jest to druga natura.

Ale nasz kalendarz poprzedza Kartezjusza. Moim argumentem jest to, że bardziej poprawnie jest traktowany jako wyliczenie, w którym stosowana jest funkcja modulo. Poniedziałek następuje po niedzieli i tak dalej, aż dojdziesz do faktu, że niedziela następuje po sobocie. Nie ma dodatniego i ujemnego, jest to moduł lub wartość bezwzględna.

Podobnie z powtarzającymi się latami. Co 365 dni (lub tak) jest dla mnie kilka specjalnych dni: urodziny, rocznice, urodziny dla dzieci itp. Itp. Aplikacje do planowania spotkań biznesowych są pełne przykładów spotkań co siedem dni, pierwszy wtorek miesiąca itp. Tylko dlatego, że MOŻEMY odwzorować to na liczbę zmiennoprzecinkową, a tak naprawdę odwzorowanie na wspomnianą liczbę rozwiązuje wiele problemów, które są naprawdę trudne w stary sposób, ale to nie znaczy, że jest to jedyny sposób, aby to zrobić.

Świadomość i zrozumienie natury „kwadratowego kołka w okrągłej dziurze” polegającej na używaniu DateTimes do przechowywania Daty sprawia, że ​​moim zdaniem jesteś lepszym programistą.

Czy w aplikacji definiującej klasę Date jest wartość, która jest wyraźnie przeznaczona jako aplikacja do planowania, czy też najlepszym rozwiązaniem jest „ustawienie na cały czas do południa”? Jakie mogą być problemy z użyciem DateTime i ustawieniem składnika Time na Noon? Czy w takim podejściu można uwzględnić przesunięcie strefy czasowej? Użyłem MomentJS, ale myślę, że to po prostu lepsza klasa Date.

Michael Blackburn
źródło
7
myślę, że to dość interesujące pytanie. Weźmy przykład urodzin, to naprawdę ma sens tylko u ludzi, mieszkam w jednym miejscu i wszyscy budzą się w tym samym czasie, w pewien sposób. gdy tylko trzeba to wyrazić matematycznie, staje się bardzo złożone. To samo dotyczy rzeczy takich jak czas rozpoczęcia / zakończenia zmiany pracy itp. Nie są one „czasami”, są „godzinami dnia w strefie czasowej, w której pracujesz”
Ewan
3
NodaTime (biblioteka C # dla daty i godziny) ma rodzaj dat.
CodesInChaos
5
Przechowuj swoje czasy jako UTC, bez problemów z datą, bez problemów ze strefą czasową.
Loren Pechtel,
3
„Ale Boże, to wygląda na włamanie i na zawsze znajduję błędy od młodszych twórców, którzy potknęli się o ten problem”. - dlaczego po prostu nie stworzysz swojej własnej klasy DateOnly, czy coś takiego i nazwiesz to dniem?
Brandin,
5
@MichaelBlackburn Jestem poważny. Twoje wyjaśnienie brzmi dokładnie tak, jak w przypadku własnego typu danych, który egzekwuje regułę biznesową (tylko data, np. Możesz zapisać ją wewnętrznie jako „DateTime” z częścią czasową ustawioną na południe), a następnie ujawnić tylko te części, które chcesz (miesiąc , dzień itp. rok / brak roku).
Brandin,

Odpowiedzi:

15

Przede wszystkim usuńmy jedno: urodziny to jedno, a daty urodzenia to drugie. Urodzin to egzotyczny typ danych, ponieważ brakuje nie tylko składniki godzin, minut itd ale również brakuje składnika rok. Jeśli naprawdę chcesz poradzić sobie z urodzinami, zaleciłbym wymyślenie własnego typu danych, który zawiera tylko numer miesiąca i numer dnia i nie jest powiązany z żadnym z wbudowanych typów danych data-godzina.

Z drugiej strony, jeśli chcesz również śledzić rok urodzenia, to to, co masz, to nie urodziny, to daty urodzenia . Powstaje teraz pytanie, dlaczego nie ma typu danych zawierającego tylko datę, dzięki czemu można wygodnie przedstawiać daty urodzenia, a zamiast tego popularne języki zmuszają do korzystania z niektórych typów, które zawierają również składnik czasu.

Pozwolę sobie krótko wspomnieć, że nie jest prawdą, że wszystkie języki programowania oferują tylko typy danych czasowych, które zawierają składnik czasu. Natknąłem się na typy danych tylko z datą w RDBMS i odpowiadających im dialektach SQL. Ale to nie ma znaczenia: fakt, że te typy danych istnieją, nie oznacza, że ​​warto je mieć, a RDBMS mają długą historię mylenia pamięci z reprezentacją.

Zrozumiesz, dlaczego posiadanie tego typu danych tylko z datą jest kiepskim pomysłem, gdy tylko zorientujesz się, że czas jest współrzędną. Większość ludzi ma bardzo niejasne pojęcie o tym, która jest godzina, i ta idea zawiera tajemnicze pojęcia kulturowe, takie jak lata, miesiące i dni, nie zdając sobie sprawy, że te pojęcia są wyłącznie reprezentacyjne : są one przydatne tylko do reprezentowania czasu człowiekowi i otrzymywania czas jako wkład człowieka. Na dowolnej warstwie poniżej rzeczywistej kontroli GUI wprowadzania czasu, czas powinien być i zwykle jest reprezentowany jako współrzędna czasu, która jest pojedynczą liczbą jednostek czasu od pewnego początku.

Na przykład w DateTimetypie danych Microsoft Dotnet jednostka czasu wynosi 100 nanosekund, a początek czasu to 12:00 północy, 1 stycznia 0001 CE

Innym przykładem tajemnej, wyłącznie reprezentacyjnej notacji są pomiary kąta przy użyciu stopni, minut stopnia i sekund stopnia. Oczywiście, aby wykonać użyteczne obliczenia, musisz wewnętrznie użyć radianów, a jeśli to konieczne, przekonwertować do i od stopni podczas interakcji z ludzkim użytkownikiem.

Nie należy więc mylić czytelnej dla człowieka reprezentacji pomiaru z faktyczną naturą pomiaru. Bardzo często idealna metoda wykonania pomiaru, która najbardziej odpowiada naturze pomiaru, bardzo różni się od czytelnej dla człowieka reprezentacji tego pomiaru.

W świetle tego wszystkiego, twoje żądanie czasowego typu danych reprezentującego tylko daty jest podobne do żądania kątowego typu danych, który byłby w stanie reprezentować tylko stopnie, wyraźnie uniemożliwiając większą precyzję. Taki typ danych byłby dość ograniczony, a ostatecznie bezużyteczny, ponieważ musiałbyś i tak przekonwertować go na iz radianów, aby zrobić z nim cokolwiek pożytecznego.

Twój problem z datą urodzenia polega na tym, że masz nieprecyzyjną współrzędną czasową: osoba ta oczywiście urodziła się w określonym momencie, ale godzina i minuta albo nie zostały zarejestrowane przez szpital, albo nie dbać o nich. Tak naprawdę dzieje się tak, że twoja współrzędna czasu i daty urodzenia ma margines błędu, tolerancję lub niepewność, jeśli chcesz, i najlepiej traktować to w ten sposób: ustaw dokładnie na środku dnia i rozważ domniemaną niepewność +12-12 godzin. I to jest dokładnie rozwiązanie, do którego intuicyjnie dotarłeś.

Mike Nakis
źródło
4
Nie dotyczy to „Dni”, które są koncepcją nawet starszą niż Czas. Są one najodpowiedniej uważane za wyliczenie lub moduł. Niedziela następuje po poniedziałku itp., Aż wrócimy do niedzieli, która następuje po sobocie. To naprawdę inna sprawa.
Michael Blackburn,
10
No cóż, oczywiście szpital zapisał datę urodzenia - to standardowa praktyka w większości szpitali. To wcale nie jest problem. Problem polega na tym, że w celu upamiętnienia wydarzeń (urodziny, święta, rocznice itp.) Ludzie nie używają lub nie chcą rozwiązania, które jest lepsze niż 1 dzień. Idź spytaj pierwszą osobę, którą zobaczysz, kiedy mają urodziny, a ona da ci miesiąc i dzień, ale nigdy godzinę i minutę. Ponadto: używamy jednostek, które cały czas zawierają skalę: milimetr, kilogram, megawat, a nawet mikrofarada.
Caleb
4
-1: Nie wszystkie zastosowania czasu mają reprezentować pojedynczy moment w czasie. Urodziny to inny pomysł, reprezentowany przez miesiąc i dzień w kalendarzu gregoriańskim. Warto zapytać „czy dziś są urodziny Kevina?” Odpowiedź zależy od lokalizacji. Gdybym był w Sydney, mogłyby to być moje urodziny, ale gdybym był w Honolulu, nie byłoby to jeszcze przez kilka godzin.
kevin cline
6
@MikeNakis Rezultatem byłyby mikroampery, a nie bzdury. Co ważniejsze: kiedy używasz daty zamiast sekundy lub milisekundy, ogólnie mówisz o całym dniu - przedziale czasowym - a nie o określonej godzinie, aw zależności od kontekstu może to być wydarzenie powtarzające się.
Caleb
4
OP mówił o urodzinach, które dokładnie reprezentuje java.util.MonthDay. Urodziny nie są miarą, to ludzka koncepcja dnia, który powtarza się co roku. Istnieje wiele ludzkich wyobrażeń o czasie, które nie są reprezentowane przez jeden punkt w czasie.
kevin cline
9

Daty i godziny różnią się w zależności od kontekstu i potrzebujesz wielu osobnych typów, aby uwzględnić wszystkie przypadki użycia.

DateTimeTyp występuje w wielu językach przedstawiają dokładny punkt w czasie ( „natychmiastowy czas”). Poza tym mamy wiele względnych lub „ludzkich” koncepcji czasu i przedziału czasowego, takich jak dni kalendarzowe, powtarzające się daty, miesiące, lata itp., Które w wielu przypadkach są niejednoznaczne i zależą od kontekstu. Te typy nie są tak powszechnie przydatne, ale konieczne w określonych domenach aplikacji, takich jak kalendarze, narzędzia do planowania i inne aplikacje, które wchodzą w interakcje z ludzkimi koncepcjami czasu.

Jeśli piszesz coś w rodzaju aplikacji kalendarza, na pewno skorzystasz z biblioteki takiej jak Joda-time, która zapewnia bogatszy zestaw typów czasu. Na przykład LocalDatedata bez godziny. Ma to inną semantykę niż zwykła DateTimez częścią czasową ustawioną na zero, ponieważ DateTimenadal wskazuje konkretny punkt w czasie (północ w określonej strefie czasowej), podczas gdy LocalDatewskazuje cały dzień i nie jest powiązany z określoną strefą czasową. Oznacza to również, że nie możesz bezpośrednio tłumaczyć jednego na drugi.

LocalDatejest z pewnością prostsze niż DateTimeto, że nie musi uwzględniać stref czasowych, ale należy pamiętać o innych kwestiach, np. że bieżąca data może faktycznie cofnąć się, gdy przekraczasz strefę czasową, i że ta sama chwila może odpowiadają różnym datom w różnych strefach czasowych. Jeśli używasz lokalnych dat w aplikacjach sieciowych lub internetowych, powinieneś bardzo uważać na te problemy. Usunięcie części czasu z daty nie rozwiązuje podstawowego problemu stref czasowych! A jeśli weźmie się pod uwagę daty historyczne i różne kultury, staje się to jeszcze trudniejsze, ponieważ ta sama data może odpowiadać niezwykle różnym przypadkom w czasie, na przykład kalendarzowi juliańskiemu i gregoriańskiemu.

Teraz pytasz, dlaczego języki nie mają czegoś takiego jak LocalDate wbudowane . Po pierwsze, niektóre języki, takie jak SQL i Visual Basic, mają typ daty bez części czasowej. A Java dodała również LocalDatew najnowszej wersji. Ale inne platformy, takie jak .Net, nie. Tylko projektanci języków mogą naprawdę odpowiedzieć, dlaczego nie jest to uwzględnione w standardowej bibliotece, ale domyślam się, że „natychmiastowy czas” jest koncepcyjnie prosty i uniwersalnie użyteczny, podczas gdy inne koncepcje czasowe są przydatne tylko dla określonych domen aplikacji (takich jak kalendarze itp. .). Dlatego warto pozwolić twórcy aplikacji na pisanie niestandardowych typów w celu obsługi bardziej złożonych przypadków użycia lub pozwolić, aby zajmowała się tym biblioteka zewnętrzna (np. Joda-time).

JacquesB
źródło
5

Jestem tak śmiesznie sfrustrowany, że muszę używać wartości DateTime dla zestawów danych, które są naprawdę „tylko jeden dzień”. Urodziny są najczęstszym przykładem, ale cały czas pojawia się w aplikacjach biznesowych.

Wynika to prawdopodobnie z faktu, że kalendarz jest skomplikowany i używany na tak wiele różnych sposobów, że nikt nie był w stanie wymyślić klasy, która jest prosta, ale na tyle ogólna, aby była przydatna w wielu dziedzinach.

Typ daty powszechnie spotykany w językach programowania może służyć do dokładnego datowania transakcji w systemie komputerowym. Inne przypadki użycia mogą wymagać niestandardowej biblioteki.

Oto krótka lista faktów na temat kalendarzy, pokazująca ich złożoność - większość z nich ma charakter historyczny, więc jeśli ograniczasz swoją uwagę do dat po 1.1.1970, nie będzie to miało na ciebie wpływu. Jeśli jednak aplikacja musi pracować z datami sprzed końca XIX wieku, fakty te będą miały znaczenie. Możliwe przypadki użycia to wszelkiego rodzaju historyczne bazy danych (książki, genealogia), ale także aktywa dużych firm lub organizacji, które nadal działają.

Wszystkie te fakty są cytowane z doskonałego FAQ znalezionego w bibliotece kalendarza dla OCaml napisanej przez Juliena Signollesa.

  1. Kalendarz juliański został wprowadzony przez Juliusza Cezara w 45 rpne. Był w powszechnym użyciu do 1500 roku, kiedy kraje zaczęły zmieniać kalendarz gregoriański (sekcja 2.2). Jednak niektóre kraje (na przykład Grecja i Rosja) korzystały z niego w latach XX wieku, a cerkiew w Rosji nadal go używa, podobnie jak niektóre inne cerkwie.

  2. Przejście z kalendarza juliańskiego na kalendarz gregoriański nie nastąpiło jednolicie, aw zależności od roku zmiany skrócono 10 do 13 dni. Na przykład we Francji 9 grudnia 1582 r. Nastąpił 20 grudnia 1582 r., Aw Grecji 9 marca 1924 r. Nastąpił 23 marca 1924 r.

  3. Nawet w epoce nowożytnej używa się wielu różnych kalendarzy (gregoriański, prawosławny, islamski i chiński), aby zacytować kilka, z których wszystkie używają różnych sposobów obliczania lat i rocznic lub dat celebracji religijnych.

Teraz masz nadzieję na typ daty w pakiecie z operacjami przydatnymi do ogólnych operacji biznesowych. Myślę, że nie ma czegoś takiego jak ogólne operacje biznesowe. Na przykład w świecie finansów musimy obliczyć:

  1. Ułamki roku (np. „6 miesięcy” odpowiada „0,5”), które są stosowane w połączeniu ze stopą procentową do obliczenia rzeczywistych odsetek od pożyczki na dany okres. Istnieje od 6 do 10 przepisów na obliczenie tych ułamków, z których każdy różni się sposobem obsługi długości roku przestępnego, pozycją okresu w odniesieniu do ostatniego dnia lutego i czasem trwania miesiąca.

  2. Podczas obliczania rocznic przy obliczaniu roczników korzystamy z kalendarza biznesowego i reguły (wybranej z zestawu ponad 6 różnych reguł), aby zmienić rocznicę z wakacji na dzień roboczy.

Dla osób pracujących w branży finansowej każdy typ kalendarza, który nie wdraża wszystkich tych funkcji i zasad, jest bezużyteczny. Jest prawdopodobne, że wiele innych branż ma inne nawyki i konwencje wymagające niestandardowych obliczeń w kalendarzu.

Czy w aplikacji definiującej klasę Date jest wartość, która jest wyraźnie przeznaczona jako aplikacja do planowania, czy też najlepszym rozwiązaniem jest „ustawienie na cały czas do południa”? Jakie mogą być problemy z użyciem DateTime i ustawieniem składnika Time na Noon? Czy w takim podejściu można uwzględnić przesunięcie strefy czasowej? Użyłem MomentJS, ale myślę, że to po prostu lepsza klasa Date.

Jeśli chcesz śledzić pojedynczy dzień kalendarzowy, najlepszym sposobem jest prawdopodobnie użycie dużej liczby całkowitej reprezentującej dzień juliański tego dnia kalendarzowego. Algorytmy konwertowania tam iz powrotem z dnia juliańskiego na dzień kalendarzowy - opisane z rokiem, miesiącem i kalendarzem - są powszechnie znane i dokładnie testowane, dzięki czemu można je łatwo wdrożyć w aplikacji - i dowiedzieć się, jaka reguła jest właściwa w twoim przypadek, aby obliczyć rocznicę zdarzenia, które miało miejsce 29. lutego.

Michael Le Barbier Grünewald
źródło
2

Myślę, że Mike Nakis w swojej powyższej odpowiedzi ma lepszą robotę niż wyjaśnienie, w jaki sposób czas ogólnie jest bezwzględnie mierzoną współrzędną, a jakakolwiek inna komunikacja, przypuszczalny stan lub trwałość tej współrzędnej czasu jest jedynie abstrakcyjnym przedstawieniem wspomnianej współrzędnej czasu.

Mówisz do takich reprezentacji, odnosząc się do Dnia Tygodnia, jako do pewnego rodzaju modułu reprezentacji rzeczywistego punktu w czasie. W rzeczywistości jest to nieco bardziej skomplikowane. Jeśli masz za zadanie napisać funkcję, która zwróci Dzień tygodnia dla danego punktu w czasie, rozważ następujące informacje, które będą potrzebne jako dane wejściowe do takiego algorytmu. Będziesz potrzebował punktu w czasie, kalendarza, strefy czasowej do rozważenia (pamiętaj, że strefy czasowe zmieniają CAŁY CZAS, więc musisz wiedzieć, kiedy ta efektywna strefa czasowa zaczęła się, kiedy skończyła się w określonych współrzędnych czasowych. Korea Północna niedawno zmienił ich na przykład!), a jeśli obowiązuje czas letni, to również zmienia się z czasem. Zastanów się, czy otrzymałeś DateTime w lokalnej strefie czasowej,

Możesz zobaczyć, jak skomplikowane może być to pozornie proste pytanie.

Wiem, że odczuwasz ból, gdy w pewnym momencie byłem w twoich butach, naprawiając wszystkie błędy w aplikacji do planowania wizyt dla produktu napisanego przez niedoświadczonych programistów. Całą rzecz trzeba było złomować.

Czas jest rzeczywiście współrzędną, ale oprócz zwykłej daty, rozważ inne dane wrażliwe na czas, które mogą być potrzebne, takie jak:

Czas trwania: Zakres milisekund, który może wystąpić, który oznacza długość lub upływ czasu bez określonych współrzędnych czasowych. Przypadkiem użycia może być

Jako użytkownik chciałbym, aby to zadanie było wykonywane 15 sekund po zakończeniu zadania o północy co drugą środę.

Interwał: zakres czasu między dwiema konkretnymi współrzędnymi czasu. Przypadek użycia, w którym warto rozważyć przerwę.

Jako użytkownik muszę widzieć każdy dzień miesiąca całkowicie zawarty w określonym przedziale czasu.

Kolejną szybką kwestią, o której chciałem powiedzieć, jest to, że skomentowałeś liczby zmiennoprzecinkowe dla danych opartych na czasie i odradzam to. Arytmetyka zmiennoprzecinkowa nieuchronnie prowadzi do błędów zaokrąglania, które mogą nie dać ci tak dokładnego pomiaru, jak to konieczne do czasu.

Podsumowując, wszystkie te informacje nieuchronnie prowadzą do następujących rozważań projektowych:

  • Określone punkty lub zakresy w czasie powinny zostać utrwalone w UTC lub w niektórych typach danych, które zawierają wystarczającą ilość informacji, aby w razie potrzeby można je było łatwo odzyskać z powrotem do UTC
  • Logikę aplikacji należy zapisać w celu sformatowania UTC lub zakresu współrzędnych UTC w reprezentatywny stan danych, który jest bardziej przyswajalny dla użytkownika końcowego.
  • Ważne czasy trwania należy zachować w milisekundach
  • Preferencje regionalne lub preferencje użytkownika końcowego dotyczące wyświetlania wszelkich danych dotyczących czasu powinny zostać utrwalone jako dodatkowe dane i traktowane jak opcja wyświetlania. (Np. Kiosk A, centralna strefa czasowa, format czasu wojskowego lub preferencje użytkownika B, czas standardowy w strefie czasowej Tel Awiwu (GMT + 7: 00) itp.)
  • Unikaj numerów FP
wałek klonowy
źródło
1
Nic z tego nie jest „nieuniknione”. Może to być wspólne dla wielu aplikacji, ale Wielki Zderzacz Hadronów zajmuje się zdarzeniami w skali nanosekundowej. Czasy systemowe przesunęły się do mikrosekund, ponieważ milisekundy nie mają wystarczającej precyzji. Aplikacje kalendarza muszą mieć pojęcie daty, która ma miejsce w lokalnym dniu kalendarzowym, niezależnie od tego, czy jesteś w tej samej strefie czasowej, w której utworzyłeś wydarzenie.
Alan Shutko
1
@AlanShutko I tak, że „dodatkowe dane”, które są potrzebne, to np. Lokalna strefa czasowa i dni oraz wszelkie inne ważne dane, które należy przechwycić. Są to jednak tylko abstrakcje do jednego punktu w czasie, nawet jeśli moment nie jest ważny dla twojego algorytmu. Jeśli chodzi o skalę nanosekundową, a nawet mikrosekundową, moja odpowiedź jest bardziej ukierunkowana na oprogramowanie sieciowe i typu LOB. Wątpię, czy wybranym językiem LHC jest C # lub Javascript.
wałek klonowy
1
Milisekundy doskonale nadają się do powtarzalnych procesów fizycznych. W przypadku działalności człowieka czasami odpowiednią jednostką są dni nominalne, np. Jeśli wysłane pod koniec dnia, będą dostępne do użytku w miejscu docelowym trzy dni później.
kevin cline
W przeszłości rozważałem użycie 64-bitowych liczb zmiennoprzecinkowych dla współrzędnych czasowych, a co ważniejsze dla przedziałów czasowych, ponieważ pozwalają one na wyrażanie małych ilości z wielką precyzją, a także dużych, gdzie utrata precyzji tak naprawdę nie ma znaczenia . (A co jeśli dinozaury zmarły 65 milionów lat temu dają lub zabierają kilka lat?) Dlaczego więc mówicie, że należy ich unikać?
Mike Nakis,
Mike, myślę, że jego troska dotyczy matematyki FP nieuchronnie zaokrąglającej, ponieważ konwertuje wartości dziesiętne na binarne. Na przykład 0,3 jest powtarzającym się dziesiętnym, gdy jest wyrażone jako binarna liczba FP, a zatem nie może być dokładnie przedstawiona. Nie chodzi o to, że brakuje ci pojemności, ale brakuje ci precyzji.
Michael Blackburn,
2

Krótko mówiąc, ponieważ większość typów czasu opartych na komputerze koncentruje się na prawidłowym zarządzaniu czasem i strefą czasową.

Istnieją 2 przypadki skrajne, które nie są dobrze obsługiwane przez zwykłe podejście. Ustawienie punktu czasowego po drugiej stronie zmiany czasu letniego przy użyciu czasu lokalnego, który następnie jest konwertowany w UTC o niższą warstwę abstrakcji, a następnie powoduje godzinę wcześniejszą / późną na spotkanie.

Drugim jest (zgodnie z pytaniem) modelowanie dowolnych informacji o dacie, takich jak rejestracja daty urodzenia osoby. Wyobraź sobie przypadek, w którym dwie osoby rodzą się jednocześnie, jedna w Nowej Zelandii, druga na Hawajach. Prawdopodobnie będą mieli różne daty urodzenia w paszportach, a jeśli osoba urodzona na Hawajach przeprowadzi się do Nowej Zelandii, zostanie uznana za dzień starszą niż osoba urodzona w Nowej Zelandii, mimo że żyła dokładnie w tym samym czasie.

Sugestia zawarta w pytaniu jako ustawienie godziny na południe, UTC będzie działać, PRAWIE wszędzie. Przesunięcia UTC wynoszą od -12 do +14, więc jest kilka miejsc na Pacyfiku, w których takie podejście się nie powiedzie. Zwykle traktuję te typy danych jako ciągi znaków w formacie rrrrmmdd, a jeśli muszę wykonać obliczenia porównań między dwiema datami, można to bezpiecznie zrobić jako porównanie ciągów. Dokonując porównań delta (np. Między datą a teraz lub jak długo osiągają wiek X), musisz upewnić się, że wszystkie daty są tworzone w tym samym przesunięciu UTC, a następnie możesz użyć standardowych funkcji czasu do wykonania pracy.

Michael Shaw
źródło
3
Zwykle traktuję te typy danych jako ciągi znaków w formacie rrrrmmdd, a jeśli muszę wykonać obliczenia porównań między dwiema datami, można to bezpiecznie zrobić jako porównanie ciągów. ” To z pewnością brzmi jak Datetyp danych, po prostu przenoszony w aString
Ross Patterson
Tak jak mówisz, jest to ciąg znaków przedstawiający datę i, w przeciwieństwie do oryginalnego plakatu, data nie ulega zmianie, ponieważ znajduje się w strefie czasowej UTC + 13.
Michael Shaw
2

Dlaczego nie istnieje prawdziwy typ danych „Tylko data”?

Z tych samych powodów, myślę, że wartości DateTime są ogólnie określone w UTC: prostota i niezawodność . Punktem wartości DateTime jest określenie pojedynczego punktu w czasie, na który nie ma wpływu strefa czasowa, czas letni, kalendarz i inne dostosowania lokalne. Wartości DateTime określają jedną chwilę (do limitu rozdzielczości typu), a nie przedział czasu lub zestaw czasów. Ograniczenia te umożliwiają porównywanie wartości DateTime w niezawodny, przewidywalny i nieskomplikowany sposób.

Próba podania daty o wartości DateTime jest jak próba użycia punktu do określenia obszaru.Możesz to zrobić, stosując konwencję, na przykład „ten punkt reprezentuje środek koła o promieniu 100 m”, ale jest tam wiele problemów: wszyscy muszą stosować tę samą konwencję, musisz napisać kilka obsługa kodu, aby praca z niewłaściwym typem była mniej bolesna, i jest prawie pewne, że w pewnym momencie będziesz musiał określić obszar większy lub mniejszy niż obszar konwencjonalny. Tak też jest z datami: możesz użyć „południa” jako tradycyjnego czasu do określania dat, ale potem wchodzisz w strefy czasowe, ponieważ ludzie oczekują określenia dat w czasie lokalnym, a nie UTC. I nawet jeśli wymyślisz zadowalający sposób użycia DateTime do określenia daty, potrzebujesz więcej informacji, aby wiedzieć, czy jest to data bezwzględna czy względna: czy to 4 lipca, 1776 czy co 4 lipca? Co jeśli chcesz powtórzyć używając innego okresu? A kalendarze mają wiele szalonych problemów: niektóre miesiące są dłuższe niż inne, niektóre lata są dłuższe niż inne, niektóre dni są nawet dłuższe niż inne, a niektóre kalendarze mają luki. Nie chciałbyś rozwiązywać tych problemów tylko przez całe dni, ponieważ te same problemy pojawiają się w krótszych okresach: prawdopodobnie chciałbyś być w stanie napisać kod, który wyraża „weź 1 tabletkę co 4 godziny” tak łatwo jak „ grupa spotyka się w każdy trzeci piątek ”.

Praca z datami wiąże się z wieloma komplikacjami. Względnie (bez zamierzonej gry słów) łatwo jest podać typ, który określa punkt w czasie i pracować z nim tak jak w przypadku liczby, ale niezwykle trudno jest podać typ, który odnosi się do wszystkich sposobów używania dat.

Jak inni zwrócili uwagę, że języki i biblioteki, które zapewniają dobre wsparcie dla dat, a to często dobry pomysł, aby wykorzystać je biorąc pod uwagę to dość trudno dostać kod daty związane dokładnie.

Caleb
źródło
2
„Trudno podać typ uwzględniający wszystkie sposoby używania dat”. To prawda, dlatego okropnym pomysłem jest zapewnienie jednego typu, aby to wszystko zrobić. Pierwsze wersje Java zawierały tylko java.util.Date, a wynik był okropny. Następnie dodali złożoną hierarchię java.util.Calendar i nie poprawiło się to znacznie.
kevin cline
1
@kevincline W pełni się zgadzam. OP nie określił języka, więc dążyłem do ogólności.
Caleb
Z tych samych powodów, myślę, że wartości DateTime są ogólnie określone w UTC ”… Och, czy to by było prawdą. Jest rok 2015 i wciąż jest dużo kodu pisanego przy użyciu domowej strefy czasowej autora :-(
Ross Patterson
1
Naprawdę zastanawiałem się, dlaczego nie ma ogólnie przyjętej konwencji dotyczącej dat. Twoje „używanie punktu do reprezentowania obszaru” doskonale ujmuje moją frustrację.
Michael Blackburn,
2

Dlaczego nie istnieje prawdziwy typ danych „Tylko data”?

Istnieje wiele takich typów w różnych bibliotekach dla różnych języków. Jest prawie na pewno jeden dla twojego obecnego języka. Pakiet użytkownika Java miał okropne API do obliczania czasu, ale wprowadzenie pakietu java.time znacznie poprawiło życie. Zobacz java.time.LocalDate, zawierający wartość rok-miesiąc-dzień, lub java.time.MonthDay, zawierający tylko numer miesiąca i dnia.

Kevin Cline
źródło
1

Manipulowanie kalendarzem jest jednym z najgorzej rozumianych aspektów informatyki. Na ten temat napisano całe książki. @MichealBlackburn ma absolutną rację, prosząc o typ danych zawierający tylko datę, taki, który nie zostanie rozwiązany do punktu na osi czasu, z zastrzeżeniem ponownej interpretacji. Historycznie istniały uzasadnione spory dotyczące znaczenia daty. Nie trzeba szukać dalej niż przyjęcie kalendarza gregoriańskiego, aby dowiedzieć się, jak skomplikowany może być. Co więcej, lata nie zawsze zaczynały się 1 stycznia, nawet w Europie Zachodniej i jej koloniach ( np. Wielka Brytania i Ameryka Brytyjska rozpoczęły rok 25 marca).

Ross Patterson
źródło
1
To prawda. Często zadawane pytania dotyczące kalendarza, które cytuję w swojej odpowiedzi, są doskonałym źródłem do odkrywania złożoności i subtelności manipulacji konspiracyjnych
Michael Le Barbier Grünewald
-2

W odpowiedzi na:

Cóż, szczerze chciałbym wiedzieć, dlaczego prawie każdy język ma tylko jeden typ danych do tego.

Najczęstszym powodem może być „ponieważ nie jest to konieczne”. Jeśli chcesz, aby data i godzina nie obchodziły godzin, minut, sekund itp., Po prostu zainicjuj ją w następujący sposób:

date = new DateTime(year, month, day, 0, 0, 0);

Jeśli chcesz, możesz sam przedłużyć DateTime:

public class Date extends DateTime {
    ...
    public Date(int year, int month, int day) {
        this(year, month, day, 0, 0, 0);
    }
}

Uwaga: celowo ignoruję domyślny czas i strefę czasową. Tak naprawdę nie ma znaczenia, co je ustawisz, o ile są takie same dla wszystkichDate s. Możesz złożyć skargę na UTC. Możesz uzasadnić wykorzystanie strefy czasowej, w której znajduje się serwer - w każdym razie nie uważam, że jest to ważne dla reprezentowania nieprecyzyjnej wartości, takiej jak Date. To samo z czasem domyślnym - możesz ustawić 0, możesz ustawić południe. To nie ma znaczenia Jeśli Facebook wyśle ​​mi powiadomienie urodzinowe o 00:01, ale urodziłem się o 23:59, nie obchodzi mnie to i nie obrażę się, że mieli więcej niż 12 godzin wolnego.

Powyższe dotyczy języka Java, ale działałoby podobnie w każdym języku z DateTimedziedziczeniem. Java ma wiele sposobów rozwiązania tego problemu, a powyższe jest przestarzałe (chcą, abyś używał go Calendarteraz). Ale jak inni napisali w komentarzach, niektóre języki faktycznie zrobić zapewnićDate klasę, prawdopodobnie właśnie z tego powodu.

Najprawdopodobniej każda Dateimplementacja jest prawdopodobnie tylko opakowaniem dla języka DateTimei zeruje czas. W przeciwnym razie potrzebujesz zduplikowanego kodu, aby rozwiązać problemy, takie jak liczba dni między dwiema datami / datami lub czy dwa Dates są równe (co z 29 lutego i 1 marca?). Tego rodzaju rzeczy są zazwyczaj rozwiązywane na DateTimezajęciach. Sensowne jest ponowne użycie tego samego kodu dla Date.

Shaz
źródło
4
-1: Użyj LocalDate, jeśli chcesz tylko rok + miesiąc + dzień. Użycie DateTime w tym celu spowoduje błędy, gdy jakiś inny programista zobaczy DateTime i przyjmie, że reprezentuje on moment w czasie.
kevin cline
@kevincline Nie uważałem tego za konieczne, ponieważ to pytanie jest niezależne od języka. Sądzę również, że oczywiste jest, że użycie kodu oznaczonego jako „Przestarzałe” jest scenariuszem „na własne ryzyko”. Co ważniejsze, użyłem tego tylko jako przykładu czegoś, co możesz zrobić w scenariuszu, w którym język nie ma klasy LocalDatelub Datetypu, a ty musisz „rzucić własny”.
Shaz
1
Ale „jest to konieczne” dla jasnego zwięzłego i poprawnego kodu obejmującego reguły biznesowe dotyczące czasu (w przeciwieństwie do czasu fizycznego). jeśli biblioteka nie podaje typów dla czasu nominalnego, programiści będą musieli je wymyślić, a sposób na zrobienie tego nie zaczyna się od „DateTime”.
kevin cline
@kevincline Nie rozumiem, w jaki sposób kod byłby mniej przejrzysty lub zwięzły. Jaka jest różnica z punktu widzenia programisty pomiędzy new Date(2000, 1, 1);i new Date(2000, 1, 1);? Czy możesz powiedzieć, który z nich ma puste godziny, minuty i sekundy pod spodem? Jeśli martwisz się wyświetlaniem dodatkowych funkcji (takich jak setMinutes ()), możesz pójść drogą Datezawijania DateTimezamiast dziedziczenia po nim, a następnie ujawniasz tylko setYear, setMonth, setDay itp. I na pewno nie mniej poprawna niż data i godzina w bibliotece, której używasz.
Shaz
Moje tło to głównie C #, który nie ma konstrukcji analogicznej do LocalDate. Najwyraźniej po prostu DateTime.
Michael Blackburn,