这是从日期获取 UTC 时的 java.sql.Timestamp 的正确方法吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33594921/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is this the correct way to obtain a java.sql.Timestamp at UTC from a Date?
提问by fge
I develop a SonarQube plugin and for one of my needs I need to store the analysis date of a project as an SQL TIMESTAMP
(Please note:a TIMESTAMP
, and nota TIMESTAMP WITH TIMEZONE
).
我开发了一个 SonarQube 插件,为了满足我的一个需求,我需要将项目的分析日期存储为 SQL TIMESTAMP
(请注意:a TIMESTAMP
,而不是a TIMESTAMP WITH TIMEZONE
)。
Here is how I currently do it:
这是我目前的做法:
// In the SonarQube Sensor
// .getAnalysisDate() returns a java.util.Date
final Instant instant = module.getAnalysisDate().toInstant();
// Timestamp at UTC from the Instant
final LocalDateTime dt = LocalDateTime.frominstant(instant, ZoneOffset.UTC);
final Timestampt ts = Timestamp.valueOf(dt);
I have a little trouble grasping the concept of an Instant, there is also ZonedDateTime etc...
我在理解 Instant 的概念时有点困难,还有 ZonedDateTime 等......
Anyway, this seems to do what I want, but is it the correct way?
无论如何,这似乎是我想要的,但这是正确的方法吗?
采纳答案by assylias
To store a UTC TIMESTAMP
in your DB, you need to create a Java Timestamp
that represents the date of your report (say 8th November 7pm UTC), but in the local time zone without conversion(say 8th November 7pm CET). So your approach is correct: get the LocalDateTime
of the analysis date in UTC (8th November 7pm) and create a Timestamp in your local time zone at that LocalDateTime
.
要将 UTC 存储TIMESTAMP
在您的数据库中,您需要创建一个 JavaTimestamp
来表示您的报告日期(例如 UTC 时间 11 月 8 日晚上 7 点),但使用本地时区而不进行转换(例如欧洲中部时间11 月 8 日晚上 7 点)。所以你的方法是正确的:LocalDateTime
以UTC(11月8日晚上7点)获取分析日期,并在你当地的时区创建一个时间戳LocalDateTime
。
I don't think there is a shorter/better way to do it. If you used a sql TIMESTAMP WITH TIME ZONE
field you would not have to do any manipulations and Date.from(Instant)
would produce the correct result.
我认为没有更短/更好的方法来做到这一点。如果您使用了 sqlTIMESTAMP WITH TIME ZONE
字段,您将不必进行任何操作并Date.from(Instant)
会产生正确的结果。
Clarification of the concepts involved, using the time at which you posted your question as an example (Sunday 8th November 2015 at 7pm UTC) and assuming your local time zone is CET (Central European Time = UTC+1):
以您发布问题的时间为例(UTC 时间 2015 年 11 月 8 日星期日晚上 7 点)澄清所涉及的概念,并假设您的本地时区是 CET(欧洲中部时间 = UTC+1):
- the Java
Timestamp
will be the number of milliseconds since the epoch, i.e. it represents the unique instant on the time line at which you posted your question and does not have any time zone information - when storing that
Timestamp
into aTIMESTAMP
(i.e. without time zone) field, the jdbc driver will calculate the date/time corresponding to yourTimestamp
in the default time zone (unless aCalendar
is explicitly provided) - so your DB will show Sunday 8th November at 8pm - a
java.time.Instant
is similar to a JavaTimestamp
: it represents a unique point in time, without time zone information - a
LocalDateTime
is like a sqlTIMESTAMP
, it says, for example, Sunday 8th November 8pm, but you don't know what point in time that is without additional time zone information - a
ZonedDateTime
is essentially aLocalDateTime
+ a time zone. For example Sunday 8th November 8pm [Europe/Paris] - that generally identifies a unique instant but not necessarily (think of when clocks change backward for DST and the same hour is repeated twice). - an
OffsetDateTime
is essentially aLocalDateTime
+ an offset vs. UTC. For example Sunday 8th November 8pm +01:00. That identifies a unique instant in time.
- Java
Timestamp
将是自纪元以来的毫秒数,即它代表您发布问题的时间线上的唯一时刻,并且没有任何时区信息 - 将其存储
Timestamp
到TIMESTAMP
(即没有时区)字段时,jdbc 驱动程序将计算与您Timestamp
在默认时区中对应的日期/时间(除非Calendar
明确提供了 a)-因此您的数据库将显示 11 月 8 日星期日晚上 8 点 - a
java.time.Instant
类似于 JavaTimestamp
:它代表一个唯一的时间点,没有时区信息 - a
LocalDateTime
就像一个 sqlTIMESTAMP
,它说,例如,11 月 8 日星期日晚上 8 点,但你不知道没有额外时区信息的时间点 - a
ZonedDateTime
本质上是 aLocalDateTime
+ a 时区。例如,11 月 8 日星期日晚上 8 点 [欧洲/巴黎] - 通常标识一个独特的时刻,但不一定(想想当 DST 时钟向后更改并且同一小时重复两次时)。 - an
OffsetDateTime
本质上是 aLocalDateTime
+ an offset vs. UTC。例如,11 月 8 日星期日晚上 8 点 +01:00。这标识了一个独特的时刻。
The standard approach is generally to store an instant as a sql TIMESTAMP WITH TIME ZONE
and use either a Timestamp
or an OffsetDateTime
on the Java side of things.
标准方法通常是将瞬间存储为 sqlTIMESTAMP WITH TIME ZONE
并在 Java 方面使用 aTimestamp
或 an OffsetDateTime
。
回答by zapl
Timestamp.from(instant)
is all you should need.
Timestamp.from(instant)
这就是你所需要的。
Neither java.sql.Timestamp
nor java.time.Instant
have a timezone so you don't need to convert to UTC.
java.sql.Timestamp
既没java.time.Instant
有时区也没有时区,因此您无需转换为 UTC。
Alternatively directly from java.util.Date
或者直接从 java.util.Date
long millisSinceEpoch = module.getAnalysisDate().getTime();
Timestamp timestamp = new Timestamp(time);
回答by Lopotun
If performance matters, I would use the following:
如果性能很重要,我会使用以下内容:
final long timeAtLocal = module.getAnalysisDate(); // or System.currentTimeMillis(); or new Date().getTime(); etc.
final long offset = TimeZone.getDefault().getOffset(timeAtLocal);
final Timestamp timeAtUTC = new Timestamp(timeAtLocal - offset);