Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/383.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将时区设置为UTC,该时区已在UTC中_Java_Postgresql_Date_Xmlgregoriancalendar - Fatal编程技术网

Java 将时区设置为UTC,该时区已在UTC中

Java 将时区设置为UTC,该时区已在UTC中,java,postgresql,date,xmlgregoriancalendar,Java,Postgresql,Date,Xmlgregoriancalendar,我有一个将时区设置为UTC的应用程序,如下所示: // set default time zone to UTC TimeZone.setDefault(TimeZone.getTimeZone(ZoneOffset.UTC)); 这对于我们在数据库中存储为UTC的所有日期字段来说都很好。 但有一个日期已经以UTC表示,因此上述时区将再次以UTC表示 如何避免在UTC中再次设置 一些代码- public static void main(String[] args) throws Dataty

我有一个将时区设置为UTC的应用程序,如下所示:

// set default time zone to UTC
TimeZone.setDefault(TimeZone.getTimeZone(ZoneOffset.UTC));
这对于我们在数据库中存储为UTC的所有日期字段来说都很好。 但有一个日期已经以UTC表示,因此上述时区将再次以UTC表示

如何避免在UTC中再次设置

一些代码-

public static void main(String[] args) throws DatatypeConfigurationException {
        DatatypeFactory datatypeFactory  = DatatypeFactory.
         newInstance();
        // set default time zone to UTC
        TimeZone.setDefault(TimeZone.getTimeZone(ZoneOffset.UTC));
        // coming from external program in UTC but assigned it here for reference
        long someTimeToBeInUTC = 1528371000000L;
        GregorianCalendar start = new GregorianCalendar();
        start.setTimeInMillis(someTimeToBeInUTC);
        XMLGregorianCalendar startXmlCalendar  = 
        datatypeFactory.newXMLGregorianCalendar(start);
        System.out.println(startXmlCalendar.
        toGregorianCalendar().getTime());

    }
想象一下,我有一个时间瞬间
someTimeToBeInUTC
,与时区无关,然后因为行
timezone.setDefault(timezone.getTimeZone(ZoneOffset.UTC))
它以UTC设置它

然后在hibernate中,我在hbm.xml中拥有存储该值的表的属性-

<property name="startTime" type="timestamp">
            <column name="start_time" length="29" />
        </property>

startTime的类型是postgres中没有时区的时间戳。
因此,当我们保存时,它会再次将其转换为UTC。

毫秒时间与时区无关

以毫秒为单位的时间是精确的时间点,无论您在日历、日期或时间戳对象中的何处使用它

请仔细阅读Java文档。它始终表示从历元(1/1/1970 00:00:00 UTC)经过的毫秒数

时区仅在从这些对象使用其他表示时有效。e、 g.从toString()方法、从日历获取字段等)

更新 假设您的时间单位为千秒,
1528371250000L

然后您可以有两个日历(它们是时区感知的),一个是UTC日历,另一个是东部日历

请参阅完整的代码示例,以说明当两者中设置了以毫秒为单位的相同时间时会发生什么:

public static void main(String... args) throws Exception {

    Calendar utcCalendar = Calendar
            .getInstance(TimeZone.getTimeZone("UTC"));

    utcCalendar.setTimeInMillis(1528371250000L);

    System.out.println("UTC Calendar: \t\t" + (utcCalendar.get(Calendar.MONTH) +1)
            + "/" + utcCalendar.get(Calendar.DAY_OF_MONTH) + "/"
            + utcCalendar.get(Calendar.YEAR) + " "
            + utcCalendar.get(Calendar.HOUR_OF_DAY) + ":"
            + utcCalendar.get(Calendar.MINUTE) + ":"
            + utcCalendar.get(Calendar.SECOND) + " " + utcCalendar.getTimeZone().getID());

    Calendar eastCalendar = Calendar.getInstance(TimeZone
            .getTimeZone("EST"));

    eastCalendar.setTimeInMillis(1528371250000L);

    System.out.println("Eastern Calendar: \t"
            + (eastCalendar.get(Calendar.MONTH)+1) + "/"
            + eastCalendar.get(Calendar.DAY_OF_MONTH) + "/"
            + eastCalendar.get(Calendar.YEAR) + " "
            + eastCalendar.get(Calendar.HOUR_OF_DAY) + ":"
            + eastCalendar.get(Calendar.MINUTE) + ":"
            + eastCalendar.get(Calendar.SECOND) + " " + eastCalendar.getTimeZone().getID());

    XMLGregorianCalendar xmlUtcCalendar = DatatypeFactory.newInstance()
            .newXMLGregorianCalendar((GregorianCalendar) utcCalendar);

    System.out.println("XML UTC Calendar: \t" + xmlUtcCalendar.toString());

    XMLGregorianCalendar xmlEastCalendar = DatatypeFactory.newInstance()
            .newXMLGregorianCalendar((GregorianCalendar) eastCalendar);

    System.out.println("XML Eastern Calendar: \t" + xmlEastCalendar.toString());

}
输出:

 UTC Calendar:          6/7/2018 11:34:10 UTC
 Eastern Calendar:      6/7/2018 6:34:10 EST
 XML UTC Calendar:      2018-06-07T11:34:10.000Z
 XML Eastern Calendar:  2018-06-07T06:34:10.000-05:00

以毫秒为单位的时间与时区无关

以毫秒为单位的时间是精确的时间点,无论您在日历、日期或时间戳对象中的何处使用它

请仔细阅读Java文档。它始终表示从历元(1/1/1970 00:00:00 UTC)经过的毫秒数

时区仅在从这些对象使用其他表示时有效。e、 g.从toString()方法、从日历获取字段等)

更新 假设您的时间单位为千秒,
1528371250000L

然后您可以有两个日历(它们是时区感知的),一个是UTC日历,另一个是东部日历

请参阅完整的代码示例,以说明当两者中设置了以毫秒为单位的相同时间时会发生什么:

public static void main(String... args) throws Exception {

    Calendar utcCalendar = Calendar
            .getInstance(TimeZone.getTimeZone("UTC"));

    utcCalendar.setTimeInMillis(1528371250000L);

    System.out.println("UTC Calendar: \t\t" + (utcCalendar.get(Calendar.MONTH) +1)
            + "/" + utcCalendar.get(Calendar.DAY_OF_MONTH) + "/"
            + utcCalendar.get(Calendar.YEAR) + " "
            + utcCalendar.get(Calendar.HOUR_OF_DAY) + ":"
            + utcCalendar.get(Calendar.MINUTE) + ":"
            + utcCalendar.get(Calendar.SECOND) + " " + utcCalendar.getTimeZone().getID());

    Calendar eastCalendar = Calendar.getInstance(TimeZone
            .getTimeZone("EST"));

    eastCalendar.setTimeInMillis(1528371250000L);

    System.out.println("Eastern Calendar: \t"
            + (eastCalendar.get(Calendar.MONTH)+1) + "/"
            + eastCalendar.get(Calendar.DAY_OF_MONTH) + "/"
            + eastCalendar.get(Calendar.YEAR) + " "
            + eastCalendar.get(Calendar.HOUR_OF_DAY) + ":"
            + eastCalendar.get(Calendar.MINUTE) + ":"
            + eastCalendar.get(Calendar.SECOND) + " " + eastCalendar.getTimeZone().getID());

    XMLGregorianCalendar xmlUtcCalendar = DatatypeFactory.newInstance()
            .newXMLGregorianCalendar((GregorianCalendar) utcCalendar);

    System.out.println("XML UTC Calendar: \t" + xmlUtcCalendar.toString());

    XMLGregorianCalendar xmlEastCalendar = DatatypeFactory.newInstance()
            .newXMLGregorianCalendar((GregorianCalendar) eastCalendar);

    System.out.println("XML Eastern Calendar: \t" + xmlEastCalendar.toString());

}
输出:

 UTC Calendar:          6/7/2018 11:34:10 UTC
 Eastern Calendar:      6/7/2018 6:34:10 EST
 XML UTC Calendar:      2018-06-07T11:34:10.000Z
 XML Eastern Calendar:  2018-06-07T06:34:10.000-05:00
tl;博士 你似乎工作太辛苦了

您使用了错误的类。改用现代java.time类

myPreparedStatement.setObject(
    … , 
    Instant.ofEpochMilli( 1_528_371_000_000L ) 
)
你用错了。没有时区的
时区类型不能用于存储特定时刻

避免设置默认时区 TimeZone.setDefault

此调用会立即影响JVM中所有应用程序的所有线程中的所有代码!所以,只有在最绝望的情况下才能打这个电话

相反,将所需/预期时区作为可选参数传递给许多java.time方法

主机操作系统和JVM的默认时区应该与代码无关。将所需/预期时区明确指定为(或)对象

避免遗留日期时间类。 与最早版本的Java捆绑在一起的旧日期时间类非常糟糕。这包括在代码中看到的
gregoriacalendar
类。相反,使用它们的替代品,现代java.time类

具体来说,
gregorianalendar
被替换为

Instant
java.time中的
Instant
类是基本的构建块。该类表示时间线上的一个时刻,分辨率为(小数点的九(9)位)

显然,从1970-01-01T00:00:00Z开始,您有一个毫秒计数。只需通过调用将该数字解析为
即时
对象

instant.toString():2018-06-07T11:30:00Z

时区 您可能希望在特定时区向用户显示
即时
。应用
ZoneId
以获取
zoneDateTime

大陆/地区
的格式指定,例如,或
太平洋/奥克兰
。切勿使用3-4个字母的伪时区,如
EST
IST
,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)

数据库 我不知道你在用
xmlgorianicalendar
做什么。我不能解决Hibernate问题,因为我不是用户,尽管我知道

但是,如果你试图记录和检索一个与博士后的时刻,你太努力了

将UTC中的某一时刻存储到带有时区的时间戳的列中(不包括不带时区的
!-见下文)

检索

Instant instant = myResultSet.getObject( … , Instant.class ) ;
请注意,SQL标准很少涉及日期-时间这一主题。不同的数据库在处理日期和时间方面表现得非常不同

Postgres的工作方式是带时区的时间戳有点用词不当。时区不作为时间戳的一部分存储。随输入一起提交的任何与UTC信息的偏移时区用于调整为UTC。UTC值将写入数据库。然后,区域/偏移被丢弃/遗忘。如果记住输入的原始区域/偏移对您很重要,则必须将其单独存储在另一列中

从Postgres检索带有时区值的
时间戳时,您总是会得到UTC值。如果您的中间件工具将您(您的应用程序)与数据库连接起来,并将其自己的观点注入到一个理想的表示时区中,那么您可能看不到这一点

使用Java很容易避免这种时区注入混淆:传递
Instant
对象,并检索
Instant
对象。
一个
Instant
始终以UTC为单位。因此,调用
ResultSet::getObject(…,Instant.class)
将始终忠实地表示数据库
String sql = "INSERT INTO tbl ( event ) VALUES ( ? ) ;" ;       // Writing a moment into a column of type `TIMESTAMP WTH TIME ZONE`.
…
Instant instant = Instant.ofEpochMilli( 1_528_371_000_000L ) ;  // Representing a moment in UTC.
myPreparedStatement.setObject( 1 , instant ) ;                  // As of JDBC 4.2 and later, we can directly exchange java.time objects with our database.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
Instant instant = Instant.now().truncatedTo( ChronoUnit.MILLISECONDS ) ;  // Lop off any nanoseconds to match Postgres storing microseconds.