Java 时区问题:如果JVM时区为UTC,则转换为UTC

Java 时区问题:如果JVM时区为UTC,则转换为UTC,java,timezone,java-7,timestamp-with-timezone,Java,Timezone,Java 7,Timestamp With Timezone,由于我们应用程序中的时区问题,我面临一些问题 我们有一些相互依赖的服务,这些服务给我们提供了最短的时间。我们在EST时区,所以之前没有任何问题。最近,我们转到UTC时区,开始看到这个问题。对于我们来说,我们可能会再次来回(EST/UTC) 所以我想做的是检查我的JVM时区,如果我的时区是UTC,我想将依赖服务的时间转换为UTC,如果我们在EST中,我什么也不做,因为依赖服务总是用EST响应。我如何做到这一点 Data1.java XMLGregorianCalendar date; XMLGre

由于我们应用程序中的时区问题,我面临一些问题

我们有一些相互依赖的服务,这些服务给我们提供了最短的时间。我们在EST时区,所以之前没有任何问题。最近,我们转到UTC时区,开始看到这个问题。对于我们来说,我们可能会再次来回(EST/UTC)

所以我想做的是检查我的JVM时区,如果我的时区是UTC,我想将依赖服务的时间转换为UTC,如果我们在EST中,我什么也不做,因为依赖服务总是用EST响应。我如何做到这一点

Data1.java

XMLGregorianCalendar date;
XMLGregorianCalendar time;
//getter & setter
Util.java

String convertDate(Date d){
    SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
            try {
                 String converted= dateFormat.format(d);
                return converted;
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
    }

    String convertTime(Date d){
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
            String Time = "";
            Time =  sdf.format(d);
            return Time;
    }
}
MyApp.java

String date = Util.convertDate(data1.getDate.toGregorianCalendar().getTime())
String time = Util.convertTime(data1.getDate.toGregorianCalendar().getTime())
这里的日期和时间字符串包含EST日期和时间,如果JVM时区是UTC,我想将其更改为UTC,并将其保持为JVM时区是EST

现有输出示例:

日期:2017-08-02
时间:21:04:04

预期:

日期:2017-08-03
时间:01:04:04


一个
java.util.Date
对象。它只保留一个
long
值,该值表示自unix纪元以来的毫秒数(
1970-01-01T00:00Z

使用
SimpleDataFormat
格式化日期时,格式化程序使用系统的默认时区将毫秒值转换为人类可读的值(天/月/年/小时/分钟/秒)

如果您得到的是
2017-08-02 21:04:04
,这意味着运行代码的JVM中的默认时区是EST(从技术上讲,
EST
实际上不是一个时区,下面将详细介绍)。如果希望将输出转换为UTC,则必须在格式化程序中进行设置:

Date date = // Date corresponding to 2017-08-03 01:04:04 UTC (or 2017-08-02 21:04:04 EDT)

// date format
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
// set UTC
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(dateFormat.format(date)); // 2017-08-03

// time format
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
// set UTC
timeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(timeFormat.format(date)); // 01:04:04
输出将是:

2017-08-03
01:04:04

要获取EST的值,只需更改时区:

// date format
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
// set to EST
dateFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println(dateFormat.format(date));

// time format
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
// set to EST
timeFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println(timeFormat.format(date));
// convert to UTC
ZonedDateTime zdt = inst.atZone(ZoneOffset.UTC);

// or convert to a timezone
ZonedDateTime zdt = inst.atZone(ZoneId.of("America/New_York"));
输出将是:

2017-08-02
21:04:04

请注意,我使用了
America/New_York
,因为
EST
产生了不正确的结果。理想情况是始终使用(始终采用
地区/城市
格式,如
美国/纽约
欧洲/柏林
)。 避免使用三个字母的缩写(如
EST
PST
),因为它们是

有,因此您可以将
美国/纽约
更改为最适合您的系统的时区。通过调用
TimeZone.getAvailableIDs()
,可以获得可用时区的列表

要检查默认时区,您可以使用
timezone.getDefault().getID()
,并检查它是
UTC
还是
GMT
(这样您就知道要使用哪种格式-尽管建议在内部使用UTC,并且仅在向用户显示值时转换为时区)

取决于默认时区并不理想,因为它可以在任何时候更改,甚至在运行时,或者由于其他人的错误配置(我以前遇到过类似的情况,这不是一件好事)。但是,您似乎没有选择余地,只需检查
getID()
返回的值,然后根据该值决定要做什么


Java新的日期和时间API 旧类(
Date
Calendar
SimpleDateFormat
)具有和,它们正在被新的API所取代

如果使用<强> java 8 < />,请考虑使用这更容易

如果您使用的是Java
EST
不是时区 媒体上出现的3-4个字母的伪时区不是真正的时区。它们没有标准化,甚至不是唯一的(!)

大陆/地区
的格式指定,例如,或
太平洋/奥克兰

ZoneId z = ZoneId.of( "America/New_York" );
避免
XMLGregorianCalendar
尽可能避免使用
XMLGregorianCalendar
。与传统的
Date
&
Calendar
&
gregoriacalendar
类一样,这些类现在被高级java.time类取代

永远不要依赖默认时区 依赖主机操作系统的默认时区是错误的做法,因为作为程序员,这超出了您的控制范围

同样,依赖JVM的当前默认时区也是一种糟糕的做法,因为这也超出了您的控制范围。JVM中任何应用程序的任何线程中的任何代码都可以在运行时更改当前默认值

听起来您的人希望使用主机操作系统的当前默认时区作为改变应用程序行为的信号。非常奇怪和笨拙的策略。您还有许多其他可用的路由:配置文件、等等

获取当前默认时区 我知道JVM无法直接访问主机操作系统当前的默认时区。您可以通过命令行实用程序或类似的工具进行迂回操作

您可以获得JVM的当前默认值。我所熟悉的大多数Java实现都默认将JVM设置为主机操作系统的默认值

ZoneId z = ZoneId.systemDefault() ;
转换为java.time 如果给您一个对象,请转换为via

调整到所需/预期时区 从该
ZonedDateTime
中提取一个
即时
。该类表示时间线上的一个时刻,分辨率为(小数点的九(9)位)

应用你想要的任何时区。对于UTC,使用
OffsetDateTime

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
获取标准ISO 8601格式的日期和时间字符串

String outputDate = odt.toLocalDate().toString() ;
String outputTime = odt.toLocalTime().toString() ;
String outputDate = zdt.toLocalDate().toString() ;
String outputTime = zdt.toLocalTime().toString() ;
对于时区,而不仅仅是与UTC的偏移,请使用
ZonedDateTime
。对于美国东海岸,也许你想要
美国/纽约

ZonedDateTime zdt = instant.atZone( ZoneId.of( "America/New_York" ) ) ;
生成标准ISO 8601格式的字符串

String outputDate = odt.toLocalDate().toString() ;
String outputTime = odt.toLocalTime().toString() ;
String outputDate = zdt.toLocalDate().toString() ;
String outputTime = zdt.toLocalTime().toString() ;

关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

您可以直接与dat交换java.time对象
String outputDate = odt.toLocalDate().toString() ;
String outputTime = odt.toLocalTime().toString() ;
ZonedDateTime zdt = instant.atZone( ZoneId.of( "America/New_York" ) ) ;
String outputDate = zdt.toLocalDate().toString() ;
String outputTime = zdt.toLocalTime().toString() ;