【问题标题】:Saving Dates in SQLServer在 SQL Server 中保存日期
【发布时间】:2009-06-03 22:59:37
【问题描述】:

我有一个遗留应用程序,其中输入是日期字符串,即:

2009 年 6 月 12 日

输入的格式总是字符串,并且是一致的,总是dd/mm/yyyy

目前,旧版应用程序只是在 DateTime 字段中插入此内容。显然,如果服务器的本地化文化设置发生变化,我们有一个错误。

两个问题:

一个:

在这种情况下,在 SQLServer 中存储日期最安全的方法是什么?

是否有一种格式可以始终正确解释,而不管日期和月份的顺序如何?

二:

究竟是什么设置决定了 SQLServer 数据库的文化,是操作系统设置,还是该数据库的设置,还是什么?

干杯

【问题讨论】:

    标签: sql-server datetime


    【解决方案1】:

    YYYY-MM-DD 格式是明确的,这意味着 SQL Server 不会混淆月份 以及将字符串值转换为DATETIME 的日期。 (我从未遇到过使用四位数年份的格式进行隐式转换的问题。)

    在 SQL Server 中存储日期值的“最安全”(也是最方便)的方法是使用 DATETIME 数据类型。

    在DATETIME 和字符串之间转换时,使用CONVERT 函数显式指定输入和输出格式。

    关于 CONVERT style 参数值的 SQL Server 2005 文档:

    http://msdn.microsoft.com/en-us/library/ms187928(SQL.90).aspx

    要将字符串表示形式转换为 DATETIME 数据类型:

    select CONVERT(datetime, '2009-06-03', 20)
    

    第一个参数是要转换的数据类型,第二个参数是要转换的表达式,第三个参数是样式。

    (style 20 是 ODBC 规范格式 = 'YYYY-MM-DD HH:MI:SS'(24 小时制)


    [跟进]

    将 DATETIME 表达式(例如 getdate() 转换为 'YYYY-MM-DD' 格式的 VARCHAR:

    select CONVERT(varchar(10), getdate(), 20)
    

    请注意,指定 varchar(10) 只会获取 etnire 'YYYY-MM-DD HH:MM:SS' 格式的前 10 个字符。

    [/跟进]


    至于什么决定了默认格式,这将是研究。我们通过指定格式来避免默认格式引起的问题。

    【讨论】:

    • 嗨,斯宾塞,感谢您提供的信息。在日期时间字段上执行 SELECT 时,如何将其转换回通用格式(yyyy-mm-dd)的字符串?
    • @andy:答案已更新以回答后续问题。 (对于答案的不完整,我深表歉意......我只是给你 SQL 表达式来进行转换。(对于影响区域/语言环境默认格式的所有内容,我真的没有很好的答案。(我“我是一名 IT 人员,我喜欢我的日期字符串规范 CCYYMMDDH24HMISS,因此我可以对它们进行排序。任何没有世纪和年份前导的格式,我使用三个字母缩写表示月份,例如 03-JUN-2009。它避免歧义。
    • 格式 YYYY-MM-DD 是 ISO-8601 建议,无论您的日期格式或语言系统设置如何,都将始终在 SQL Server 上工作。用它! :-) 您始终可以从该通用格式转换为您需要的任何本地化表示。
    • @spencer:哈哈,是的,不用道歉,谢谢你的帮助。刚从修复遗留应用程序回来......日期的处理非常糟糕,代码也是......
    • @spencer7593 这种格式并不明确,这就是为什么我同意您始终指定格式的建议。 SQL 在隐式和显式强制转换/转换之间不一致。试试这个:set language British select month(CAST('2016-01-12' AS datetime))
    【解决方案2】:

    我建议在将所有日期放入数据库时​​将它们存储为 UTC 时间。这样会保持一致。

    这样存储日期似乎效果很好......

    YYYY-MM-DD
    

    【讨论】:

    • ISO-8601 标准 - 始终有效 - 为什么不是每个人都已经使用它? :-)
    【解决方案3】:

    见SET DATEFORMAT。 SQL 'culture' 由SET LANGUAGE 在会话级别设置。 SQL Server 有自己的日期格式设置,独立于宿主操作系统。这有几个原因:ANSI 合规性,为了防止操作系统更改影响使用该主机上托管的数据库的应用程序,尤其是兼容性,SQL 早于操作系统当前运行的时间。

    【讨论】:

      【解决方案4】:

      请记住,DATA 不是它的 PRESENTATION。在这种情况下,DATA 是 DATE 或 DATETIME,无论您如何显示它们。
      至于插入/更新/比较日期时间值,我引用了 BOL:

      在比较中指定日期时 或用于 INSERT 或 UPDATE 的输入 语句,使用的常量是 对所有语言都进行相同的解释 设置:ADO、OLE DB 和 ODBC 应用程序应使用 ODBC 时间戳、日期和时间转义 的子句:
      { ts 'yyyy-mm-dd hh:mm:ss[.fff] '} 如:{ ts '1998-09-24 10:02:20' }
      { d 'yyyy-mm-dd'} 如:{ d '1998-09-24' }
      { t 'hh:mm:ss'} 如:{ t '10:02:20'}

      我可以向您保证,如果您使用这种格式,它们将始终有效,无论您的服务器的语言环境如何

      【讨论】:

      • 仅用于隐式转换。请注意,如果您转换/转换“yyyy-mm-dd”并且您的语言是“英国”,那么它会将您的字符串视为“yyyy-dd-mm”。
      【解决方案5】:

      我在这些问题上有点保守,但我更喜欢在表中使用单独的年/月/日字段,而不是使用特定于 DBMS 数据类型的日期字段。这当然需要更多的空间,但没有歧义和增加便携性对我来说是值得的。

      您付出的代价是您无法获得免费的日期/时间算术和排序,但您自己或通过稍微复杂一点的“ORDER BY”子句就可以轻松完成。

      【讨论】:

      • ISO_8601 格式 (YYYY-MM-DD) 的日期将始终在 SQL Server 上运行 - 无论您的日期格式或语言设置多么糟糕。真的不需要将日、月、年分成单独的字段。
      • @Marc:我相信你是对的。对我来说,问题一直出在代码和 DBMS 之间的接口上——我可以从任何数据库中提取一个整数,但是日期类型在 DB API、编程语言等之间变化无常且不一致。这对我来说更容易在合理的情况下将事物视为整数。个人选择,显然......
      • @marc_s 不,他们不会。设置语言英国,然后在不指定可选格式的情况下进行转换/转换。转换/转换假定为 'yyyy-dd-mm'!
      【解决方案6】:

      我同意 spencer7593 的建议,但请注意,使用不带格式的 cast 或 convert 会产生意想不到的结果。此 T-SQL 查询返回 12,而不是 1。

      set language British
      select month(CAST('2016-01-12' AS datetime))
      

      【讨论】:

        【解决方案7】:

        通常我更喜欢插入为

        insert into tbl values('yyyyMMdd')
        

        然后,它将根据 db 以适当的格式插入。

        【讨论】:

          猜你喜欢
          • 2014-08-09
          • 2023-04-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-30
          • 2017-09-02
          • 2015-08-19
          相关资源
          最近更新 更多