Por que não retornar datas como uma string do banco de dados?

41

Em um aplicativo Web típico, as datas são recuperadas da camada do banco de dados fortemente tipada (por exemplo, em c # como System.DateTime em vez de System.String).

Quando uma data precisa ser expressa como uma sequência (por exemplo, exibida em uma página), a conversão de DateTime em sequência é feita na camada de apresentação.

Por que é isso? Por que é ruim converter o DateTime em uma string na camada de banco de dados?

Veja também o debate acalorado no bate-papo e a pergunta original que começou tudo isso .

John Wu
fonte
73
Deixe-me perguntar: você converteria cada tipo em uma string? O que torna o Date diferente?
gardenhead
7
Boa pergunta! Por favor, veja o debate acalorado em andamento, aqui .
John Wu
8
Bem, parece bastante óbvio que o outro cara está errado e todo mundo está certo. Não é realmente uma questão aqui
gardenhead
7
Às vezes, você precisa fazer cálculos de datas fora do banco de dados. Consideravelmente mais difícil se tudo o que você tem são cordas.
Eric King
14
Outro problema - que tipo de corda você precisa? Existem muitas maneiras de representar um datetime como uma string. E se eu tivesse um banco de dados que retornasse apenas a hora atual, representada como número de segundos desde a época, como uma string (por exemplo, a hora atual é "1474496980"). Isso seria útil? Deseja usar um banco de dados como esse?
Riwalk

Respostas:

168

Datas, DateTimes e realmente qualquer outro objeto digitado geralmente devem ser deixados em seu formato digitado corretamente até o momento em que você precisar que eles sejam transformados em algum outro tipo - especialmente quando esse tipo for uma forma legível por humanos e, especialmente, quando houver perda / tipo de conversão unidirecional.

Por quê? Como se supõe que o tipo fornece muitas funcionalidades práticas úteis, como teste de igualdade adequado, adição e subtração, comparação (maior que, menor que), funcionalidade de fuso horário e local (especialmente importante para qualquer coisa relacionada ao tempo), etc. Se você decidir apoiar os americanos e o formato "Mês dia [º], ano", bem como o estilo britânico comum de "Dia mês ano" ou o padrão ISO de "Ano-mês-dia"? O que você faria se fosse uma string e precisasse fazer essa alteração, analisá-la novamente em uma Data? Ugh, não, obrigado - existem muitos males e erros covardes dessa maneira, que devem ser totalmente evitados.

Mais especificamente, você mencionou a arquitetura em camadas, que possui a camada de apresentação separada dos dados posteriormente. Este é realmente o outro grande motivo para passar uma Data como uma Data e não uma sequência - porque em que tipo de formatação de sequência a data deve ser inserida? Inglês, chinês, com ou sem segundos / milissegundos, nome completo do mês ou dígitos, você deseja classificar o campo de data posteriormente (a classificação de uma sequência exige um determinado formato de sequência, se você deseja que ela funcione corretamente), etc? Tudo isso é uma questão de apresentação - como o usuário deve visualizar os dados - e colocar essa lógica em qualquer outro lugar limitaria a vantagem de ter uma arquitetura hierárquica em primeiro lugar. O banco de dados não precisa saber ou se importar com como você deseja visualizar a data no futuro.

Finalmente, quase todas as aplicações complexas (que são para que servem as arquiteturas em camadas) que se preocupam com o tempo usarão inevitavelmente horários / datas de muitas e muitas maneiras diferentes, e geralmente em todos os níveis diferentes da arquitetura. Os objetos digitados relacionados a horários e datas existem por um motivo muito bom: o próprio tempo e, especialmente, os sistemas de calendário humano, são estranhos e difíceis. Por fim, horários e datas não são cadeias de caracteres pelo mesmo motivo que números inteiros e pontos flutuantes não são cadeias de caracteres, e isso só tornará sua vida mais difícil se você tentar fingir que são realmente apenas matrizes de caracteres, porque simplesmente não são.

BrianH
fonte
26
+1 apenas para usar a palavra covarde. Concordo com seus argumentos convincentes e explicações abrangentes, mas é por isso que tive que fazer login e votar em você.
Adrian Larson
1
Representar a data e hora em segundos desde um tempo definido no passado também é robusto entre diferentes calendários. Por exemplo, calendários islâmicos e chineses não usam nenhum mês, número do ano, etc. da Grécia, eu consideraria lidar com isso no nível do banco de dados como uma má prática.
rexkogitans
As datas são frequentemente apresentadas como "X dias atrás". Boa sorte analisando isso de volta ao valor original.
Agent_L 22/09/16
5
Também não devemos esquecer os problemas de alteração do horário de verão (e outros similares). Vai "6 de novembro de 2016 01:30:26" ser a primeira vez ou a segunda vez que essa data e hora terá acontecido? O UTC DateTime é pelo menos exclusivo e você sempre pode convertê-lo na representação local para esse tempo - voltar para o outro lado nem sempre é possível.
J ...
3
Why? Because it is assumed that the type provides you with lots of handy built in functionalityNa minha opinião, isso é apenas secundário. A verdadeira razão é que o tipo diz o que é algo . Uma data não é uma sequência, apenas se traduz facilmente em uma sequência legível por humanos.
Doval
53

Ele está dizendo para usar o servidor da web para converter o tempo dos dados em uma string. Estou dizendo fazê-lo no servidor de banco de dados e não no servidor web. Por que você acha que isso é melhor? - Cabeça MT

Eu quero saber o tipo.

Realmente não me importo se o seu banco de dados armazena informações em uma string, alguns ints ou bytes, porque, no final, sempre são bytes de qualquer maneira. Essa string ocupando mais espaço do que o necessário em seu banco de dados não me incomoda. O que me incomoda é encontrar datas como esta:

10/11/2016

E sem saber se é o décimo primeiro mês ou o décimo mês.

Mas é validado, você diz. Claro que você passa por um processo de validação. A data está perfeitamente correta. Mas aqui estou mantendo essa coisa e tudo que sei é que a data é uma sequência. Eu nem posso te dizer que data é essa.

"Décimo dia de novembro no ano de dois mil e dezesseis anos de nosso senhor."

Isso é uma corda. Uma de nossas apresentações precisa desse formato. Você disse que o banco de dados converte todas as datas em strings, certo? Divirta-se com isso.

O trabalho do banco de dados é armazenar dados que não estão presentes. Claro, você pode fazer isso em strings, mas depois precisa analisá-lo para torná-lo útil para apresentar em outros formatos. Armazená-lo em um formulário analisado padrão para qualquer tipo que o DB ofereça nos coloca o mais perto possível de apresentar o que podemos estar sem ter tomado uma decisão de apresentação. Realmente não importa para mim se o banco de dados faz o backup desse tipo com uma string ou ints ou bytes. Contanto que ele saiba o que está fazendo.

Mas quando você não avisa o banco de dados, estamos lidando com uma data e armazenamos uma data como uma string, você está apresentando prematuramente e favorecendo uma apresentação sobre todas as outras. Isso força todos os outros apresentadores a analisar antes da conversão. Não, o banco de dados não faz parte da camada de apresentação. Não peça para ser.

Da mesma forma, a camada de apresentação não faz parte do banco de dados, portanto, não é aconselhável associar um relatório aos detalhes do banco de dados. É muito mais robusto agir sobre os tipos.

candied_orange
fonte
Esta resposta aborda o armazenamento como seqüências de caracteres. No entanto, ele não endereça o padrão comum de armazenamento de datas em um tipo de data nativo, mas formata isso para uma sequência na consulta SQL , usando funções como CONVERT (T-SQL), nem que um DBMS normalmente serialize suas datas em uma string em um formato configurável, independentemente da consulta. Por exemplo: postgresql.org/docs/9.5/static/…
dcorking 22/09/16
Isso é um relatório. Isso acontece após o armazenamento. Como converter minha data de nascimento em minha idade.
Candied_orange 22/09
2
Eu apenas queria encorajá-lo a estender sua resposta, pois o tópico do OP é como "as datas são recuperadas da camada do banco de dados". Existe um padrão bem estabelecido, embora possivelmente descontinuado, em que um relatório consulta o banco de dados em busca de seqüências de datas formatadas e localizadas. Acho que o OP gostaria de ouvir esses argumentos de depreciação. Eu sei que sim.
dcorking 22/09/16
@dcorking note update.
Candied_orange # 22/16
+1 adicionando mais água ao moinho: basta criar um sistema em uma base instalada que abranja vários fusos horários, onde o instante absoluto é fundamental e veja como você se sai com as conversões de carimbo de data e hora em todos os lugares. Pior, defina um ponto de extensão para as pessoas criarem seus próprios plugins e fornecer a eles carimbos de data / hora, pois as strings vêem quão consistentes serão esses carimbos de data / hora!
Newtopian 22/09/16
19

Localidade

A conversão de data em string para fins de apresentação requer conhecer as preferências do usuário, pois a mesma data exata geralmente deve ser exibida de maneira diferente para usuários em diferentes localidades. Mesmo se você usar um único código de idioma em seu aplicativo, o comportamento adequado deverá usar o código de idioma do aplicativo em vez do servidor de banco de dados; e não é garantido que eles sejam idênticos, mesmo que nesse momento coincidam coincidentemente.

A conversão de um tipo de dados de data universal para uma sequência específica de código de idioma deve ocorrer na camada de apresentação, porque é a camada que sabe como essa conversão deve ser realizada.

Peter é
fonte
3
Para um exemplo real de incompatibilidade de localidade, imagine escrever um aplicativo para usuários do Maine, EUA, e depois ele será hospedado no farm de servidores da costa oeste da Amazon. ;) Essa não é uma situação improvável, na verdade.
Jpmc26 22/09/16
@ jpmc26 Não entendo a diferença - o Maine usa um formato de data diferente para o resto dos EUA?
Pete Kirkham
2
O @PeteKirkham Maine e a costa oeste dos EUA usam fusos horários separados por 3 horas.
precisa saber é o seguinte
1
Ou outro cenário da vida real: imagine executar um servidor na Suíça que atenda a clientes em quatro idiomas (alemão, francês, italiano, inglês) diferentes com localidades diferentes (e regras de formatação ligeiramente diferentes). Boa sorte ao escolher o local certo para o servidor em tal situação.
Voo 23/09
1
@ jpmc26 fusos horários e localidades não são a mesma coisa. Por exemplo, temos escritórios em Glasgow, Escócia, Atlanta EUA e Pune Índia. Os consultores nesses escritórios, por sua vez, monitoram sites (campi, hospitais, hotéis etc.) em todo o mundo, 24 horas por dia. O banco de dados do aplicativo funciona no UTC, mas exibe horários no horário local do site que está sendo monitorado. Os consultores dos EUA têm datas localizadas em MM / DD / AAAA, mas as localidades do Reino Unido e da Índia são DD / MM / AAAA - isso depende da localidade, não do fuso horário do site ou usuário.
Pete Kirkham
9

Isso é indesejável pelo mesmo motivo que você não deseja converter cegamente qualquer tipo em uma string assim que atinge a camada do aplicativo. Existe uma grande probabilidade de você querer usar esse objeto de alguma maneira antes de apresentá-lo ao usuário (se você o apresentar ao usuário). Para este exemplo específico, imagine que você precisava fazer algumas contas matemáticas no objeto. Não há desvantagem em converter o objeto em uma string precisamente antes de exibi-lo.

Gardenhead
fonte
4

Os tipos existem por uma razão: se eles não adicionassem nenhum benefício, não os teríamos e não os usaríamos; teríamos apenas "o tipo" e tudo seria isso. Eles não são apenas convenientes, mas também agregam segurança e eficiência. A seguir, é apresentada uma lista de por que você deve sempre persistir tipos no formato nativo e não como seqüências de caracteres . Usei DateTimecomo exemplo a maior parte do tempo, mas os mesmos princípios se aplicam a qualquer tipo primitivo, como números inteiros, decimais, binários etc.


Banco de dados

Restrições

Restrição de tipo

Quase todos os armazenamentos de dados permitem especificar restrições nos dados, isso inclui restrições de tipo. Um dos principais benefícios da especificação de uma DateTimeinstância é que os dados armazenados serão restritos a esse tipo. Nunca será possível inserir nada além de uma data e hora, independentemente de como os dados foram inseridos no armazenamento. O último é importante para sistemas maiores, onde existem vários processos que interagem diretamente com a loja. Isso também inclui a tentativa de adicionar datas defeituosas como 30 de fevereiro (de qualquer ano), pois fevereiro pode ter apenas 29 dias em um ano bissexto e 28 dias em anos não bissextos.

Restrições de validação

Também há restrições de validação que podem ser implementadas no Data Store, como garantir que uma data inserida não exceda a data atual ou que uma data de início ocorra antes de uma data de término.

Operações

A maioria das lojas de dados também têm construído em operações / funções como DateAddou DatePartno MS SQL Server. Isso permite que você comece a filtrar ou selecionar dados específicos enquanto os dados ainda estão na loja (ainda não recuperados para o aplicativo).

Formato universalmente aceito

Ao usar o tipo nativo, outros desenvolvedores ou sistemas que também interagem com a loja não precisam ser informados nos mínimos detalhes de como esse tipo primitivo é armazenado. Não é esse o caso se esse tipo foi armazenado como uma sequência, então você deve garantir que todos entendam o formato dessa DateTimerepresentação de sequência. Esse sistema se torna frágil ao lidar com dados que abrangem localidades, regiões e culturas na origem dos dados, o local físico de um aplicativo e os atributos do usuário / sistema final que está interagindo com esses dados. Exemplo: o formato da data em um país pode ser MM / dd / aaaa (como nos EUA), mas em outro pode ser dd / MM / aaaa, detectar essa diferença se torna quase impossível.

Rapidez

Velocidade de recuperação, velocidade de validação, velocidade de operações e eficiência de armazenamento também são fatores importantes. Exemplo da velocidade de recuperação: os armazenamentos de dados permitem índices em colunas e esses índices geralmente podem ser usados ​​com mais eficiência se o tipo for armazenado em seu formato nativo.

Aplicação

Data de acesso

A execução de consultas na loja se torna mais simples usando o sistema de tipo nativo, pois os desenvolvedores, mais uma vez, não precisam adivinhar o formato de armazenamento. Quase todos os provedores de aplicativos de armazenamento de dados ( exemplo: ado.net ) fornecem mecanismos para criar as consultas parametrizadas adequadas com base nos tipos nativos transmitidos. Veja um exemplo de adição da parte Data a uma consulta ado.net em um armazenamento do Sql Server, fazer o mesmo com strings seria muito complicado e frágil / propenso a erros.

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

Operações

Os tipos nativos no código também fornecem operações padrão como o tipo .net System.Date. As operações são geralmente de natureza matemática, como adicionar datas, encontrar a diferença entre datas, etc. Novamente, isso não é possível com facilidade nos tipos de string.

Camada de apresentação

Localidade

Quando um tipo primitivo é finalmente convertido em uma sequência na camada de apresentação ( o local correto na pilha do programa), o programador agora tem várias opções para exibi-lo corretamente de acordo com o contexto em que é apresentado. Esse contexto geralmente consiste no significado real dos dados e na localidade do usuário.

Exemplo 1

Uma instância de data e hora pode ser formatada automaticamente com base no código do idioma do usuário.

DateTime.Now.ToString("D", CultureInfo.GetCultureInfo(userContext.Culture))
Exemplo 2

Uma instância decimal pode estar representando um valor (moeda) e o código do idioma do usuário também deve exibir o valor de acordo com sua preferência. Um aplicativo c # pode então exibir o valor usando

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

Isso pode ser crítico, pois culturas diferentes exibem números de maneira diferente. No período dos EUA (.) E vírgula (,) têm o significado reverso exato, como na Holanda.

Localização

Isso é muito específico para DateTimeinstâncias. Uma data e hora representam uma ocorrência em um momento específico, mas isso geralmente deve ser transmitido / apresentado ao usuário, dependendo de seu próprio fuso horário. Exemplo: uma DateTimeinstância 2016-09-21T23:38:21.399Zpode ser exibida como 9/21/2016 5:21 PMpara um usuário no fuso horário oriental nos EUA. Existem várias maneiras de fazer isso, mas torna-se quase impossível se a instância de data e hora for mantida na memória como um tipo de sequência ou no armazenamento de dados como um tipo de sequência.


Regra geral

As 2 regras gerais para um aplicativo seguem quando se trata de converter qualquer tipo primitivo em uma representação de cadeia de caracteres.

  • Ao aceitar a entrada, converta essa entrada no tipo primitivo correto o mais cedo possível na pilha do programa (geralmente na camada de apresentação)
  • Ao recuperar dados a serem exibidos, converta esses dados na representação de string o mais tarde possível na pilha do programa (novamente, geralmente na camada de apresentação)
Igor
fonte
0

Não há realmente nada de errado em fazer isso (é feito o tempo todo nos serviços), desde que você esteja usando um formato não ambíguo para a sua data. Por inequívoca, quero dizer que não apenas a data está clara (por exemplo, MM / DD vs. DD / MM), mas também em que fuso horário está. Então, com antecedência, se você vai representar suas datas como texto, use um formato ISO . Eu prefiro as cadeias de tempo baseadas em UTC.

Prós:

  • Data / hora com base em padrões As seqüências de caracteres são portáteis e fáceis de entender
  • Geralmente, as datas nos bancos de dados contêm um componente de tempo. Se isso não for significativo para seus dados, isso poderá simplificar as coisas.

Contras:

  • Tamanho dos dados. O formato interno de uma data em um banco de dados geralmente usa muito menos espaço do que a renderização String dessa data.
  • Geralmente, você deseja inseri-lo em uma estrutura real de data ou hora no cliente, para que haja tempo extra na análise.

Se alguém dissesse que queria fazer isso, eu perguntaria "por quê?" porque não há muito sentido nisso. Se o motivo pelo qual alguém deseja retornar a data como uma String é porque eles apenas a exibem diretamente, esse não é um bom motivo para usar Strings no banco de dados.

JimmyJames
fonte