在数据库中存储时间(hh: mm)的最佳方法

我想在数据库表中存储时间,但只需要存储小时和分钟。 我知道我可以只使用 DATETIME 而忽略日期的其他组件,但是什么是最好的方法来做到这一点,而不存储超过我实际需要的信息?

172541 次浏览

你可以把它存储为午夜过后分钟数的整数:

例如。

0 = 00:00
60 = 01:00
252 = 04:12

然而,您需要编写一些代码来重新构建时间,但是这并不复杂。

我将它们转换成一个整数(HH * 3600 + MM * 60) ,并以这种方式存储它。存储空间小,使用起来也很方便。

试试小约会时间。它可能不会给你你想要的,但它会帮助你在未来的需要,在日期/时间的操纵。

如果您正在使用 SQLServer2008 + ,请考虑带有更多使用示例的 TIME数据类型.SQLTeam 文章

因为你没有提到它位如果你是在 SQLServer2008你可以使用时间数据类型否则使用分钟从午夜

你确定你只需要几个小时和几分钟吗?如果你想对它做一些有意义的事情(比如计算两个数据点之间的时间跨度) ,没有关于时区的信息,DST 可能会给出不正确的结果。时区可能不适用于你的情况,但 DST 最肯定会。

只是存储一个固定的日期时间,忽略其他一切。为什么要花费额外的时间编写加载 int、操作它并将其转换为 datetime 的代码,而您只需要加载 datetime 即可?

如果您正在使用 MySQL,请使用 TIME 字段类型以及 TIME 附带的相关功能。

00:00:00是标准的 unix 时间格式。

如果您需要回过头来手工查看表,那么整数可能比实际的时间戳更令人困惑。

SQLServer 实际上将时间存储为一天中的几个小时。例如,1整天 = 值为1。12小时是0.5。

如果希望在不使用 DATETIME 类型的情况下存储时间值,则以十进制形式存储时间将适合这种需要,同时还可以简化到 DATETIME 的转换。

例如:

SELECT CAST(0.5 AS DATETIME)
--1900-01-01 12:00:00.000

将值存储为 DECIMAL (9,9)将消耗5个字节。然而,如果精度不是最重要的,REAL 只会消耗4个字节。在这两种情况下,聚合计算(即平均时间)都可以很容易地根据数值计算,但不能根据 Data/Time 类型计算。

我们把它存储为24小时的时钟,而不是午夜过后几分钟。

09:12 = 912 14:15 = 1415

当转换回“人类可读形式”时,我们只需从右边插入冒号“ :”两个字符。如果需要的话,可以在左边写上零。每种方法都节省了数学运算,并且使用的字节更少(与 varchar 相比) ,另外还强制使用数值(而不是字母数字)

相当愚蠢,虽然... 应该有一个时间的数据类型,在 MS SQL 已经很多年,恕我直言..。

节省时间的 UTC 格式可以帮助更好地克里斯汀建议。

请确保您正在使用24小时的时钟,因为没有子午线上午或下午在 UTC 使用。

例如:

  • 4:12 AM-0412
  • 10:12 AM - 1012
  • 下午2:28-1428
  • 11:56 PM-2356

它仍然优于使用标准的四位数字格式。

日期时间开始日期时间结束

I implore you to use 两个 DATETIME 值 instead, labelled something like Event _ start and event_end.

时间是一项复杂的业务

现在世界上大多数国家在大多数测量中都采用了基于草地的公制系统,无论是对是错。总的来说这是好事,因为至少我们都同意 g 等于 ml 等于立方厘米。至少大概是这样。公制有许多缺陷,但至少它在国际上一贯存在缺陷。

然而,随着时间的推移,我们有: 每秒1000毫秒,每分钟60秒到一分钟,每分钟60分钟到一小时,每半天12小时,每月大约30天,每个国家的时间与其他国家的时间相抵消,每个国家的时间格式不同。

虽然有很多东西需要消化,但是对于这样一个复杂的场景来说,不可能有一个简单的解决方案。

有些地方可以走捷径,但有些地方还是不走捷径比较明智

虽然这里的最佳答案建议你在午夜过后存储一个整数分钟,这看起来似乎是完全合理的,但我已经学会了避免这样做的艰难方式。

The reasons to implement two DATETIME values are for an increase in accuracy, resolution and feedback.

当设计产生不理想的结果时,这些都非常方便。

存储的数据是否超过所需数据?

It might initially appear like more information is being stored than I require, but there is a good reason to take this hit.

从长远来看,储存这些额外的信息几乎总能节省我的时间和精力,因为我不可避免地发现,当有人被告知某件事花了多长时间时,他们还会想知道事件发生的时间和地点。

这是个巨大的星球

在过去,我曾因忽视这个星球上除了我自己的国家之外还有其他国家而感到愧疚。这在当时看起来是个好主意,但是这总是导致问题、头疼和浪费时间。总是考虑所有的时区。

C#

A DateTime renders nicely to a string in C#. The ToString(string Format) method is compact and easy to read.

例如。

new TimeSpan(EventStart.Ticks - EventEnd.Ticks).ToString("h'h 'm'm 's's'")

SQL 服务器

另外,如果将数据库单独读取到应用程序接口,那么 dateTimes 很容易一目了然地阅读,并且在它们上面执行计算也很简单。

例如。

SELECT DATEDIFF(MINUTE, event_start, event_end)

ISO8601 date standard

如果使用 SQLite,那么您就没有这个,所以使用一个 Text 字段并以 ISO8601格式存储它,例如。

"2013-01-27T12:30:00+0000"

备注:

  • This uses 24 hour clock*

  • ISO8601的时间偏移(或 + 0000)部分直接映射到 GPS 坐标的经度值(不考虑夏时制或全国范围)。

例如。

TimeOffset=(±Longitude.24)/360

指的是东方或西方。

因此,值得考虑的是,是否值得将经度、纬度和海拔与数据一起存储。这将在应用中有所不同。

  • ISO8601是一种国际格式。

  • The wiki is very good for further details at http://en.wikipedia.org/wiki/ISO_8601.

  • 日期和时间存储在国际时间中,根据存储时间的位置记录偏移量。

根据我的经验,总是需要存储完整的日期和时间,无论我是否认为有当我开始的项目。ISO8601是一个非常好的,防止未来的做法。

免费附加建议

将事件像链条一样组合在一起也是值得的。例如,如果记录一场比赛,整个事件可以按照比赛者、比赛环路、环路检查点和环路圈进行分组。

根据我的经验,确定谁存储了记录也是明智的。可以作为通过触发器填充的独立表,也可以作为原始表中的附加列。

你投入的越多,得到的就越多

我完全理解尽可能节省空间的愿望,但我很少以丢失信息为代价。

数据库的一个经验法则是,正如标题所说,数据库只能告诉你它所拥有的数据的多少,而且回溯历史数据以填补空白的成本可能非常高。

解决办法是第一次就把它做对。这当然说起来容易做起来难,但是您现在应该对有效的数据库设计有了更深入的了解,并且随后有更大的机会在第一次就正确地完成它。

你最初的设计越好,以后的维修费用就越低。

我之所以这么说,是因为如果我能回到过去,那么当我到达那里时,我也会这么告诉自己。

ticks存储为 long/bigint,当前以毫秒为单位。通过查看 TimeSpan.TicksPerSecond值可以找到更新后的值。

大多数数据库都有一个 DateTime 类型,它自动将时间存储为幕后的刻度,但是对于某些数据库,例如 SqlLite,存储刻度可以作为存储日期的一种方式。

大多数语言允许从 TicksTimeSpanTicks的简单转换。

例子

在 C # 中,代码是:

long TimeAsTicks = TimeAsTimeSpan.Ticks;


TimeAsTimeSpan = TimeSpan.FromTicks(TimeAsTicks);

但是要注意,因为在 SqlLite 的例子中,它只提供少量不同的类型,这些类型是: INTREALVARCHAR。有必要将刻度数存储为一个字符串或两个 INT单元格的组合。这是因为 INT是一个32位有符号数字,而 BIGINT是一个64位有符号数字。

注意

然而,我个人的偏好是将日期和时间存储为 ISO8601字符串。

What I think you're asking for is a variable that will store minutes as a number. This can be done with the varying types of integer variable:

SELECT 9823754987598 AS MinutesInput

然后,在你的程序中,你可以简单地通过计算按照你想要的形式查看:

long MinutesInAnHour = 60;


long MinutesInADay = MinutesInAnHour * 24;


long MinutesInAWeek = MinutesInADay * 7;




long MinutesCalc = long.Parse(rdr["MinutesInput"].toString()); //BigInt converts to long. rdr is an SqlDataReader.




long Weeks = MinutesCalc / MinutesInAWeek;


MinutesCalc -= Weeks * MinutesInAWeek;




long Days = MinutesCalc / MinutesInADay;


MinutesCalc -= Days * MinutesInADay;




long Hours = MinutesCalc / MinutesInAnHour;


MinutesCalc -= Hours * MinutesInAnHour;




long Minutes = MinutesCalc;

当您要求使用效率时会出现一个问题,但是,如果时间不够,那么 只需使用可为空的 BigInt 来存储分钟值。

值为 null 意味着时间尚未被记录。

现在,我将以往返外太空的形式来解释。

遗憾的是,表列只能存储单个类型。因此,需要根据需要为每种类型创建一个新表。

例如:

  • 如果 MinutesInput = 0. . 255,则使用 TinyInt(如上所述进行转换)。

  • 如果 MinutesInput = 256. . 131071,则使用 SmallInt(注意: SmallInt 的 min 值为 -32,768。因此,在存储和 检索值,在转换之前使用全部范围)

  • 如果 MinutesInput = 131072. . 8589934591,则使用 Int(注意: 否定并添加 2147483648)

  • 如果 MinutesInput = 8589934592. . 36893488147419103231,则使用 < strong > BigInt (注: 如有必要,加上并否定9223372036854775808)。

  • 如果分钟输入 > 36893488147419103231,那么我个人会使用 因为字符是一个字节,所以必须增加 X 我们不得不在以后的日子里重新讨论这个问题的答案,以便详细描述这个问题 (或者也许一个堆积如山的家伙可以完成这个答案)

Since each value will undoubtedly require a unique key, the efficiency of the database will only be apparent if the range of the values stored are a good mix between very small (close to 0 minutes) and very high (Greater than 8589934591).

直到被存储的数值实际上达到一个大于36893488147419103231的数字,那么你可能只有一个单独的 BigInt 列来表示你的分钟,因为你不需要在一个唯一标识符上浪费一个整型数和另一个整型数来存储分钟值。

IMHO what the best solution is depends to some extent on how you store time in the rest of the database (and the rest of your application)

就我个人而言,我一直在使用 SQLite,并尝试始终使用 Unix 时间戳来存储绝对时间,所以当处理一天中的时间(像你要求的那样) ,我会按照 Glen Solsberry 在他的答案中写的那样,存储从午夜到现在的秒数

当采取这种一般的方法时,人们(包括我!)如果我在任何地方都使用相同的标准,阅读代码就不会那么困惑了