如何在Java 1.6中将UTC日期转换为本地日期

时间:2019-05-24 08:52:59

标签: java datetime timezone java-6

我从这样的XML文件中获得带有UTC时间戳的字符串:

2019-05-24T00:59:55.1-05:00

我使用以下方法将字符串转换为日期。

    private Date getUTC2JavaDateB(String dateStr) {
    String dateS = dateStr;
    String timePattern = "";
    Date d = null;
    SimpleDateFormat formatter = null;
    if (dateS.length() >= 19) {
        dateS = dateS.substring(0, 19);
    }
    timePattern = "yyyy-MM-dd'T'hh:mm:ss";
    formatter = new SimpleDateFormat(timePattern);
    d = formatter.parse(dateS, new ParsePosition(0));

    return d;
}

现在这是我的问题。我想将其从UTC转换为当地时间。

我在其他一些线程中发现了一些代码片段,但它们对我而言仍然无效。

    private Date toLocalTimeStamp(Date date) {
    try {

        DateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        utcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));

        DateFormat currentTFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        currentTFormat.setTimeZone(TimeZone.getTimeZone(getCurrentTimeZone()));

        return currentTFormat.format(date);
    } catch (Exception ex) {
        return date;
    }
}

我得到一个异常“字符串不能转换为日期”-这对我来说很清楚。但是,现在如何将字符串转换为日期?我将UTC转换为本地日期的方法正确吗?

任何帮助将不胜感激! :-)

3 个答案:

答案 0 :(得分:1)

ThreeTen Backport

import org.threeten.bp.OffsetDateTime;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZonedDateTime;

public class ConvertUtcDateTimeToLocalInJava16 {

    public static void main(String[] args) {
        String dateStr = "2019-05-24T00:59:55.1-05:00";
        OffsetDateTime dateTime = OffsetDateTime.parse(dateStr);
        ZonedDateTime dateTimeInMyTimeZone
                = dateTime.atZoneSameInstant(ZoneId.systemDefault());
        System.out.println(dateTimeInMyTimeZone);
    }

}

我在Java 1.7.0_67上运行了该程序。输出为:

  

2019-05-24T07:59:55.100 + 02:00 [欧洲/哥本哈根]

我自己没有安装Java 1.6,但是至少运行该程序证明它不需要Java 1.8。我敢声称它也可以在Java 1.6上运行。您只需要在您的项目中添加ThreeTen Backport。使用底部的链接。

ThreeTen Backport是Java.time(现代Java日期和时间API)到Java 6和7的反向移植。

我正在利用您的日期时间字符串为ISO 8601格式的事实,该格式是java.time中的类将其解析为默认格式(并打印)的格式。如您所知,字符串末尾的-05:00是UTC偏移量,表示比UTC落后5小时(因此您的时间00:59:55.1对应于05:59:55.1 UTC)。

即使在Java 1.6上,也不需要使用DateSimpleDateFormat。这些类的设计总是很差,尤其是后者特别麻烦。因此,请考虑不使用它们。

请指定时区

ZoneId.systemDefault()为您提供了JVM的时区设置。这应该是您要求的“本地时区”,但它很脆弱,因为可以随时通过程序的另一部分或在同一JVM中运行的任何其他程序来更改设置。如果您有一种了解正确时区的方法,则最好明确地指定它。例如:

    ZonedDateTime dateTimeInMyTimeZone
            = dateTime.atZoneSameInstant(ZoneId.of("Africa/Algiers"));
  

2019-05-24T06:59:55.100 + 01:00 [非洲/阿尔及尔]

您怎么了?

首先,我怀疑您的期望是错误的。您的两种转换方法均返回Date,但是Date不能具有时区,因此将毫无用处。 Date是一个时间点,仅此而已。与Date相反,java.time提供了一个带有UTC偏移量的日期和时间OffsetDateTime和一个带有时区的日期和时间ZonedDateTime

格式模式字符串中的小写hh不正确。它是从01到12的AM或PM内的一个小时。字符串中的小时是从00到23的24小时制。为此,您需要像第二种方法那样使用大写HH

接下来,您将不会从字符串中解析UTC偏移量,因此可能会得到错误的时间(在这种情况下,SimpleDateFormat使用默认时区)。您还忽略了小数(在示例中为.1)是一个细节,引入了小于一秒的错误。无论如何,SimpleDateFormat不可能正确地在秒上解析一个十进制数(它仅支持精确的三个十进制数)。

链接

答案 1 :(得分:0)

您的字符串上已经有一个时区指示符。如果由于某种原因而坚持使用Java 6(请参阅my comment),则可以使用SimpleDateFormat轻松地稍稍更新字符串,然后解析包括时区在内的整个字符串:

// Remove the colon in the timezone indicator
assert str.charAt(str.length() - 3) == ':';
str = str.substring(0, str.length() - 3) + str.substring(str.length() - 2);
// Parse the result
Date dt = (new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).parse(str);

Live Example

答案 2 :(得分:0)

如果您不熟悉Java 6并且没有更新的时间处理库(Joda Time,310 backport等)...

使用XML日期处理方法

您要解析的日期是ISO-8601格式的,这是XML DateTime数据类型使用的格式。

JAXB实现附带的Java 6提供了许多XML处理工具,包括解析ISO 8601日期类型。这里特别令人感兴趣的是GregorianXMLCalendar

所以这会给你一个java.util.Date

java.util.Date date = DatatypeFactory.newInstance()
  .newXMLGregorianCalendar("2019-05-24T00:59:55.1-05:00")
  .toGregorianCalendar()
  .getTime()

然后您将能够在您感兴趣的区域中显示和格式化...

    // What is the UTC hour of 00:59:55.1 at -5 offset ?
    SimpleDateFormat utc = new SimpleDateFormat("HH:mm");
    utc.setTimeZone(TimeZone.getTimeZone("UTC"));
    System.out.println(utc.format(date)); // --> 05:59

    // What would it be in Paris ?
    SimpleDateFormat paris = new SimpleDateFormat("HH:mm");
    paris.setTimeZone(TimeZone.getTimeZone("Europe/Paris"));
    System.out.println(paris.format(date)); // -> 07:59 Paris is UTC+2 in the summer, so it's OK.