用于UTC或带时区的时间戳的SQL标准
我正在寻找一种标准的SQL方法,以确保独立于数据库的列具有UTC时间戳或具有时区信息的时间戳。 在DB-column中存储时间戳UTC的UTC示例:
-
存储的UTC值= 2014-01-01 15:30:00.000
当地时间印度21:00 / 9pm当地时间戳“2014-01-01 21:00:00.000”
-
存储的UTC值= 2013-12-31 23:30:00.000
当地时间印度05:00 / 5am当地时间戳“2014-01-01 05:00:00.000”
在UTC方式中,应用程序必须处理时间分区
现在我不知道可能的方式,时间戳和时区具有上述值
-
存储的本地值= 2014-01-01 21:00:00.000
当地时间印度21:00 / 9pm当地时间戳“2014-01-01 21:00:00.000”
但是有时区信息吗?
或者如何获取此时间戳的时区信息?
-
存储的本地值= 2014-01-01 05:00:00.000
当地时间印度05:00 / 5am当地时间戳“2014-01-01 05:00:00.000”
但是有时区信息吗?
或者如何获取此时间戳的时区信息?
希望有人可以帮助我摆脱黑暗? 是否存在关于时间问题和存储数据以供国际应用的良好实践?
TL;博士
要存储片刻,时间轴上的一个点,请定义SQL标准类型TIMESTAMP WITH TIME ZONE
的数据库列。
以UTC格式存储片刻。
Instant instant = Instant.now() ; // Capture the current moment in UTC. myPreparedStatement.setObject( … , instant ) ;
检索UTC时刻。
Instant instant = myResultSet.getObject( … , Instant.class ) ;
从UTC调整到时区。 同一时刻,不同的挂钟时间。
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ; // Specify time zone in proper `Continent/Region` name, never the ambiguous non-standard 3-4 letter pseudo-zone such as `IST` or `PST`. ZonedDateTime zdt = instant.atZone( z ) ;
从时区调整为UTC。 同一时刻,不同的挂钟时间。
Instant instant = zdt.toInstant() ;
日期时间不是字符串
严重数据库不会将日期时间值存储为字符串。 不要将数据库或Java库生成的字符串表示与日期时间值本身混淆。
存储UTC
最佳做法是将UTC用于数据库和其他存储,以及大部分业务逻辑。 仅在用户期望的当地时区中出现 。
有关标准日期时间类型,请参阅Wikipedia。 即使您不使用Postgres,也请查阅有关日期时间数据类型的优秀文档 。 但我确实推荐Postgres,原因很多,包括它对日期时间的出色支持。
使用TIMESTAMPZ
这位Postgres专家提出了简单而明智的建议: 始终使用TIMESTAMP和TIME ZONE
该数据类型的名称用词不当 ,造成了如此多的混乱。 不存储时区信息。 这意味着使用传入数据指示的时区,并将存储的值调整为UTC 。 将TIMESTAMP WITH TIME ZONE
考虑为具有TIMESTAMP WITH TIME ZONE
TIMESTAMP WITH RESPECT FOR TIME ZONE
。 大声重读这段三次,然后阅读上面的链接,并做一些实验,以确保你理解。
您可能还想单独存储原始时区信息。 不用于业务逻辑,而是用作调试的日志信息。
Java的
至于Java,请务必避免使用java.util.Date和.Calendar类。 众所周知,它们很麻烦。 它们在Java 8中被新的java.time包取代。 使用该软件包和/或启发java.time的Joda-Time 2.4库。
时区
在Java中始终指定所需的时区。 如果省略,您将隐式使用JVM的当前默认时区。 隐式默认值意味着您的结果会随时间和空间而变化。 这是日期工作中很多麻烦的根本原因。 如果您想要UTC,请使用Joda-Time, DateTimeZone.UTC
的常量。
忽略时区不会让您的生活更轻松。
ISO 8601
该标准非常有用且合理。 研究优秀的维基百科页面 。 应该是String表示的首选。
搜索StackOverflow
数百个(如果不是数千个)答案已涵盖这些问题。