java Calendar类显示的时间与linux系统时间不同

时间:2015-08-04 07:00:47

标签: java timezone dst

使用RHEL系统,使用java 7。

$ java -version
java version "1.7.0_72"
Java(TM) SE Runtime Environment (build 1.7.0_72-b14)
Java HotSpot(TM) Server VM (build 24.72-b04, mixed mode)

date命令输出如下:

$ date
Tue Aug  4 08:48:08 METDST 2015

但是,通过以下Java程序,我得到的时间正好少了1个小时

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;

public class TimeInfo
{

  public static void main(String[] args)
  {
    Calendar cal = Calendar.getInstance();
    SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
    System.out.println("DateTime = " + fmt.format(cal.getTime()));

    TimeZone tz = Calendar.getInstance().getTimeZone();
    System.out.println("Time zone is: " + tz.getDisplayName() + ", timezone id = " + tz.getID());
    System.out.println(" DST = " + tz.getDSTSavings());

  }

}

输出:

DateTime = 08/04/2015 07:48:13
Time zone is: GMT+01:00, timezone id = GMT+01:00
 DST = 0

系统处于夏令时(从日期命令输出看)。但是,java Calendar类无法捕获它。试图打印时区,时区ID,DST等 - 但他们无法捕获DST生效。

如何以编程方式解决此问题(并且不对程序中的时区名称进行硬编码)?

1 个答案:

答案 0 :(得分:2)

诸如 METDST 之类的字符串不是时区。它们是夏令时 (DST) 是否在某个区域生效的模糊指标。但它们不是标准化的,甚至不是唯一的。最重要的是,我找不到任何对 METMETDST 区域的引用。

使用real time zones names。它们的格式为 Continent/Region

您正在使用糟糕的日期时间类,这些类现在已被 JSR 310 中定义的现代 java.time 类所取代。切勿使用 DateCalendar 和 { {1}}。

这些遗留类的众多问题之一是 SimpleDateFormat 方法。该类存储在 UTC 中看到的时刻,但其 Date#toString 方法在生成其文本时隐式应用 JVM 的当前默认时区。这是一个反功能,造成时区被存储在 toString 中的错觉,而实际上并没有。 (更糟糕的是,该类中一个时区,但与我们的讨论无关。)

我不确定您的问题,因为我不知道所涉及的实际时区。但该问题可能与 JVM 具有与主机操作系统不同的默认时区有关。此处要学习的课程:使用 UTC 工作。将 UTC(零时分秒的偏移量)视为唯一的真实时间。其他时区只是一个变化。您的日志记录、调试、数据交换和默认时区应采用 UTC。将桌面上的第二个时钟设置为 UTC(认真的)。

使用java.time

java.time 类内置于 Java 8 及更高版本中。您似乎在使用 Java 7。对于 Java 7,您可以通过将 ThreeTen-Backport 库添加到您的项目中来获得大部分 java.time 功能。在此答案中找到以下链接。

当前时刻

使用 Instant 类捕获以 UTC 显示的当前时刻。

Date

以标准 ISO 8601 格式生成文本。

Instant instant = Instant.now() ;

调整到时区以获取 ZonedDateTime 对象。

String output = instant.toString() ;

我们上面的变量 ZoneId z = ZoneId.of( "America/Edmonton" ) ; ZonedDateTime zdt = instant.atZone( z ) ; instant 代表时间轴上的同一时刻、同一点。它们的挂钟时间、日期和时间的感知因世界各地的时区而异。

夏令时

您的代码试图检查夏令时 (DST) 是否有效。为此,请使用时区 ZoneRules 对象中的 ZoneId

zdt

关于java.time

Table of all date-time types in Java, both modern and legacy

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

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

现在位于 Joda-Timemaintenance mode 项目建议迁移到 java.time 类。

您可以直接与您的数据库交换 java.time 对象。使用符合 JDBC driver 或更高版本的 JDBC 4.2。不需要字符串,不需要 ZoneId z = ZoneId.of( "Africa/Tunis" ) ; ZoneRules rules = z.getRules() ; boolean isDaylightSavingInEffectNow = rules.isDaylightSavings​( Instant.now() ) ; 类。 Hibernate 5 和 JPA 2.2 支持 java.time

从哪里获取 java.time 类?