Почему бы не вернуть даты в виде строки из базы данных?

41

В типичном веб-приложении даты извлекаются из слоя базы данных, строго типизированного (например, в c # как System.DateTime в противоположность System.String).

Когда дату необходимо выразить в виде строки (например, отображаемой на странице), преобразование из DateTime в строку выполняется на уровне представления.

Почему это? Почему плохо конвертировать DateTime в строку на уровне базы данных?

Смотрите также горячие дебаты в чате и оригинальный вопрос, с которого все началось .

Джон Ву
источник
73
Позвольте мне спросить вас: вы бы просто конвертировали каждый тип в строку? Что отличает дату от других?
садовод
7
Хороший вопрос! Пожалуйста, смотрите горячие дебаты в процессе, здесь .
Джон Ву
8
Ну, кажется довольно очевидным, что другой парень не прав, а все остальные правы. Не совсем вопрос здесь
садовник
7
Иногда вам нужно сделать математику даты вне базы данных. Значительно сложнее, если у тебя есть только струны.
Эрик Кинг,
14
Другая проблема - то , что вид строки вам нужно? Существует множество способов представления даты и времени в виде строки. Что если бы у меня была база данных, которая только возвращала текущее время, представленное в виде # секунд с начала эпохи, в виде строки (например, текущее время - «1474496980»). Это было бы полезно? Хотели бы вы использовать такую ​​базу данных?
прогулка

Ответы:

168

Даты, DateTimes и действительно любой другой типизированный объект, как правило, следует оставлять в их правильно типизированном формате до того момента, пока они не понадобятся для преобразования в какой-либо другой тип, особенно когда этот тип является удобочитаемой для человека формой, особенно когда это с потерями / односторонний вид конверсии.

Зачем? Поскольку предполагается, что тип предоставляет вам множество удобных встроенных функций, таких как правильное тестирование на равенство, сложение и вычитание, сравнение (больше чем, меньше чем), функциональность часового пояса и локали (особенно важно для всего, что связано со временем), и т.д. Если вы решили, что хотите поддержать американцев и формат «День месяца [й], год», а также общий британский стиль «День месяц год» или стандарт ISO «Год-месяц-день»? Что бы вы сделали, если бы это была строка, и вам нужно было внести это изменение, разобрать его обратно в Date? Тьфу, нет, спасибо - там много зла и подлых ошибок, которые лучше всего избегать.

В частности, вы упомянули многоуровневую архитектуру, в которой уровень представления данных отделен от данных позже. На самом деле это еще одна серьезная причина для передачи даты как даты, а не строки - потому что в какой тип форматирования строки следует указывать дату? Английский, китайский, с или без секунд / миллисекунд, полное название месяца или цифры, вы хотите отсортировать поле даты позже (сортировка по строке требует определенного формата строки, если вы хотите, чтобы она работала правильно) и т. Д.? Все это вопрос представления - как пользователь должен просматривать данные - и размещение этой логики в другом месте ограничит преимущество наличия многоуровневой архитектуры. База данных не должна знать или заботиться о том, как вы хотите просматривать дату в будущем.

Наконец, почти все сложные приложения (для которых нужны многоуровневые архитектуры), которые заботятся о времени, неизбежно будут использовать время / даты многими, многими различными способами и часто на всех различных уровнях архитектуры. Типизированные объекты, связанные со временем и датой, существуют по очень веской причине: само время, особенно системы календаря человека, странные и сложные. В конечном счете, времена и даты не являются строками по той же причине, что целые числа и числа с плавающей запятой не являются строками, и это только усложнит вашу жизнь, если вы попытаетесь притвориться, что они на самом деле являются просто массивами символов, потому что они просто не являются.

BrianH
источник
26
+1 только за использование подлого слова. Я согласен с вашими убедительными аргументами и исчерпывающими объяснениями, но именно поэтому мне пришлось войти и проголосовать за вас.
Адриан Ларсон
1
Представление даты и времени в секундах с определенного времени в прошлом также является надежным среди различных календарей. Например, в исламском и китайском календарях не используются гриогрианские месяцы, номера года и т. Д. Я бы посчитал это плохой практикой на уровне базы данных.
Rexkogitans
Даты часто представлены как «X дней назад». Удачи в анализе этого значения.
Agent_L
5
Давайте также не будем забывать проблемы изменения DST (и другие подобные). Будет ли «6 ноября 2016 г. 1:30:26 AM» впервые или во второй раз, когда произойдет эта дата и время? UTC DateTime по крайней мере уникален, и вы всегда можете перевести его в локальное представление для этого времени - обратный путь не всегда возможен.
J ...
3
Why? Because it is assumed that the type provides you with lots of handy built in functionalityНа мой взгляд, это просто вторично. Настоящая причина в том, что тип говорит вам, что что-то есть . Дата не является строкой, она просто легко переводится в удобочитаемую строку.
Довал
53

Он говорит использовать веб-сервер для преобразования времени данных в строку. Я говорю сделать это на сервере базы данных, а не на веб-сервере. Почему вы думаете, что это лучше? - MT Head

Я хочу знать тип.

Мне действительно все равно, хранит ли ваша база данных информацию в виде строки, нескольких целых или байтов, потому что, в конце концов, это всегда байты. Эта строка занимает больше места, чем нужно в вашей базе данных, меня не беспокоит. То, что беспокоит меня, сталкивается с датами как это:

11/10/2016

И не зная, одиннадцатый или десятый месяц.

Но это подтверждается, вы говорите. Конечно, вы прошли через процессы проверки. Дата совершенно правильная. Но здесь я поддерживаю эту вещь, и все, что я знаю, это дата - это строка. Я даже не могу сказать вам, что это за дата.

«Десятый день ноября в две тысячи шестнадцатый год нашего господина».

Это строка. Одна из наших презентаций нуждается в этом в этом формате. Вы сказали, что база данных конвертирует все даты в строки, верно? Веселитесь с этим.

Задача базы данных - хранить данные, а не представлять данные. Конечно, вы можете делать это в строках, но тогда вам нужно разобрать его, чтобы сделать его полезным для представления в других форматах. Хранение в стандартной разобранной форме для любого типа, который предлагает БД, позволяет нам быть как можно ближе к готовности представить без принятия решения о представлении. Для меня действительно не имеет значения, поддерживает ли БД этот тип строкой, целыми числами или байтами. Пока он знает, что делает.

Но когда вы не даете БД знать, что мы имеем дело с датой, и сохраняете дату в виде строки, вы преждевременно представляете ее и предпочитаете одну презентацию всем остальным. Это заставляет всех других докладчиков анализировать перед конвертацией. Нет, база данных не является частью уровня представления. Не проси об этом.

Аналогично, уровень представления не является частью базы данных, поэтому не стоит связывать отчет с деталями базы данных. Гораздо надежнее действовать на типы.

candied_orange
источник
Этот ответ обращается к хранилищу в виде строк. Однако он не обращается к общему шаблону хранения дат в собственном типе даты, а затем форматирует его в строку в запросе SQL , используя такие функции, как CONVERT (T-SQL), а также то, что СУБД обычно сериализует свои даты в строку в настраиваемом формате независимо от запроса. Например: postgresql.org/docs/9.5/static/…
dcorking
Это отчет. Это происходит после хранения. Как преобразование моей даты рождения в мой возраст.
candied_orange
2
Я просто хотел призвать вас расширить свой ответ, так как тема ОП - как «даты извлекаются из уровня базы данных». Существует устоявшаяся, хотя и, возможно, устаревшая модель, в которой отчет запрашивает в базе данных форматированные и локализованные строки дат. Я думаю, что ФП хотел бы услышать эти аргументы об осуждении. Я знаю, что буду.
dcorking
@dcorking note update.
Candied_Orange
+1 добавление воды на мельницу: просто создайте систему на установленной базе, которая охватывает несколько часовых поясов, где абсолютный момент имеет первостепенное значение, и посмотрите, насколько хорошо вы справляетесь со строковыми <-> преобразованиями меток времени везде. В худшем случае сделайте так, чтобы люди создавали свои собственные плагины и давали им временные метки, поскольку строки видят, насколько последовательными будут эти временные метки!
Ньютопия
19

место действия

Преобразование даты в строку для целей представления требует знания пользовательских предпочтений, поскольку одна и та же дата обычно должна отображаться по-разному для пользователей в разных локалях. Даже если вы используете одну локаль в вашем приложении, правильное поведение должно использовать локаль приложения вместо сервера базы данных; и они не гарантируются идентичными, даже если в этот момент они совпадают по совпадению.

Преобразование из универсального типа данных даты в строку, зависящую от локали, должно происходить на уровне представления, поскольку именно этот уровень знает, как должно выполняться это преобразование.

Петерис
источник
3
В качестве реального примера несоответствия региональных настроек представьте себе приложение для штата Мэн, пользователей из США, а затем оно будет размещено в ферме серверов Amazon на западном побережье. ;) Это не так уж невероятно, на самом деле.
jpmc26
@ jpmc26 Я не понимаю разницы - использует ли Мэн другой формат даты для остальной части США?
Пит Киркхем
2
@PeteKirkham Мэн и западное побережье США используют часовые пояса с интервалом в 3 часа.
jpmc26
1
Или другой реальный сценарий: представьте себе, что в Швейцарии запущен сервер, который должен обслуживать клиентов на четырех (немецком, французском, итальянском, английском) разных языках с разными локалями (и немного другими правилами форматирования). Удачи в выборе правильной локали для вашего сервера в такой ситуации.
Во
1
@ jpmc26 часовые пояса и локали - это не одно и то же. Например, у нас есть офисы в Глазго, Шотландия, Атланта, США и Пуна, Индия. Консультанты в этих офисах, в свою очередь, круглосуточно контролируют сайты (кампусы, больницы, отели и т. Д.) По всему миру. База данных приложения работает в формате UTC, но отображает время по местному времени для отслеживаемого сайта. Даты консультантов в США локализованы на MM / DD / YYYY, а в Великобритании и Индии - DD / MM / YYYY - это зависит от локали, а не от часового пояса сайта или пользователя.
Пит Киркхем
9

Это нежелательно по той же причине, по которой вы не захотите просто слепо преобразовывать любой тип в строку, как только она достигнет уровня приложения. Существует высокая вероятность того, что вы захотите каким-то образом использовать этот объект, прежде чем представлять его пользователю (если вы даже представляете его пользователю). Для этого конкретного примера представьте, что вам нужно сделать некоторую математическую дату на объекте. Нет недостатка в том, чтобы просто преобразовать объект в строку перед тем, как вы ее отобразите.

gardenhead
источник
4

Типы существуют по определенной причине: если бы они не добавляли никакой выгоды, мы бы их не имели и не использовали бы, а у нас был бы просто «тип», и все было бы так. Они не только удобны, они также добавляют безопасность и эффективность. Ниже приведен список причин, по которым вы всегда должны сохранять типы в их собственном формате, а не в виде строк . DateTimeБольшую часть времени я использовал в качестве примера, но те же принципы применимы к любому примитивному типу, такому как целые, десятичные, двоичные и т. Д.


Хранилище данных

Ограничения

Тип Ограничение

Почти все хранилища данных позволяют указывать ограничения на данные, в том числе ограничения типов. Одним из основных преимуществ указания DateTimeэкземпляра является то, что хранимые данные будут ограничены этим типом. Никогда нельзя будет вводить что-либо, кроме даты и времени, независимо от того, как данные были вставлены в хранилище. Последнее важно для больших систем, где есть несколько процессов, которые напрямую взаимодействуют с магазином. Сюда также входит попытка добавить ошибочные даты, например, 30 февраля (любого года), поскольку в феврале может быть только 29 дней в високосном году и 28 дней в течение не високосных.

Ограничения валидации

Существуют также ограничения проверки, которые могут быть реализованы в хранилище данных, например, обеспечение того, чтобы вставленная дата не превышала текущую дату или чтобы дата начала наступала раньше даты окончания.

операции

Большинство хранилищ данных также имеют встроенные операции / функции, такие как DateAddили DatePartв MS Sql Server. Это позволяет начать фильтрацию или выбор определенных данных, пока они еще находятся в хранилище (еще не загружены в приложение).

Универсально принятый формат

При использовании нативного типа другие разработчики или системы, которые также взаимодействуют с хранилищем, не должны быть проинформированы о мельчайших деталях того, как хранится этот примитивный тип. Это не тот случай, если этот тип был сохранен как строка, тогда вы должны убедиться, что все понимают формат этого DateTimeпредставления строки. Эта система становится хрупкой при работе с данными, которые охватывают локали, регионы и культуры в источнике данных, физическое местоположение приложения и атрибуты конечного пользователя / системы, взаимодействующей с этими данными. Пример: формат даты в одной стране может быть ММ / дд / гггг (как в США), но в другой это может быть дд / мм / гггг, обнаружение такой разницы становится практически невозможным.

скорость

Скорость поиска, скорость проверки, скорость операций и эффективность хранения также являются важными факторами. Пример скорости извлечения: хранилища данных позволяют использовать индексы для столбцов, и эти индексы, как правило, могут использоваться более эффективно, если тип хранится в его собственном формате.

заявка

Доступ к данным

Выполнение запросов к хранилищу упрощается при использовании системы собственных типов, поскольку разработчикам, опять же, не нужно угадывать формат хранения. Почти все поставщики приложений хранилища данных ( пример: ado.net ) предоставляют механизмы для создания правильных параметризованных запросов на основе переданных собственных типов. Вот пример добавления части Date в запрос ado.net для хранилища Sql Server. делать то же самое со строками было бы очень громоздким и хрупким / подверженным ошибкам.

command.Parameters.Add(new SqlParameter("@startDate", SqlDbType.Date) {Value = myDateInstance.Date});

операции

Собственные типы в коде также обеспечивают стандартные операции, такие как тип .net System.Date. Операции обычно имеют математическую природу, такие как добавление дат, поиск различий между датами и т. Д. Опять же, это невозможно сделать для строковых типов.

Уровень представления

место действия

Когда примитивный тип окончательно преобразуется в строку на уровне представления ( правильное расположение в программном стеке, чтобы сделать это ), у программиста теперь есть различные опции, чтобы правильно отобразить его в соответствии с контекстом, в котором он представлен. Этот контекст обычно состоит из фактического значения данных и языкового стандарта пользователя.

Пример 1

Экземпляр datetime может быть автоматически отформатирован в зависимости от локали пользователя.

DateTime.Now.ToString("D", CultureInfo.GetCultureInfo(userContext.Culture))
Пример 2

Десятичный экземпляр может представлять сумму (валюту), и языковой стандарт пользователя должен также отображать сумму в соответствии с их предпочтениями. Приложение C # может затем отобразить значение с помощью

amount.ToString("C", CultureInfo.GetCultureInfo(userContext.Culture))

Это может иметь решающее значение, так как разные культуры показывают цифры по-разному. В США период (.) И запятая (,) имеют точное обратное значение, как в Нидерландах.

Место расположения

Это очень характерно для DateTimeслучаев. Дата и время представляют происшествие в определенный момент времени, но обычно это должно быть передано / представлено пользователю в зависимости от его собственного часового пояса. Пример: DateTimeэкземпляр 2016-09-21T23:38:21.399Zможет отображаться как 9/21/2016 5:21 PMдля пользователя в восточном часовом поясе в США. Есть много способов сделать это, но это становится практически невозможным, если экземпляр даты и времени хранится в памяти как строковый тип или в хранилище данных как строковый тип.


Главное правило

Общие 2 правила для приложения следуют, когда дело доходит до преобразования любого примитивного типа в строковое представление, как они

  • Принимая входные данные, преобразуйте эти входные данные в правильный тип примитива как можно раньше в программном стеке (обычно на уровне представления)
  • При извлечении данных для отображения преобразуйте эти данные в строковое представление как можно позже в программном стеке (опять же, обычно на уровне представления)
Игорь
источник
0

В этом нет ничего плохого (это делается все время в службах), если вы используете не двусмысленный формат для вашей даты. Под однозначным пониманием я подразумеваю не только четкую дату (например, ММ / ДД и ДД / ММ), но и временную зону, в которой она находится. Поэтому заранее, если вы собираетесь представлять свои даты в виде текста, используйте формат ISO , Я настоятельно предпочитаю строки времени по UTC.

Плюсы:

  • Стандартные дата / время Строки переносимы и просты для понимания
  • Часто даты в БД содержат компонент времени. Если это не имеет смысла для ваших данных, это может упростить вещи.

Минусы:

  • Размер данных. Внутренний формат даты в БД обычно занимает гораздо меньше места, чем строковое отображение этой даты.
  • Как правило, вы захотите включить его в реальную структуру даты или времени на клиенте, так что может быть дополнительное время при разборе.

Если бы кто-то сказал, что хочет это сделать, я бы спросил "почему?" потому что в этом нет особого смысла. Если причина, по которой кто-то хочет вернуть дату в виде строки, заключается в том, что он просто отображает ее напрямую, это не является хорошей причиной для использования строк из базы данных.

JimmyJames
источник