将时间(hh:mm)存储在数据库中的最佳方法
我想在数据库表中存储时间,但只需要存储小时和分钟。 我知道我可以使用DATETIME并忽略date的其他组件,但是如果不存储比我实际需要的更多信息,最好的方法是什么?
您可以将其存储为午夜过后的分钟数的整数:
例如。
0 = 00:00 60 = 01:00 252 = 04:12
然而,你需要编写一些代码来重构时间,但这不应该是棘手的。
如果您使用的是SQL Server 2008+,请考虑TIME
数据types。 SQLTeam文章更多使用示例。
只要存储一个正常的date时间,并忽略其他一切。 为什么要花费额外的时间编写加载int的代码,对其进行处理,并将其转换为date时间,只需加载date时间?
DATETIME开始DATETIME结束
我恳请您使用两个DATETIME值 ,标记类似event_start和event_end 。
时间是一个复杂的业务
现在世界上大部分的公司都已经采用了基于公制的测量系统,无论对错还是错。 这是好事,因为至less我们都可以同意ag是一毫升,是立方厘米。 至less大约如此。
随着时间的stream逝,我们有; 每秒1000毫秒,60秒至1分钟,60分钟至1小时,每半天12小时,每月约30天,每月甚至每年不等,每个国家都有其时间偏移,每个国家的时间格式都不一样。
消化需要很多东西,但是这样一个复杂的场景不可能有简单的解决scheme。
有些angular落可以削减,但有些地方更不明智
虽然这里最好的答案是暗示你在午夜之前保存整整一分钟似乎是完全合理的,但我已经学会了避免这么做。
实施两个DATETIME值的原因是为了提高准确性,分辨率和反馈。
当devise产生不良结果时,这些都非常方便。
我是否存储比所需的更多的数据?
它可能最初看起来好像存储的信息比我所需要的更多,但是有一个很好的理由来采取这种打击。
存储这些额外的信息几乎总是会最终节省我长期的时间和精力,因为我不可避免地发现,当有人被告知需要花费多长时间时,他们还想知道事件发生的时间和地点。
这是一个巨大的星球
在过去,我一直忽视这个星球上除了我自己之外还有其他国家。 当时这似乎是一个好主意,但是这总是导致了问题,头痛和后来浪费的时间。 总是考虑所有的时区。
C#
DateTime很好地呈现给C#中的string。 ToString(string格式)方法紧凑且易于阅读。
例如
new TimeSpan(EventStart.Ticks - EventEnd.Ticks).ToString("h'h 'm'm 's's'")
SQL服务器
另外,如果你正在读取数据库的数据到你的应用程序接口,那么dateTimes一眼就可以阅读,并且对它们进行计算是很简单的。
例如
SELECT DATEDIFF(MINUTE, event_start, event_end)
ISO8601date标准
如果使用SQLite,那么你没有这个,所以而是使用一个文本字段,并存储在ISO8601格式,例如。
“2013-01-27T12:30:00 + 0000”
笔记:
-
这使用24小时制*
-
ISO8601的+0000部分直接映射到GPS协调中的格点。 因此值得考虑是否值得存储经度,纬度和高度以及数据。 这在应用中会有所不同。
-
ISO8601是一种国际格式。
-
在http://en.wikipedia.org/wiki/ISO_8601上; ,维基是非常好的进一步的细节。
-
date和时间以国际时间存储,偏移量根据存储时间在世界的哪个位置进行logging。
根据我的经验,总是需要存储完整的date和时间,无论我是否认为开始项目时都是如此。 ISO8601是一个很好的,未来的方式来做到这一点。
额外的build议是免费的
这也是值得像链一样组织事件。 例如,如果logging一场比赛,则整个事件可以由赛车手,race_circuit,circuit_checkpoints和circuit_laps分组。
根据我的经验,识别存储logging的人也是明智的。 既可以作为通过触发器填充的独立表格,也可以作为原始表格中的附加列。
你越投入,越多
我完全理解尽可能和空间一样经济的愿望,但是我很less这样做,而不是以损失信息为代价。
数据库的一个经验法则就像标题所说的那样,一个数据库只能跟数据一样告诉你,通过历史数据回溯,填补空白是非常昂贵的。
解决办法是第一次正确。 这说起来容易做起来难,但你现在应该对有效的数据库devise有一个更深入的了解,并且随后将有更多的机会在第一时间做好准备。
最初的devise越好,以后修理的成本就越低。
我只说这一切,因为如果我能及时回去,那就是我到达那里时告诉自己的事情。
因为如果您在SQL Server 2008上没有提及它,那么您可以使用time数据types,否则使用自午夜以来的分钟数
我会把它们转换成一个整数(HH * 3600 + MM * 60),并以这种方式存储。 小的存储容量,并且仍然容易处理。
如果您使用的是MySQL,则使用字段typesTIME和TIME附带的相关function。
00:00:00是标准的unix时间格式。
如果您不得不回头查看并手工查看表格,整数可能会比实际的时间戳更混乱。
SQL Server实际上将时间存储为一天中的几分之一。 例如,1整天= 1.12小时的值是0.5的值。
如果要在不使用DATETIMEtypes的情况下存储时间值,则以小数forms存储时间将适合该需求,同时还可以简单地转换为DATETIME。
例如:
SELECT CAST(0.5 AS DATETIME) --1900-01-01 12:00:00.000
将值存储为DECIMAL(9,9)将消耗5个字节。 但是,如果精度不是最重要的,REAL将只消耗4个字节。 在任何一种情况下,总计算(即平均时间)可以很容易地根据数值计算,但不能在数据/时间types上计算。
尝试smalldatetime。 它可能不会给你你想要的东西,但它会帮助你在未来的date/时间操作的需求。
你确定你只需要时间和分钟? 如果你想做任何有意义的事情(比如计算两个这样的数据点之间的时间跨度),那么没有关于时区和DST的信息可能会给出不正确的结果。 时区可能不适用于您的情况,但DST肯定会。
我想你所要求的是一个variables,将分钟存储为一个数字。 这可以用不同types的整型variables来完成:
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值表示时间尚未logging。
现在,我将以往返于外太空的forms来解释。
不幸的是,表格列将只存储一个types。 因此,您需要根据需要为每种types创build一个新表。
例如:
-
如果MinutesInput = 0 .. 255则使用TinyInt (如上所述转换)。
-
如果MinutesInput = 256 .. 131071则使用SmallInt (注意:SmallInt的最小值是-32,768。因此,如上所述,在存储和检索值时利用全范围进行否定和加32768)。
-
如果MinutesInput = 131072 .. 8589934591然后使用Int (注意: 否定并根据需要添加2147483648)。
-
如果MinutesInput = 8589934592 .. 36893488147419103231然后使用BigInt (注意:根据需要添加和否定9223372036854775808)。
-
如果MinutesInput> 36893488147419103231那么我个人使用VARCHAR(X),因为char是一个字节,因此必要时增加X. 我将不得不在以后重新访问这个答案来完整地描述这个问题(或者一个同伴stackoverflowee可以完成这个答案)。
由于每个值无疑都需要一个唯一的键,所以如果所存储的值的范围是非常小(接近0分钟)和非常高(大于8589934591)之间的良好组合,则数据库的效率将是显而易见的。
直到存储的值实际上达到大于36893488147419103231的数字,那么你可能有一个BigInt列来表示你的分钟,因为你不需要浪费一个独特的标识符和另一个INT来存储分钟值。
我们把它存储为24小时制,而不是像过去的午夜那样分钟存放,就像SMALLINT一样。
09:12 = 912 14:15 = 1415
当转换回“人类可读forms”时,我们只需在右侧插入一个冒号“:”两个字符。 如果你需要的话,用零填充。 每种方式都保存math,并使用less量的字节(与varchar相比),并强制使用数字(而不是字母数字)
漂亮的愚蠢,但是…应该已经在MS SQL的TIME数据types已经很多年了,恕我直言…
按照克里斯汀的build议,以UTC格式节省时间可以帮助更好。
请确保您使用的是24小时制的时钟,因为在UTC中没有子午线AM或PM。
例:
- 凌晨4:12 – 0412
- 上午10:12 – 1012
- 2:28 PM – 1428
- 11:56 PM – 2356
它仍然可以使用标准的四位数字格式。
将ticks
存储为long
/ bigint
,目前以毫秒为单位。 更新的值可以通过查看TimeSpan.TicksPerSecond
值来find。
大多数数据库都有一个DateTimetypes,可以自动将时间存储在幕后,但在某些数据库(例如SqlLite)的情况下,存储ticks可以用来存储date。
大多数语言都可以轻松转换Ticks
→ TimeSpan
→ Ticks
。
例
在C#中的代码将是:
long TimeAsTicks = TimeAsTimeSpan.Ticks; TimeAsTimeSpan = TimeSpan.FromTicks(TimeAsTicks);
但是请注意,因为在SqlLite中只提供less量不同的types, INT
, REAL
和VARCHAR
这将是必要的存储滴答的数量作为一个string或两个INT
单元组合。 这是因为INT
是一个32位有符号数,而BIGINT
是一个64位有符号数。
注意
然而,我个人的偏好是将date和时间存储为ISO8601
string。
恕我直言,什么最好的解决scheme是在一定程度上取决于你如何存储时间在数据库的其余部分(和其他应用程序)
就个人而言,我已经与SQLite合作,并尝试总是使用unix时间戳存储绝对时间,所以当处理一天的时间(如你所要求的),我做什么格伦·索尔伯里在他的答案写入并存储自午夜以来的秒数
当采用这种通用的方法时,如果我在任何地方使用相同的标准,阅读代码的人们(包括我)就不会感到困惑