【问题标题】:Store date with optional month / day带有可选月/日的存储日期
【发布时间】:2014-04-22 19:26:37
【问题描述】:

我想在我的 Postgres 数据库中存储日期。
唯一的问题是这个日期可以有可选的日期甚至月份。

示例:
用户提供他受雇的时间段 - 不需要完整日期(日 + 月 + 年),而只提供开始年份和结束年份。
但是也有用户在同一年的 5 月到 10 月工作,所以也必须提供月份。

如何处理这种可选的日期部分?

【问题讨论】:

  • 是否应该将 2000 年开始工作的用户与 2000 年 1 月 1 日开始工作的用户区分开来?
  • 这是前端表示的问题,如果用户没有提供,我想隐藏月份和日期字段。
  • 似乎您实际上需要将它们存储为年、日、月。否则,您将无法提供有效的Date。然后你可以建立一个Date 如果所有的属性都给出了。这样 U/I 也会更容易,因为您可以提供 3 个下拉列表。
  • 或者只是一个普通的字符串输入,带有用于不同用例的模式验证器和一个模型方法,如果可以解析字符串(例如Date.parse,则返回相应的日期对象。
  • 仅供参考,这些被称为“模糊日期”或“部分日期”

标签: ruby-on-rails ruby database postgresql database-design


【解决方案1】:

无论如何都要使用正确的date 类型。 不要存储文本或多列。那会更昂贵且更不可靠。

使用函数to_date(),开箱即可满足您的需求。例如,如果您使用模式'YYYYMMDD' 调用它并且实际字符串缺少日或月和日的字符,则默认为一年/月的第一个月/第一天:

db=# SELECT to_date('2001', 'YYYYMMDD');
  to_date
------------
 2001-01-01

db=# SELECT to_date('200103', 'YYYYMMDD');
  to_date
------------
 2001-03-01

如果需要,您还可以存储一个指示年/月/日的精度标志。

【讨论】:

  • 我们决定使用单独的表格,例如 time_period,它将开始和结束日期存储为 date,并带有适当的掩码来告诉用户真正提供了哪些值。
【解决方案2】:

虽然accepted answer 不错,但还有另一种选择。

ISO 8601

ISO 8601 标准为各种日期时间值的文本表示定义了合理的格式。

年份以显而易见的方式表示,一个四位数字:2014

用必需的连字符表示年月:2014-01
请注意,在其他 ISO 8601 格式中,连字符是可选的。但不要针对年月,以免产生歧义。

完整日期类似:2014-08-21 或没有可选连字符:20140821。我建议保留连字符。

因此您可以将值存储为文本。文本的长度会告诉您它是仅年、年月还是日期。

【讨论】:

  • 我很惊讶你会建议text 来存储日期。 date 占用 4 个字节,2014-08-21 占用 11 个字节,如text。排序规则会减慢text 的排序,计算持续时间或任何日期算法最好基于实际的date 类型。索引、格式化、转换 - 使用正确的 date 类型,一切都变得更简单/更干净/更快。像“2001-02-29”这样的非法日期是不可能的。简而言之:永远不要将date 存储为text。如果我们需要区分日/月/年,一个字节的附加 "char" 标志就可以了。
  • @ErwinBrandstetter 我的回答提供了替代方案,而不是建议。两种答案中的方法都有利有弊。两者都不理想。基本问题是数据库缺少部分日期时间值的数据类型。我想知道 SQL:2011 中的新 temporal features 如果实现了是否提供部分值(我还没有研究过)。
猜你喜欢
  • 1970-01-01
  • 2015-06-01
  • 1970-01-01
  • 2012-03-30
  • 2011-06-27
  • 2015-10-06
  • 2020-01-29
  • 1970-01-01
  • 2011-09-29
相关资源
最近更新 更多