Благодарение на разнообразието от култури на Земята, ние имаме различни формати за дати. За числови дати имаме месец-ден-година, ден-месец-година и година-месец-ден. Имаме и кратки и дълги формати. Датите могат да се смесват с времето, което е друга история. Тази реалност ни следва в работата. Ето защо форматът на датата в SQL не е нещо, което можем да приемем лесно.
Във Филипините използваме 2 формата:месец-ден-година и ден-месец-година. Месец-ден-година е общият формат за числови дати. Но с по-дълги формати за дата ние използваме взаимозаменяемо ден-месец-година и месец-ден-година.
На работа никога не съм срещал настройка за формат на дата на SQL Server, различна от месец-ден-година. Въпреки това, той варира в отчетите и файловете за обмен на данни и проекта Extract-Transform-Load (ETL). Да не говорим за потребители, които го променят в своите станции за лични предпочитания! При всички тези сценарии неправилното справяне с тях е рецепта за нарушаване.
Вашите приложения се занимават с различни култури? Това е друго ниво на сложност и проблем при работа с тези различни SQL формати за дата. В тази статия ще разгледаме стандарта за справяне с всички тези разновидности и примери. Прочетете до края! Но преди да продължим, нека направим кратка обиколка за това как SQL Server съхранява датите.
Как SQL Server съхранява датите
Познай. SQL Server съхранява ли 29.03.2021 21:35, както е в базата данни? Какво ще кажете за 29.03.2021 г.? Съхраняват ли се като форматирани низове? Въз основа на тази документация от Microsoft не е така.
Да вземем например типа данни DATE. Съхранява се като 3-байтово цяло число.
Откъде знаем?
Е, Microsoft казва, че е така, но не предоставя повече информация. Това не означава, че не можем да го знаем със сигурност. Първо, минималната стойност на типа данни DATE е 01/01/0001 или 1 януари, 1 CE или Common Era. За да преобразуваме това в цяло число, първо преобразуваме тази дата във VARBINARY, както следва:
SELECT CAST(CAST('01/01/0001' AS DATE) AS VARBINARY(3))
Резултатът е 0x000000 в шестнадесетичен формат. От тази стойност можем да видим, че целочислената стойност на 1 януари, 1 CE е 0. Това е логично, защото това е минималната стойност DATE.
Сега напредваме с 1 ден.
SELECT CAST(CAST('01/02/0001' AS DATE) AS VARBINARY(3)) -- January 2, 1 CE
Резултатът е 0x010000 . Това е малко сложно, но тази публикация ни даде идея. Не можем да го третираме така, както го виждаме. Байтовете са обърнати и действителната шестнадесетична стойност е 0x000001 . Ако знаете малко за шестнадесетичните числа, знаете, че това е равно на 1 – това е 1 ден от началната точка, 1 януари, 1 CE.
Сега, нека опитаме скорошна дата:29.03.2021.
SELECT CAST(CAST('03/29/2021' AS DATE) AS VARBINARY(3))
Резултатът е 0x55420B . Когато го обърнем, той става 0x0B4255 . Този път не можем да разберем стойността, като го погледнем. И така, ние го умножаваме по 1 като цяло число.
SELECT 0x0B4255 * CAST(1 AS INT)
Резултатът е737 877 . Това е броят на дните от 1 януари, 1 н.е. Нека го потвърдим с DATEDIFF.
SELECT DATEDIFF(DAY,CAST('01/01/0001' AS DATE),CAST('03/29/2021' AS DATE))
Резултатът е същият:737 877 дни. Много готино!
В крайна сметка:Форматираната дата е само за целите на презентацията
Ето как SQL Server съхранява типовете данни DATE. Различно е за DATETIME, SMALLDATETIME и DATETIME2, но все пак се съхранява като цели числа. SQL Server изчислява продължителността на времето от началната точка и показва датата, която всички можем да разберем.
Независимо дали го разглеждате в SQL Server Management Studio, dbForge Studio за SQL Server или вашето приложение, 29.03.2021 г. е само презентация. Ако промените региона или езика, съхранената стойност 0x55420B ще остане същото.
Сега знаем, че датите не се съхраняват като низове. Можем да забравим за съхраняването на дати в определен формат . Така или иначе не работи. Вместо това, нека разгледаме различни начини в SQL за форматиране на датите, от които се нуждаете вашите приложения.
4 лесни начина за форматиране на дати
Нека разгледаме следните SQL функции за дата:
- Функция CONVERT
- ЗАДАДЕТЕ ЕЗИК
- ЗАДАДЕТЕ ФОРМАТ НА ДАТА
- Функция FORMAT
Можете също да използвате инструмент за форматиране на SQL заявки.
1. Функция CONVERT
CONVERT е една от функциите за преобразуване на данни, която може да служи и за форматиране на дата. Фигура 1 показва пример.
Първите два аргумента на CONVERT са целевият тип данни и стойността на датата. Третият е по избор, но важи и за датите. Числовите стойности са стиловете за формат на дата в SQL, които се използват по време на преобразуването от дата в низ.
На фигура 1 Япония използва формат година-месец-ден с наклонена черта като разделител. Германия използва ден-месец-година с точки като разделители. Великобритания и Франция използват същата последователност като Германия, но с наклонена черта като разделител. Само Съединените щати използват месец-ден-година с тире като разделител.
В SQL можете също да конвертирате израза DATETIME в DATE.
За пълен списък на CONVERT стилове за формат на дата в SQL, проверете тази справка от Microsoft.
2. ЗАДАЙТЕ ЕЗИК
Тази настройка определя езика, приложен към сесията. Това засяга форматите на датите и системните съобщения. Когато зададете език, вие също имплицитно прилагате настройките SET DATEFORMAT (ще го разберем по-късно).
Засега нека проверим примерите на фигура 2. Променям езиковите настройки на литовски и след това обратно на английски.
Вижте фигура 2. Литовският формат за дата е година-месец-ден. Винаги, когато опитвам различни дати, дългата дата винаги включва „m.“ преди месеца и „d.“ след деня. Първата буква на месеца и името на делничния ден също не се изписват с главни букви. За други езикови настройки е различно, но разбирате смисъла.
За повече информация относно SET LANGUAGE, вижте тази справка от Microsoft.
3. ЗАДАЙТЕ ФОРМАТ НА ДАТА
Тази настройка поставя реда на месеца, деня и годината за интерпретиране на низове от знаци за дата. Той ще отмени неявните настройки за формат на датата, направени от SET LANGUAGE. Ето пример на фигура 3.
На фигура 3 кодът използва DMY или формат ден-месец-година. При тези настройки всяка стойност на датата, зададена на променлива за дата, трябва да следва този модел. 30/03/2021 съответства на този формат, но 31/03/2021 задейства грешка, тъй като 31 не е валиден месец.
По този начин промените във формата на датата може да счупят приложението ви, ако логиката работи на базата на друг формат.
За повече информация относно SET DATEFORMAT вижте тази справка от Microsoft.
4. Функция FORMAT
От всички налични опции за форматиране, тази е най-гъвкавата. Подобно е и за форматирането на дата в .Net, тъй като FORMAT разчита на наличието на .Net Framework на сървъра, където е инсталиран SQL Server. Това обаче е недостатъкът на тази опция.
Точно както се прави в C#, FORMAT приема стойност за дата и форматен низ. Нека имаме няколко примера на фигура 4.
Подобно на .Net, в SQL Server можете да форматирате дати с помощта на различни разделители. Освен това можете да позиционирате месеца, деня и годината навсякъде. След това можете да получите културната информация и да използвате нейния формат за дата.
За повече информация и примери относно FORMAT вижте тази справка от Microsoft.
Сега идентифицирахме 4 начина за форматиране на дати и разнообразието от формати на дати. Има ли стандартен формат, който винаги работи при преобразуване на низове в дати?
ISO 8601 – Най-преносимият SQL формат за дата без грешки, който можете да използвате за преобразуване
ISO 8601 съществува от 1988 г. Това е международният стандарт за обмен на данни, свързани с дати и часове .
Предлага се и във функцията CONVERT като един от стиловете за формат на дата:стилове 126 и 127 са съвместими с ISO 8601.
Какво го прави преносим и без грешки?
Проблемът с формати, различни от ISO 8601
Нека демонстрираме проблема за не-ISO 8601 с пример:
DECLARE @d VARCHAR(10) = '03/09/2021';
SET LANGUAGE Italian;
SELECT FORMAT(CONVERT(DATETIME, @d),'D')
SET LANGUAGE English
SELECT FORMAT(CONVERT(DATETIME, @d),'D')
SET DATEFORMAT DMY
SELECT FORMAT(CONVERT(DATETIME, @d),'D')
SET DATEFORMAT MDY
SELECT FORMAT(CONVERT(DATETIME, @d),'D')
В зависимост от локала на вашата дата, можете да интерпретирате @d като 9 март 2021 г. или 3 септември 2021 г. Не можете да сте сигурни кое е кое. Ето къде е проблемът.
Проверете резултата на фигура 5 по-долу:
Дори SQL Server не го знае със сигурност!
Най-лошото е, че този вид сценарий може да счупи приложението ви, точно както се случи на фигура 3 по-рано. Тази ситуация е проблематична за приложения, работещи с мултикултурни потребители.
Може ли ISO 8601 да помогне с това?
Използване на ISO 8601 за справяне с проблеми с форматирането
Забележете, когато ISO 8601 формат ггггММдд се използва вместо MM/dd/yyyy и проверете резултата на фигура 6:
Винаги ще бъде 9 март, независимо кой език и настройки за формат на датата се използват. Това е чудесно за обмен на данни и системни интеграции. Ако вашият потребител има друг формат за дата в станцията, това също няма да има значение.
Ако трябва да трансформирате датите си в низове и обратно, използвайте ISO 8601.
ISO 8601 в SQL Server се предлага в 2 варианта:
- ГГГГММДД е само за дати.
- ГГГГ-ММ-ДДТЧ:ММ:СС за комбинация от дата и час, където T е разделителят между дата и час.
Други начини за обработка на формати за дата от приложения към SQL Server
1. Използвайте контроли с дата в приложението
Когато помолите потребител да въведе дати във формуляр, не му позволявайте да използва свободен текст. Използвайте контроли за дата, които позволяват избор само от валидни стойности.
2. Преобразувайте в различен формат само когато е необходимо
Не продължавайте да трансформирате датите в низове и обратно. Използвайте родните типове данни за дата или дата и час на приложението за повикване. Ако трябва да ги трансформирате по някаква причина, използвайте ISO 8601.
3. Задайте дата/час, часова зона и култура в стартирането на вашето приложение, ако е приложимо
Ако приложението ви използва фиксиран формат за дата и вашите потребители обичат да променят форматите за дата, можете да коригирате и двете при стартиране на приложението. Изрично задайте от какво се нуждае вашето приложение. Ще бъде много по-добре, ако вашият мрежов администратор може да заключи тези настройки.
Вземане за вкъщи
И така, обработката на различни формати на SQL дата е непосилна? Не мога да ви виня, ако все още го намирате така, но ние разбрахме, че не е невъзможно.
Ето какво разгледахме:
- SQL датите се съхраняват като цели числа . Това, което виждаме с очите си, вече е форматирано въз основа на настройките на SQL Server. Без значение колко пъти сменяме езика и форматите на датата, съхранената стойност ще остане същата. Безполезно е да мислите за съхраняване на дати в конкретен формат.
- Има 4 начина за форматиране на дати:КОНВЕРТИРАНЕ , ЗАДАДЕТЕ ЕЗИК , ЗАДАДЕТЕ ФОРМАТ НА ДАТА и ФОРМАТ .
- Ако трябва да трансформирате дати в низове и обратно, използвайте формат ISO 8601 .
- Има 3 други начина за справяне с форматите на датите:
- използване на контроли за дата във вашето приложение;
- преобразуване на дати в низове само когато е необходимо;
- задаване на необходимата часова зона, култура, дата/час на сървъра при стартиране, когато е приложимо .
Смятате ли, че това ще бъде полезно за вас и за другите? След това, моля, споделете тази статия в любимите си социални медийни платформи.