强制Java时区为GMT/UTC

SyB*_*Ber 87 java timezone utc gmt

无论机器上设置的时区如何,我都需要强制任何与GMT/UTC相关的操作.在代码中有任何方便的方法吗?

为了澄清,我正在使用数据库服务器时间进行所有操作,但它是根据本地时区格式化的.

谢谢!

Kev*_*ock 114

OP回答了这个问题以更改正在运行的JVM的单个实例的默认时区,设置user.timezone系统属性:

java -Duser.timezone=GMT ... <main-class>
Run Code Online (Sandbox Code Playgroud)

如果在从数据库中检索日期/时间/时间戳对象时需要设置特定时区ResultSet,请使用getXXX获取Calendar对象的方法的第二种形式:

Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
ResultSet rs = ...;
while (rs.next()) {
    Date dateValue = rs.getDate("DateColumn", tzCal);
    // Other fields and calculations
}
Run Code Online (Sandbox Code Playgroud)

或者,在PreparedStatement中设置日期:

Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
PreparedStatement ps = conn.createPreparedStatement("update ...");
ps.setDate("DateColumn", dateValue, tzCal);
// Other assignments
ps.executeUpdate();
Run Code Online (Sandbox Code Playgroud)

这些将确保当数据库列不保留时区信息时,存储在数据库中的值是一致的.

java.util.Datejava.sql.Date类存储在UTC的实际时间(毫秒).要将输出格式化为另一个时区,请使用SimpleDateFormat.您还可以使用Calendar对象将时区与值相关联:

TimeZone tz = TimeZone.getTimeZone("<local-time-zone>");
//...
Date dateValue = rs.getDate("DateColumn");
Calendar calValue = Calendar.getInstance(tz);
calValue.setTime(dateValue);
Run Code Online (Sandbox Code Playgroud)

有用的参考

https://docs.oracle.com/javase/9​​/troubleshoot/time-zone-settings-jre.htm#JSTGD377

https://confluence.atlassian.com/kb/setting-the-timezone-for-the-java-environment-841187402.html

  • @SyBer:这有效但你必须确保在任何方法调用TimeZone.getDefault()方法之前设置它.如果不是,您将会有一些混淆,因为默认值在第一次执行后被缓存.这也意味着如果您在API /库中执行此操作(从普通视图中隐藏)可能会出现问题 - 请务必记录您正在执行的操作. (6认同)
  • 关于为整个 JVM 设置时区需要注意的一件事是,它会影响一切,包括日志记录等。如果这是想要的效果,请记住一些事情。 (2认同)

MG *_*per 23

此外,如果您可以这种方式设置JVM时区

System.setProperty("user.timezone", "EST");
Run Code Online (Sandbox Code Playgroud)

或者-Duser.timezone=GMT在JVM中.


小智 10

我不得不为Windows 2003 Server设置JVM时区,因为它总是为新的Date()返回GMT;

-Duser.timezone=America/Los_Angeles

或者你适当的时区.找到时区列表证明也有点挑战......

这是两个清单;

http://wrapper.tanukisoftware.com/doc/english/prop-timezone.html

http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzatz%2F51%2Fadmin%2Freftz.htm


lwp*_*ro2 8

对我来说,只需快速SimpleDateFormat,

  private static final SimpleDateFormat GMT = new SimpleDateFormat("yyyy-MM-dd");
  private static final SimpleDateFormat SYD = new SimpleDateFormat("yyyy-MM-dd");
  static {
      GMT.setTimeZone(TimeZone.getTimeZone("GMT"));
    SYD.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
  }
Run Code Online (Sandbox Code Playgroud)

然后使用不同的时区格式化日期.


Daw*_*ień 8

使用系统属性:

-Duser.timezone=UTC
Run Code Online (Sandbox Code Playgroud)

  • 为什么要使用它?请在您的答案中添加一些解释,以便其他人可以从中学习 (6认同)

Bas*_*que 8

tl;博士

String sql = "SELECT CURRENT_TIMESTAMP ;
…
OffsetDateTime odt = myResultSet.getObject( 1 , OffsetDateTime.class ) ;
Run Code Online (Sandbox Code Playgroud)

避免依赖主机操作系统或 JVM 作为默认时区

我建议您编写所有代码以明确说明所需/预期的时区。您不需要依赖 JVM 的当前默认时区。而且要知道,JVM当前的默认时区可以改变在任何时刻运行过程中的任何应用程序调用的任何线索,有任何代码TimeZone.setDefault。这样的调用会立即影响该 JVM 中的所有应用程序。

时间

其他一些答案是正确的,但现在已经过时了。与最早版本的 Java 捆绑在一起的糟糕的日期时间类存在缺陷,它们是由不了解日期时间处理的复杂性和微妙之处的人编写的。

遗留的日期时间类已被JSR 310 中定义的java.time类取代。

要表示时区,请使用ZoneId。要表示与 UTC 的偏移量,请使用ZoneOffset. 偏移量只是本初子午线之前或之后的若干小时-分钟-秒数。时区要多得多。时区是特定地区人民使用的偏移量的过去、现在和未来变化的历史记录。

我需要将任何与时间相关的操作强制为 GMT/UTC

对于零时分秒的偏移量,请使用常量ZoneOffset.UTC

Instant

要以 UTC 格式捕获当前时刻,请使用Instant. 此类代表 UTC 中的一个时刻,根据定义始终使用 UTC。

Instant instant = Instant.now() ;  // Capture current moment in UTC.
Run Code Online (Sandbox Code Playgroud)

ZonedDateTime

要通过特定地区的人们使用的挂钟时间查看同一时刻,请调整到时区。同一时刻,时间线上的同一点,不同的挂钟时间。

ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Run Code Online (Sandbox Code Playgroud)

数据库

你提到了一个数据库。

要从数据库中检索片刻,您的列应该是类似于 SQL 标准的数据类型TIMESTAMP WITH TIME ZONE。检索对象而不是字符串。在 JDBC 4.2 及更高版本中,我们可以与数据库交换java.time对象。该OffsetDateTime由JDBC要求,而InstantZonedDateTime是可选的。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Run Code Online (Sandbox Code Playgroud)

在大多数数据库和驱动程序中,我猜你会得到在 UTC 中看到的时刻。但如果没有,您可以通过以下两种方式之一进行调整:

  • 提取一个Instantodt.toInstant()
  • 从给定的偏移量调整到零偏移量:OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC ) ;`。

Java(旧版和现代版)和标准 SQL 中的日期时间类型表


关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

现在处于维护模式Joda-Time项目建议迁移到java.time类。

您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*

从哪里获得 java.time 类?


Eya*_*der 6

我将以原始形式(长时间戳或java的日期)从DB中检索时间,然后使用SimpleDateFormat对其进行格式化,或使用Calendar来操作它.在这两种情况下,您应该在使用之前设置对象的时区.

查看SimpleDateFormat.setTimeZone(..)Calendar.setTimeZone(..)了解详情


sno*_*rbi 5

您可以使用TimeZone.setDefault()更改时区:

TimeZone.setDefault(TimeZone.getTimeZone("GMT"))
Run Code Online (Sandbox Code Playgroud)

  • 除非您有多个具有不同要求的 JVM。我们可以争论不休,但每种情况都是独一无二的:有时您需要设置整个系统的时区,有时您只设置一个 JVM 的时区。让我们高兴的是,今天的系统非常灵活,我们可以同时做到 (5认同)
  • 有时,这正是您想要实现的目标。例如。我已经看到基于 Java 的微服务始终使用 UTC 运行以避免时区问题。在这些系统中,数据库后端也使用 UTC 运行,因此很自然地将 JVM 也“强制”为 UTC。重要的是:你必须知道你在做什么以及有什么后果...... (2认同)