W typowej aplikacji internetowej daty są pobierane z warstwy bazy danych silnie wpisanej (np. W c # jako System.DateTime w przeciwieństwie do System.String).
Gdy data musi być wyrażona jako ciąg (np. Wyświetlany na stronie), konwersja z DateTime na ciąg odbywa się w warstwie prezentacji.
Dlaczego to? Dlaczego konwersja DateTime na ciąg znaków w warstwie bazy danych jest złą rzeczą?
Zobacz także gorącą debatę na czacie i oryginalne pytanie, które to wszystko rozpoczęło .
database
sql
formatting
John Wu
źródło
źródło
Odpowiedzi:
Daty, DateTimes i naprawdę każdy inny wpisany obiekt powinien być generalnie pozostawiony w swoim poprawnie wpisanym formacie do momentu, kiedy będzie trzeba go przekształcić w inny typ - szczególnie, gdy ten typ jest czytelny dla człowieka, a zwłaszcza gdy jest stratny / konwersja jednokierunkowa.
Dlaczego? Ponieważ zakłada się, że ten typ zapewnia wiele przydatnych wbudowanych funkcji, takich jak prawidłowe testowanie równości, dodawanie i odejmowanie, porównywanie (większe niż, mniejsze niż), strefa czasowa i funkcjonalność ustawień regionalnych (szczególnie ważne dla wszystkiego, co dotyczy czasu), itd. Jeśli zdecydujesz, że chcesz wspierać Amerykanów i format „Dzień miesiąca [th], rok”, a także wspólny brytyjski styl „Dzień Miesiąc Rok” lub standard ISO „Rok-miesiąc-dzień”? Co byś zrobił, gdyby był to ciąg znaków i trzeba wprowadzić tę zmianę, przekształcić go z powrotem w datę? Nie, dziękuję - w ten sposób jest wiele złych i nikczemnych błędów, których najlepiej całkowicie uniknąć.
Mówiąc dokładniej, wspomniałeś o architekturze warstwowej, która później ma warstwę prezentacji oddzielną od danych. Jest to w rzeczywistości kolejny duży powód, aby data podawać jako datę, a nie ciąg - ponieważ w jakim typie formatowania ciągu należy wprowadzić datę? Angielski, chiński, z sekundami / milisekundami lub bez, pełna nazwa miesiąca lub cyfry, czy chcesz później posortować według pola daty (sortowanie według ciągu wymaga określonego formatu ciągu, jeśli chcesz, aby działało poprawnie) itp.? To wszystko kwestia prezentacji - w jaki sposób użytkownik powinien przeglądać dane - a umieszczenie tej logiki gdziekolwiek indziej ograniczyłoby przewagę posiadania architektury warstwowej. Baza danych nie powinna wiedzieć ani dbać o to, jak chcesz zobaczyć datę w przyszłości.
Wreszcie, prawie wszystkie złożone aplikacje (po to są wielopoziomowe architektury), które dbają o czas, nieuchronnie wykorzystują czasy / daty na wiele, wiele różnych sposobów, a często na wszystkich poziomach architektury. Wpisane obiekty związane z czasami i datami istnieją z naprawdę dobrego powodu: sam czas, a zwłaszcza ludzkie systemy kalendarza, są dziwne i trudne. Ostatecznie czasy i daty nie są łańcuchami z tego samego powodu, że liczby całkowite i zmiennoprzecinkowe nie są łańcuchami, a utrudni ci życie tylko wtedy, gdy spróbujesz udawać, że są to po prostu tablice postaci, ponieważ po prostu nie są.
źródło
Why? Because it is assumed that the type provides you with lots of handy built in functionality
Moim zdaniem jest to tylko kwestia drugorzędna. Prawdziwym powodem jest to, że typ mówi ci, czymś jest . Data nie jest ciągiem, po prostu łatwo przekłada się na ciąg czytelny dla człowieka.Chcę znać typ.
Naprawdę nie dbam o to, czy twoja baza danych przechowuje informacje w postaci ciągu, niektórych liczb całkowitych lub bajtów, ponieważ na końcu i tak zawsze są bajty. Ten ciąg zajmujący więcej miejsca niż potrzeba w bazie danych nie przeszkadza mi. To, co mnie martwi, to takie randki:
11/10/2016
I nie wiedząc, czy to jedenasty, czy dziesiąty miesiąc.
Ale, jak mówisz, jest to potwierdzone. Pewnie poddasz go procesom sprawdzania poprawności. Data jest całkowicie poprawna. Ale tutaj utrzymuję tę rzecz i wszystko, co wiem, to data to ciąg znaków. Nie mogę nawet powiedzieć, jaka to data.
„Dziesiąty dzień listopada dwa tysiące szesnastego roku naszego pana”.
To jest struna. Jedna z naszych prezentacji potrzebuje go w tym formacie. Powiedziałeś, że baza danych konwertuje wszystkie daty na ciągi, prawda? Baw się dobrze z tym.
Zadaniem bazy danych jest przechowywanie danych nieobecnych danych. Jasne, możesz to zrobić w ciągach, ale musisz to przeanalizować, aby było przydatne do prezentacji w innych formatach. Przechowywanie go w standardowej parsowanej formie dla dowolnego typu oferowanego przez DB pozwala nam być tak blisko gotowości do prezentacji, jak to tylko możliwe, bez podjęcia decyzji o prezentacji. Naprawdę nie ma dla mnie znaczenia, czy DB popiera ten typ ciągiem znaków, liczbami całkowitymi lub bajtami. Tak długo, jak wie, co robi.
Ale kiedy nie poinformujesz DB, że mamy do czynienia z datą i przechowujemy datę jako ciąg znaków, przedwcześnie prezentujesz i preferujesz jedną prezentację nad wszystkimi innymi. To zmusza wszystkich innych prezenterów do parsowania przed konwersją. Nie, baza danych nie jest częścią warstwy prezentacji. Nie proś o to.
Podobnie warstwa prezentacji nie jest częścią bazy danych, więc nie jest rozsądne łączenie raportu ze szczegółami bazy danych. Znacznie bardziej niezawodne jest działanie na typach.
źródło
Widownia
Konwersja daty na ciąg znaków w celu prezentacji wymaga znajomości preferencji użytkownika, ponieważ dokładnie ta sama data powinna być wyświetlana inaczej dla użytkowników w różnych lokalizacjach. Nawet jeśli używasz jednego ustawienia narodowego w aplikacji, właściwe zachowanie powinno używać ustawień regionalnych aplikacji zamiast serwera bazy danych; i nie gwarantuje się, że będą identyczne, nawet jeśli w tym momencie przypadkowo się zgadzają.
Konwersja z uniwersalnego typu danych daty na ciąg znaków specyficznych dla ustawień regionalnych powinna mieć miejsce w warstwie prezentacji, ponieważ jest to warstwa, która wie, w jaki sposób należy wykonać tę konwersję.
źródło
Jest to niepożądane z tego samego powodu, dla którego nie chcesz po prostu ślepo konwertować dowolnego typu na ciąg, gdy tylko trafi on do warstwy aplikacji. Istnieje duże prawdopodobieństwo, że będziesz chciał użyć tego obiektu w jakiś sposób przed przedstawieniem go użytkownikowi (jeśli w ogóle go przedstawisz). W tym konkretnym przykładzie wyobraź sobie, że musisz wykonać matematykę daty na obiekcie. Konwersja obiektu na ciąg znaków dokładnie przed jego wyświetleniem nie ma żadnej wady.
źródło
Rodzaje istnieją z jakiegoś powodu, jeśli nie przyniosłyby żadnych korzyści, nie mielibyśmy ich i nie użylibyśmy ich, mielibyśmy po prostu „typ” i wszystko byłoby tak. Są nie tylko wygodne, ale także zwiększają bezpieczeństwo i wydajność. Poniżej znajduje się lista powodów, dla których należy zawsze utrzymywać typy w ich rodzimym formacie, a nie ciągi znaków . Użyłem
DateTime
jako przykładu przez większość czasu, ale te same zasady obowiązują dla każdego rodzaju pierwotnego, takiego jak liczby całkowite, dziesiętne, binarne itp.Magazyn danych
Ograniczenia
Wpisz Ograniczenie
Prawie wszystkie magazyny danych pozwalają określić ograniczenia danych, w tym ograniczenia typu. Jedną z głównych zalet określenia
DateTime
instancji jest to, że przechowywane dane będą ograniczone do tego typu. Nigdy nie będzie można wprowadzić niczego poza datą i godziną, niezależnie od tego, jak dane zostały wstawione do sklepu. Ta ostatnia jest ważna w przypadku większych systemów, w których istnieje wiele procesów, które współdziałają bezpośrednio ze sklepem. Obejmuje to również próbę dodania błędnych dat, takich jak 30 lutego (dowolnego roku), ponieważ luty może mieć tylko 29 dni w roku przestępnym i 28 dni w latach przestępnych.Ograniczenia walidacji
Istnieją również ograniczenia sprawdzania poprawności, które można wdrożyć w magazynie danych, takie jak zapewnienie, że wstawiona data nie przekracza bieżącej daty lub że data początkowa wystąpi przed datą końcową.
Operacje
Większość magazynów danych ma również wbudowane operacje / funkcje, takie jak
DateAdd
lubDatePart
w MS Sql Server. Umożliwia to rozpoczęcie filtrowania lub wybierania określonych danych, gdy dane są jeszcze w sklepie (jeszcze nie są pobierane do aplikacji).Format powszechnie akceptowany
Korzystając z rodzimego typu, inni programiści lub systemy, które również współpracują ze sklepem, nie muszą być informowani o najdrobniejszych szczegółach dotyczących sposobu przechowywania tego pierwotnego typu. Nie dzieje się tak, jeśli ten typ był przechowywany jako ciąg znaków, musisz upewnić się, że wszyscy rozumieją format tego
DateTime
ciągu znaków. System ten staje się niestabilny w przypadku danych obejmujących lokalizacje, regiony i kultury pochodzenia danych, fizyczną lokalizację aplikacji oraz atrybuty użytkownika końcowego / systemu, który wchodzi w interakcję z tymi danymi. Przykład: format daty w jednym kraju może być MM / dd / rrrr (jak w USA), ale w innym może być dd / MM / rrrr, wykrycie tej różnicy staje się prawie niemożliwe.Prędkość
Ważnymi czynnikami są również szybkość pobierania, szybkość sprawdzania poprawności, szybkość operacji i wydajność przechowywania. Przykład prędkości pobierania: magazyny danych pozwalają na indeksy na kolumnach, a indeksy te można ogólnie bardziej efektywnie wykorzystać, jeśli typ jest przechowywany w jego rodzimym formacie.
Podanie
Dostęp do danych
Wykonywanie zapytań w sklepie staje się prostsze przy użyciu natywnego systemu typów, ponieważ programiści po raz kolejny nie muszą zgadywać co do formatu pamięci. Prawie wszyscy dostawcy aplikacji do przechowywania danych ( przykład: ado.net ) zapewniają mechanizmy tworzenia odpowiednich sparametryzowanych zapytań na podstawie przekazywanych typów natywnych. Oto przykład dodania części Data do zapytania ado.net w odniesieniu do sklepu z serwerem Sql, robienie tego samego z łańcuchami byłoby bardzo uciążliwe i kruche / podatne na błędy.
Operacje
Rodzime typy w kodzie zapewniają również standardowe operacje, takie jak typ .net
System.Date
. Operacje mają zazwyczaj charakter matematyczny, takie jak dodawanie dat, znajdowanie różnicy między datami itp. Ponownie nie jest to łatwe do wykonania na typach łańcuchów.Warstwa prezentacji
Widownia
Kiedy typ pierwotny zostanie ostatecznie przekonwertowany na ciąg znaków w warstwie prezentacji ( poprawne położenie stosu programu, aby to zrobić ), programista ma teraz różne opcje poprawnego wyświetlania go zgodnie z kontekstem, w którym jest prezentowany. Ten kontekst ogólnie składa się z rzeczywistego znaczenia danych i ustawień regionalnych użytkownika.
Przykład 1Instancję daty i godziny można automatycznie sformatować na podstawie ustawień regionalnych użytkownika.
Przykład 2Wystąpienie dziesiętne może reprezentować kwotę (walutę), a ustawienia regionalne użytkownika powinny również wyświetlać kwotę zgodnie z ich preferencjami. Aplikacja c # może następnie wyświetlić wartość za pomocą
Może to mieć krytyczne znaczenie, ponieważ różne kultury wyświetlają liczby inaczej. W okresie amerykańskim (.) I przecinek (,) mają dokładnie odwrotne znaczenie jak w Holandii.
Lokalizacja
Jest to bardzo specyficzne dla
DateTime
instancji. Data i godzina reprezentują zdarzenie w określonym momencie, ale zwykle musi zostać przekazane / przedstawione użytkownikowi w zależności od jego własnej strefy czasowej. Przykład:DateTime
instancja2016-09-21T23:38:21.399Z
może być wyświetlana jak9/21/2016 5:21 PM
dla użytkownika we wschodniej strefie czasowej w USA. Istnieje wiele sposobów osiągnięcia tego celu, ale staje się to prawie niemożliwe, jeśli instancja daty i czasu jest przechowywana w pamięci jako typ łańcucha lub w magazynie danych jako typ łańcucha.Główna zasada
W przypadku konwersji dowolnego typu pierwotnego na reprezentację łańcuchową obowiązują 2 ogólne zasady aplikacji
źródło
Naprawdę nie ma w tym nic złego (robi się to cały czas w usługach), o ile używasz niejednoznacznego formatu daty. Przez jednoznaczność rozumiem nie tylko, że data jest jasna (np. MM / DD vs. DD / MM), ale także jaka jest strefa czasowa. Więc z góry, jeśli zamierzasz przedstawić swoje daty jako tekst, użyj formatu ISO . Zdecydowanie wolę ciągi czasowe oparte na UTC.
Plusy:
Cons:
Gdyby ktoś powiedział, że chce to zrobić, zapytałbym „dlaczego?” ponieważ tak naprawdę nie ma to wiele sensu. Jeśli powodem, dla którego ktoś chce zwrócić datę jako ciąg, jest to, że po prostu wyświetli ją bezpośrednio, nie jest to dobry powód, aby używać ciągów z bazy danych.
źródło