当前位置: 首页 > 知识库问答 >
问题:

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

白修谨
2023-03-14

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

我们有一些相互依赖的服务,这些服务给我们提供了最短的时间。我们在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

预期:

Date: 2017-08-03
time: 01:04:04

共有2个答案

张翰海
2023-03-14

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

大陆/地区的格式指定适当的时区名称,例如美国/蒙特利尔非洲/卡萨布兰卡,或太平洋/奥克兰

ZoneId z = ZoneId.of( "America/New_York" );

尽可能避免使用XMLGregorianCalendar。就像传统的Date

依赖主机操作系统的默认时区是错误的做法,因为作为html" target="_blank">程序员,这超出了您的控制范围。

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

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

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

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

ZoneId z = ZoneId.systemDefault() ;

如果给您一个XMLGregorianCalender对象,请通过GregorianCalender转换为java.time.ZonedDateTime

GregorianCalendar gc = myXMLGregorianCalendar.toGregorianCalendar() ;
ZonedDateTime zdt = gc.toZonedDateTime() ;

从该ZonedDateTime中提取一个即时Instant类以UTC表示时间线上的一个时刻,分辨率为纳秒(最多九(9)位小数)。

Instant instant = zdt.toInstant() ;

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

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;

去约会

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

对于时区,而不仅仅是UTC偏移量,请使用ZonedDateTime。对于美国东海岸,也许你想要America/New_York

ZonedDateTime zdt = instant.atZone( ZoneId.of( "America/New_York" ) ) ;

生成标准ISO 8601格式的字符串。

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

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

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

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

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

从哪里获得java.time类?

  • JavaSE 8,JavaSE 9,JavaSE 10,JavaSE 11,以及更高版本-标准JavaAPI的一部分,具有捆绑实现。
    • Java9增加了一些小功能和修复。
    • 大部分java.time功能都被向后移植到Java6
    • java.time类的Android捆绑包实现的更高版本。
    • 对于早期的Android(

    ThreePre-Extra项目扩展java.time附加类。这个项目是未来可能添加到java.time.的试验场。您可以在这里找到一些有用的类,如IntervalYear轮YearQUter等。

澹台衡
2023-03-14

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

输出将是:

2017-08-02
21:04:04

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

有许多不同的时区使用EST作为“短名称”,因此您可以将America/New_York更改为最适合您系统的时区。通过调用TimeZone.getAvailableIDs(),可以获得可用时区的列表。

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

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

旧类(DateCalendarSimpleDateFormat)存在许多问题和设计问题,它们正在被新的API所取代。

如果使用java 8,考虑使用新的javaTimeAPI。与旧的API相比,它更容易实现,更少出现错误,更不容易出错。

如果你用Java

下面的代码适用于两者。唯一的区别是包名称(在Java8中是java.time,在Threeten Backport(或Android的ThreeTenABP)中是org.threeten.bp),但是类和方法名称是一样。

首先,您将GregorianCalendar转换为Instant

// convert calendar
Instant inst = Instant.ofEpochMilli(data1.getDate.toGregorianCalendar().getTimeInMillis());

在Java 8中,GregorianCalendar有一种方法可以直接进行转换:

Instant inst = data1.getDate.toGregorianCalendar().toInstant();

然后,您可以将瞬间转换为时区:

// convert to UTC
ZonedDateTime zdt = inst.atZone(ZoneOffset.UTC);

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

然后,您可以使用DateTimeFormatter对其进行格式化:

DateTimeFormatter dateFmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter timeFmt = DateTimeFormatter.ofPattern("HH:mm:ss");

System.out.println(dateFmt.format(zdt));
System.out.println(timeFmt.format(zdt));

这将产生与上述相同的输出。

您还可以使用ZoneId.systemDefault().getId()检查JVM默认时区,并检查它是UTC还是GMT

 类似资料:
  • 我有当前的毫秒utc/unix时间,现在我想将其转换为特定时区的日期时间,例如EST utc-5(纽约)。 我使用以下方法获得当前的毫秒/ unix时间: 现在我想把这个长值转换成一个特定的时区。 我如何使用 Joda time 做到这一点,因为我听说这是最好的库,但 API 对我来说似乎有点混乱。

  • 问题内容: 这是我的约会日期“ 15-05-2014 00:00:00” 如何将IST转换为UTC即(到14-05-2014 18:30:00) 基于时区到UTC时区。 我的代码是 如果用户从任何区域输入相同的日期,则将获得UTC时间(例如:从澳大利亚,然后从15-05-2014 00:00:00到14-05-2014 16:00:00) 请任何建议。 问题答案: 您不能将日期值“转换为”其他时区

  • > 如何将IST转换为UTC,即(至2014年5月14日18:30:00) 我的代码是 > 如果用户从任何区域输入相同的日期,则将获得UTC时间(例如:从澳大利亚输入,然后是2014年5月15日00:00:00至2014年5月14日16:00:00) 请提出任何建议。

  • 问题内容: 我有一个UTC时区,例如: 还有一个pytz时区对象: 转换为给定时区的正确方法是什么? 问题答案: 我想我明白了: 这行代码首先将朴素的(不了解时区的) 对象转换为包含时区(UTC)的对象。然后,它使用该功能根据请求的时区调整时间。

  • 编辑:对不起,也许我的问题不对。。。。 我正在尝试将UTC时间戳转换为Java(Kotlin)中的本地时间戳 f、 exm。 UTC时间18:00德国当地时间是20:00我需要UTC时间戳中的德国当地时间。。。。。 返回UTC时间:( 如何在特定时区将即时UTC转换为Pochmilli

  • 我做了下面的代码,但我知道它是正确的或不是,请协助我做正确的方式时区转换。 我把UTC日期作为json字符串,转换成用户的时区格式,并显示Android端