将Java时区强制为GMT / UTC


95

无论计算机上设置的时区如何,我都需要对GMT / UTC进行任何与时间相关的操作。在代码中有任何方便的方法吗?

为了明确起见,我将所有操作都使用数据库服务器时间,但是它是根据本地时区格式化的。

谢谢!


实际上,他的问题是我的一个问题,但我找到了解决方案。
SyBer 2010年

查看重复的问题,然后搜索“ Joda”和“ DateTimeZone”。
Basil Bourque 2014年

Answers:


124

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

java -Duser.timezone=GMT ... <main-class>

如果从数据库检索Date / Time / Timestamp对象时需要设置特定的时区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
}

或者,在PreparedStatement中设置日期:

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

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

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);

有用的参考

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


为整个JVM设置时区时要注意的一件事是,它会影响所有内容,包括日志记录之类的内容。如果这是理想的效果,请记住一点。
Hermann Hans 2010年

是的,那很好。值得一提的是,我实际上直接在代码中设置了user.timezone,而不是通过-D参数。
SyBer 2010年

6
@SyBer:可以,但是您必须确保在任何方法调用TimeZone.getDefault()方法之前进行设置。否则,您会有些困惑,因为默认值是在第一次执行后被缓存的。这也意味着如果您在API /库中(从纯视图中隐藏)执行此操作,则可能会遇到问题-请确保大量记录正在执行的操作。
凯文·布洛克

23

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

System.setProperty("user.timezone", "EST");

-Duser.timezone=GMT在JVM参数中。


System.setProperty("user.timezone" ...)不起作用。
wilmol


9

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

TimeZone.setDefault(TimeZone.getTimeZone("GMT"))

没有犯罪行为,但是暂时修改全局静态状态听起来像是一个非常糟糕的主意...
G. Demecki

您可以,但不可以。这是非常糟糕的建议。整个JVM的时区已更改。
苏格兰,

1
有时候,这正是您想要实现的目标。例如。我已经看到基于Java的微服务始终与UTC一起运行以避免时区问题。在这些系统中,数据库后端也与UTC一起运行,因此自然也将JVM“强制”为UTC。重要的是:您必须知道自己在做什么以及会有什么后果……
snorbi

绝对不。如果您希望整个系统都使用UTC(一个很好的主意),请将系统时区设置为UTC,而不要使用Java时区。
苏格兰,苏格兰,

3
除非您有多个具有不同要求的JVM。我们可以永远争论不休,但每种情况都是唯一的:有时您需要设置整个系统的时区,有时只需要设置一个JVM。让我们感到高兴的是,当今的系统是如此灵活,以至于我们都可以做到
snorbi

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"));
  }

然后使用其他时区格式化日期。


6

我会以原始格式(较长的时间戳或java的Date)从数据库中检索时间,然后使用SimpleDateFormat对其进行格式化,或使用Calendar对其进行处理。在这两种情况下,都应在使用对象之前设置对象的时区。

请参阅SimpleDateFormat.setTimeZone(..)Calendar.setTimeZone(..)了解详细信息


6

tl; dr

String sql = "SELECT CURRENT_TIMESTAMP ;

OffsetDateTime odt = myResultSet.getObject( 1 , OffsetDateTime.class ) ;

避免依赖主机OS或JVM作为默认时区

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

java.time

其他一些答案是正确的,但现在已过时。与最早的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.

ZonedDateTime

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

ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

数据库

您提到一个数据库。

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

OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;

在大多数数据库和驱动程序中,我想您将获得UTC所展现的瞬间。但是,如果没有,则可以通过以下两种方式进行调整:

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

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


关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代麻烦的老传统日期时间类,如java.util.DateCalendar,和SimpleDateFormat

要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

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

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

在哪里获取java.time类?


1

创建一对客户端/服务器,以便执行后,客户端服务器发送正确的时间和日期。然后,客户端要求服务器pm GMT,服务器将正确的答案发送回去。



1

在MySQL中执行以下行以重置您的时区:

SET @@global.time_zone = '+00:00';

0

哇。我知道这是一个古老的线程,但是我只能说不要在任何用户级代码中调用TimeZone.setDefault()。这总是为整个JVM设置时区,几乎总是一个非常糟糕的主意。学习使用joda.time库或Java 8中新的DateTime类,它与joda.time库非常相似。


-6

如果您只想使用Intiger来获取GMT时间:var currentTime = new Date(); var currentYear ='2010'var currentMonth = 10; var currentDay = '30'var currentHours = '20'var currentMinutes = '20'var currentSeconds = '00'var currentMilliseconds = '00'

currentTime.setFullYear(currentYear);
currentTime.setMonth((currentMonth-1)); //0is January
currentTime.setDate(currentDay);  
currentTime.setHours(currentHours);
currentTime.setMinutes(currentMinutes);
currentTime.setSeconds(currentSeconds);
currentTime.setMilliseconds(currentMilliseconds);

var currentTimezone = currentTime.getTimezoneOffset();
currentTimezone = (currentTimezone/60) * -1;
var gmt ="";
if (currentTimezone !== 0) {
  gmt += currentTimezone > 0 ? ' +' : ' ';
  gmt += currentTimezone;
}
alert(gmt)

5
在我看来就像JavaScript(!= Java)。
菲尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.