为什么不从数据库以字符串形式返回日期?


41

在典型的Web应用程序中,从强类型的数据库层中检索日期(例如,在c#中为System.DateTime,与System.String相反)。

当日期需要表示为字符串时(例如,显示在页面上),则在表示层中完成从DateTime到字符串的转换。

为什么是这样?为什么将DateTime转换为数据库层上的字符串是一件坏事?

另请参阅聊天中激烈的辩论,以及引发所有这些问题原始问题


73
让我问你一个问题:你能将每种类型都转换成字符串吗?是什么使Date有所不同?
gardenhead

7
好问题!请在此处查看正在进行激烈辩论
John Wu

8
好吧,很明显,另一个人是错误的,其他所有人都是正确的。这里不是一个真正的问题
gardenhead 16/09/21

7
有时您需要在数据库外部进行日期数学运算。如果您只有字符串,则难度会大大提高。
埃里克·金

14
另一个问题-什么样的字符串你需要什么?有很多方法可以将日期时间表示为字符串。如果我有一个仅返回当前时间(表示从纪元开始的秒数)作为字符串的数据库(例如,当前时间为“ 1474496980”),该怎么办?这样有用吗?您想使用这样的数据库吗?
riwalk

Answers:


168

日期,日期时间以及实际上任何其他类型的对象,通常应保留其正确类型的格式,直到需要将它们转换为其他类型的时间为止-尤其是当该类型是人类可读的形式时,尤其是当它是有损/单向转换。

为什么?因为假定类型为您提供了许多方便的内置功能,例如适当的相等性测试,加法和减法,比较(大于,小于),时区和语言环境功能(对于与时间相关的任何事物尤其重要),等等。如果您决定要支持美国人和“ Month Day [th],Year”格式,以及常见的英式“ Day Month Year”,还是ISO标准“ Year-Month-Day”?如果它是字符串并且需要进行更改并将其解析回Date,该怎么办?gh,不,谢谢-这样会有很多弊端和臭虫,最好完全避免。

更具体地说,您提到了分层体系结构,该体系结构的表示层与稍后的数据分开。这实际上是将Date作为日期而不是字符串传递的另一个重要原因-因为该日期应放入哪种类型的字符串格式中?您是否要稍后在日期字段上对英文,中文(带或不带秒/毫秒,完整的月份名称或数字)进行排序(对字符串进行排序需要某种字符串格式,如果您希望它能正常工作的话)等等?这完全是表示的问题-用户应如何查看数据-并将该逻辑放置在其他任何地方将首先限制分层体系结构的优势。数据库不需要知道或关心将来如何查看日期。

最后,几乎所有关心时间的复杂应用程序(这是分层体系结构的目的)都将不可避免地以许多不同方式(通常在体系结构的所有不同级别)使用时间/日期。存在与时间和日期相关的类型化对象的确有充分的理由:时间本身,尤其是人类日历系统,既奇怪又困难。最终,时间和日期不是字符串,其原因与整数和浮点数不是字符串一样,并且如果您假装它们实际上只是字符数组,只会使您的生活更加艰难,因为它们不是字符数组。


26
+1是仅用于含糊不清的单词。我同意您的令人信服的论点和全面的解释,但这就是为什么我必须登录并为您投票。
阿德里安·拉森

1
将日期时间表示为自过去定义的时间以来的秒数,在不同的日历中也很可靠。例如,伊斯兰和中国日历不使用任何希腊月份,年份等。我会考虑在数据库级别处理此错误做法。
rexkogitans

日期通常显示为“ X天前”。祝您好运,并将其解析回原始值。
Agent_L

5
我们也不要忘记DST更改(和其他类似问题)的问题。将“2016年11月6日上午一点30分26秒”是这个日期和时间将发生在第一时间或第二次?UTC DateTime至少是唯一的,您可以始终将其转换为该时间的本地表示形式-并非总是可以以其他方式返回。
J ...

3
Why? Because it is assumed that the type provides you with lots of handy built in functionality我认为这只是次要的。真正的原因是类型告诉您什么是什么。日期不是字符串,它只是很容易转换为人类可读的字符串。
Doval 2013年

53

他说要使用Web服务器将数据时间转换为字符串。我是说在数据库服务器而不是Web服务器上执行此操作。您为什么认为更好?- MT头

我想知道类型。

我真的不在乎您的数据库是否将信息存储在字符串,一些整数或字节中,因为最后,无论如何它始终是字节。该字符串所占用的空间超过了数据库所需的空间,这并不困扰我。令我困扰的是这样的日期:

2016年11月10日

而且不知道是第十一个月还是第十个月。

但是您说的已经过验证。确保您通过了验证过程。日期是完全正确的。但是在这里我维护着这个东西,我只知道日期是一个字符串。我什至不告诉你这是几号。

“我们主人在二千一十六年的十一月第十日。”

那是一个字符串。我们的演示文稿之一需要这种格式。您说数据库将所有日期都转换为字符串,对吗?玩得开心。

数据库的工作是存储数据而不是现有数据。当然,您可以在字符串中执行此操作,但随后必须对其进行解析,以使其对于其他格式的呈现很有用。以标准的解析形式将其存储到数据库提供的任何类型,都可以使我们尽可能地准备好呈现,而无需做出呈现决定。对于我来说,数据库是否使用字符串,整数或字节支持该类型真的不重要。只要知道它在做什么。

但是,当您不让数据库知道我们正在处理一个日期并将日期存储为字符串时,您会过早地呈现该表述,并且优先于其他所有表述。这迫使所有其他演示者在转换之前进行解析。不,数据库不是表示层的一部分。不要问它是。

同样,表示层也不是数据库的一部分,因此将报表与数据库详细信息耦合也是不明智的。对类型进行操作要健壮得多。


该答案以字符串形式存储。但是,它没有解决以本机日期类型存储日期的常见模式,而是使用诸如CONVERT(T-SQL)之类的函数将其格式化为SQL查询中的字符串,或者DBMS通常序列化其日期转换为可配置格式的字符串,无论查询如何。例如:postgresql.org/docs/9.5/static/...
dcorking

那是一份报告。它在存储后发生。就像将我的出生日期转换成我的年龄一样。
candied_orange

2
我只想鼓励您扩展答案,因为OP的主题是“如何从数据库层检索日期”。有一个公认的模式(尽管可以说已被弃用),其中报告查询数据库以获取格式化和本地化的日期字符串。我认为OP希望听到这些弃用论据。我知道我会的
dcorking

@dcorking笔记更新。
candied_orange

+1向工厂添加更多的水:只需在已安装的基础上创建一个系统,该系统跨越多个时区,其中绝对瞬时是最重要的,并查看您在任何地方使用string <-> timestamp转换的效果如何。最糟糕的是,给人们一个扩展点,让他们创建自己的插件,并给他们时间戳记,因为字符串可以看到这些时间戳记的一致性!
Newtopian

19

语言环境

为了演示目的,将日期转换为字符串需要了解用户的喜好,因为对于不同地区的用户,通常应该完全相同地显示同一日期。即使您在应用程序中使用单个语言环境,正确的行为也应使用应用程序的语言环境而不是数据库服务器。并且即使此时恰好匹配,也不能保证它们是相同的。

从通用日期数据类型到特定于语言环境的字符串的转换应该在表示层中进行,因为它是知道如何执行转换的层。


3
对于一个实际的地区不匹配示例,可以想象为美国缅因州的用户编写一个应用程序,然后将其托管在亚马逊的西海岸服务器场中。;)实际上,这并非不可能。
jpmc26 2016年

@ jpmc26我不明白其中的区别-缅因州是否使用与美国其他地区不同的日期格式?
皮特·柯坎

2
@PeteKirkham缅因州和美国西海岸使用的时区相隔3个小时。
jpmc26 2016年

1
或另一种现实生活中的场景:假设在瑞士运行一台服务器,该服务器必须以四种(德语,法语,意大利语,英语)不同语言,不同语言环境(以及略有不同的格式规则)为客户提供服务。在这种情况下,请为您的服务器选择正确的语言环境。
Voo

1
@ jpmc26时区和语言环境不是一回事。例如,我们在苏格兰格拉斯哥,美国亚特兰大和印度浦那设有办事处。这些办公室的顾问反过来全天候监控世界各地(校园,医院,旅馆等)的地点。应用程序数据库使用UTC,但以受监视站点的本地时间显示时间。美国顾问的日期本地化为MM / DD / YYYY,但是英国和印度的语言环境为DD / MM / YYYY-这取决于语言环境,而不是网站或用户的时区。
皮特·柯坎

9

出于相同的原因,这是不可取的,因为您不希望在类型到达应用程序层后立即将任何类型的字符串盲目转换为字符串。在将对象呈现给用户之前,您很有可能想要以某种方式使用该对象(如果您确实将其呈现给用户)。对于此特定示例,假设您需要对该对象进行一些日期数学运算。仅在显示对象之前将其转换为字符串没有任何弊端。


4

类型的存在是有原因的,如果它们没有带来任何好处,那么我们将不会拥有它们,也不会使用它们,而我们只会拥有“类型”,而一切都会如此。它们不仅方便,还增加了安全性和效率。以下列出了为什么您应始终以其本机格式而不是字符串形式保留类型。我DateTime大部分时间都作为示例,但是相同的原理适用于任何原始类型,例如整数,小数,二进制等。


数据存储

约束条件

类型约束

几乎所有数据存储区都允许指定数据约束,其中包括类型约束。指定DateTime实例的主要好处之一是将存储的数据限制为该类型。无论日期如何插入到存储中,都永远不可能输入除日期时间以外的任何内容。后者对于大型系统非常重要,在大型系统中,有多个与商店直接交互的流程。这还包括尝试添加错误的日期(例如每年的2月30日),因为2月February年只能有29天,非non年只能有28天。

验证约束

还可以在数据存储区中实施验证约束,例如确保插入的日期不超过当前日期或开始日期早于结束日期。

运作方式

大多数数据存储区还具有内置的操作/功能,例如DateAddDatePart在MS Sql Server中。这样,您就可以在数据仍在存储中(尚未检索到应用程序)时开始过滤或选择特定数据。

普遍接受的格式

通过使用本机类型,也不必通知其他与商店交互的开发人员或系统有关该原始类型如何存储的详细信息。如果该类型存储为字符串则不是这种情况,那么您必须确保每个人都理解该DateTime字符串表示形式的格式。当处理跨越数据来源中的区域,区域和区域性的数据,应用程序的物理位置以及与该数据进行交互的最终用户/系统的属性时,此系统变得脆弱。例如:一个国家的日期格式可能是MM / dd / yyyy(例如在美国),但在另一个国家中,日期格式可能是dd / MM / yyyy,因此几乎不可能检测到这种差异。

速度

检索速度,验证速度,操作速度和存储效率都是重要因素。检索速度的示例:数据存储允许在列上进行索引,并且如果以本机格式存储类型,则通常可以更有效地使用这些索引。

应用

资料存取

使用本机类型系统,对商店执行查询变得更加简单,因为开发人员再次不必猜测存储格式。几乎所有的数据存储应用程序提供程序(例如:ado.net)都提供了用于根据传入的本机类型创建适当的参数化查询的机制。这是将Date部分添加到针对Sql Server存储的ado.net查询中的示例,对字符串执行相同的操作将非常麻烦且容易出错。

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

运作方式

代码中的本机类型还提供标准操作,例如.net类型System.Date。操作通常本质上是数学的,例如添加日期,查找日期之间的差异等。同样,在字符串类型上也不容易做到这一点。

表示层

语言环境

当原始类型最终在表示层(在程序堆栈中的正确位置)中转换为字符串时,程序员现在可以使用各种选项来根据显示上下文正确地显示它。该上下文通常由数据的实际含义和用户的语言环境组成。

例子1

可以基于用户的语言环境自动格式化日期时间实例。

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

十进制实例可以表示金额(货币),然后用户的语言环境还应根据其偏好显示金额。然后,C#应用程序可能会使用

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

这可能很关键,因为不同的文化显示数字的方式不同。在美国,句号(。)和逗号(,)与荷兰的含义完全相反。

位置

这是非常特定于DateTime实例的。日期和时间表示在特定时间点发生的事件,但是通常必须根据用户自己的时区将其传达/呈现给用户。示例:可以在美国东部时区为用户显示一个DateTime实例。有很多方法可以完成此操作,但如果日期时间实例以字符串类型保存在内存中或以字符串类型保存在数据存储中,则几乎无法实现。2016-09-21T23:38:21.399Z9/21/2016 5:21 PM


一般规则

在将任何原始类型转换为字符串表示形式时,应遵循应用程序的一般2条规则,这些规则如下:

  • 接受输入时,应尽早在程序堆栈中(通常在表示层中)将该输入转换为正确的原始类型。
  • 检索要显示的数据时,应尽可能晚在程序堆栈中(同样,通常在表示层中)将数据转换为字符串表示形式

0

只要您在日期中使用无歧义的格式,这样做就没有任何问题(服务中一直都在这样做)。明确地说,我的意思是不仅要明确日期(例如MM / DD vs. DD / MM),而且要明确其所在的时区。因此,在开始时,如果要将日期表示为文本,请使用ISO格式。我非常喜欢基于UTC的时间字符串。

优点:

  • 基于标准的日期/时间字符串可移植且易于理解
  • 数据库中的日期通常包含时间成分。如果这对您的数据没有意义,那么实际上可以简化事情。

缺点:

  • 数据大小。数据库中日期的内部格式通常将使用比该日期的String渲染少的空间。
  • 通常,您将需要将其转换为客户端上的实际日期或时间结构,因此可能需要更多的时间进行解析。

如果有人说他们想这样做,我会问“为什么?” 因为没有太多意义。如果有人要返回日期作为字符串的原因是因为他们只是直接显示日期,那么这不是从数据库中使用字符串的好理由。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.