java Calendar 类显示的时间与 linux 系统时间不同
Posted
技术标签:
【中文标题】java Calendar 类显示的时间与 linux 系统时间不同【英文标题】:java Calendar class shows different time than linux system time 【发布时间】:2015-10-26 11:14:26 【问题描述】:使用 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
系统处于夏令时状态(从 date 命令输出中可以看出)。但是,java Calendar 类无法捕捉到这一点。尝试打印时区、时区 ID、DST 等 - 但他们无法捕捉到 DST 是否有效。
如何以编程方式解决此问题(并且无需在程序中硬编码时区名称)?
【问题讨论】:
在谷歌上找到这个,可能有帮助:How to get java Date with Daylight savings @BackSlash:抱歉,那里描述的解决方案对我不起作用。一个硬编码时区(我不想要),另一个调用 getTimeZone() 的日历,这在我的代码中已经不起作用。 存在一些与在各种 Linux 发行版上选择默认时区相关的 Java 错误(例如 this one)。请将您的 JRE 更新到当前版本,看看问题是否仍然存在。 我建议你不要使用Calendar
、SimpleDateFormat
和TimeZone
。这些类设计不佳且早已过时,SimpleDateFormat
特别是出了名的麻烦。而是使用ZonedDateTime
、DateTimeFormatter
和ZoneId
,均来自java.time, the modern Java date and time API。
【参考方案1】:
METDST
等字符串不是时区。它们是夏令时 (DST) 是否有效的模糊指标。但它们不是标准化的,甚至不是唯一的。最重要的是,我找不到任何对 MET
或 METDST
区域的引用。
使用real time zones names。它们的格式为Continent/Region
。
您正在使用糟糕的日期时间类,这些类现在已被 JSR 310 中定义的现代 java.time 类所取代。切勿使用 Date
、Calendar
和 SimpleDateFormat
。
这些遗留类的许多问题之一是Date#toString
方法。该类存储 UTC 中的时刻,但其 toString
方法在生成其文本时隐式应用 JVM 的当前默认时区。这是一个反特征,会造成时区存储在Date
中的错觉,而实际上并没有。 (更糟糕的是,在该类中有一个时区,但与我们的讨论无关。)
我不确定您的问题,因为我不知道所涉及的实际时区。但问题可能与 JVM 的默认时区与主机操作系统不同。这里要学习的一课:使用 UTC。 将 UTC(零时分秒的偏移量)视为一个真实时间。其他时区只是一个变化。您的日志记录、调试、数据交换和默认时区应采用 UTC。把你桌上的第二个时钟设置为 UTC(真的)。
使用java.time
java.time 类内置于 Java 8 及更高版本中。您似乎正在使用 Java 7。对于 Java 7,您可以通过将 ThreeTen-Backport 库添加到您的项目来获得大部分 java.time 功能。在此答案中找到以下链接。
当前时刻
使用Instant
类捕捉UTC 中的当前时刻。
Instant instant = Instant.now() ;
以标准 ISO 8601 格式生成文本。
String output = instant.toString() ;
调整到时区以获取ZonedDateTime
对象。
ZoneId z = ZoneId.of( "America/Edmonton" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
我们上面的变量instant
和zdt
代表同一时刻,时间轴上的同一点。它们的挂钟时间不同,对日期和时间的感知在世界各地因时区而异。
夏令时
您的代码试图检查夏令时 (DST) 是否有效。为此,请使用来自时区 ZoneId
对象的 ZoneRules
。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZoneRules rules = z.getRules() ;
boolean isDaylightSavingInEffectNow = rules.isDaylightSavings( Instant.now() ) ;
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date
、Calendar
和 SimpleDateFormat
。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.*
类。 Hibernate 5 & JPA 2.2 支持 java.time。
从哪里获取 java.time 类?
Java SE 8、Java SE 9、Java SE 10、Java SE 11 和更高版本 - 具有捆绑实现的标准 Java API 的一部分。 Java 9 带来了一些小功能和修复。 Java SE 6 和 Java SE 7 大部分 java.time 功能在ThreeTen-Backport 中向后移植到 Java 6 和 7。 Android java.time 类的更高版本的 android (26+) 捆绑实现。 对于早期的 Android (API desugaring 的进程带来了最初未内置于 Android 中的 subset of the java.time 功能。 如果脱糖不能满足您的需求,ThreeTenABP 项目会将ThreeTen-Backport(如上所述)适配到 Android。见How to use ThreeTenABP…。【讨论】:
以上是关于java Calendar 类显示的时间与 linux 系统时间不同的主要内容,如果未能解决你的问题,请参考以下文章
Java学习笔记4.5.1 日期时间 - Date类与Calendar类