这是从日期获取 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 21:53:57  来源:igfitidea点击:

Is this the correct way to obtain a java.sql.Timestamp at UTC from a Date?

javajava-8java-time

提问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 TIMESTAMPin your DB, you need to create a Java Timestampthat 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 LocalDateTimeof 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 ZONEfield 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 Timestampwill 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 Timestampinto a TIMESTAMP(i.e. without time zone) field, the jdbc driver will calculate the date/time corresponding to your Timestampin the default time zone (unless a Calendaris explicitly provided) - so your DB will show Sunday 8th November at 8pm
  • a java.time.Instantis similar to a Java Timestamp: it represents a unique point in time, without time zone information
  • a LocalDateTimeis like a sql TIMESTAMP, 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 ZonedDateTimeis essentially a LocalDateTime+ 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 OffsetDateTimeis essentially a LocalDateTime+ an offset vs. UTC. For example Sunday 8th November 8pm +01:00. That identifies a unique instant in time.
  • JavaTimestamp将是自纪元以来的毫秒数,即它代表您发布问题的时间线上的唯一时刻,并且没有任何时区信息
  • 将其存储TimestampTIMESTAMP(即没有时区)字段时,jdbc 驱动程序将计算与您Timestamp在默认时区中对应的日期/时间(除非Calendar明确提供了 a)-因此您的数据库将显示 11 月 8 日星期日晚上 8 点
  • ajava.time.Instant类似于 Java Timestamp:它代表一个唯一的时间点,没有时区信息
  • aLocalDateTime就像一个 sql TIMESTAMP,它说,例如,11 月 8 日星期日晚上 8 点,但你不知道没有额外时区信息的时间点
  • aZonedDateTime本质上是 a LocalDateTime+ a 时区。例如,11 月 8 日星期日晚上 8 点 [欧洲/巴黎] - 通常标识一个独特的时刻,但不一定(想想当 DST 时钟向后更改并且同一小时重复两次时)。
  • anOffsetDateTime本质上是 a LocalDateTime+ an offset vs. UTC。例如,11 月 8 日星期日晚上 8 点 +01:00。这标识了一个独特的时刻。

The standard approach is generally to store an instant as a sql TIMESTAMP WITH TIME ZONEand use either a Timestampor an OffsetDateTimeon 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.Timestampnor java.time.Instanthave 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);