使用Java中的Calendar对象设置和格式化时区,然后返回Date对象

时间:2017-07-03 17:17:59

标签: java date datetime time timezone

我有一个函数,我需要获取当前日期,设置为另一个时区,并将转换/格式化的日期作为Date对象返回。我有适用的代码,但Date对象未设置为新转换的日期,它返回当前日期。

以下是代码:

public static Date getCurrentLocalDateTime() {

    Calendar currentdate = Calendar.getInstance();
    DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    TimeZone obj = TimeZone.getTimeZone("America/Denver");
    formatter.setTimeZone(obj);

    Logger.info("Local:: " + currentdate.getTime());

    String formattedDate = formatter.format(currentdate.getTime());

    Logger.info("America/Denver:: "+ formattedDate);

    Date finalDate = null;
    try {
        finalDate = formatter.parse(formattedDate);
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    Logger.info("finalDate:: " + finalDate);

    return finalDate;
}

从我已经审核并尝试的示例中,这应该可以正常工作。其中一个问题是我需要返回Date对象,以便它与当前代码一起使用。

输出如下:

2017-07-03 17:08:24,499 [INFO] from application in application-akka.actor.default-dispatcher-3 -
                Local:: Mon Jul 03 17:08:24 UTC 2017
2017-07-03 17:08:24,501 [INFO] from application in application-akka.actor.default-dispatcher-3 -
                America/Denver:: 2017-07-03 11:08:24
2017-07-03 17:08:24,502 [INFO] from application in application-akka.actor.default-dispatcher-3 -
                finalDate:: Mon Jul 03 17:08:24 UTC 2017

如您所见,它将日期正确格式化为山区时区,但随后将其设置回Calendar时间。

编辑---代码解决方案:

public static Date getCurrentLocalDateTime() {
    Calendar currentdate = Calendar.getInstance();
    ZonedDateTime converted = currentdate.toInstant().atZone(ZoneId.of("America/Denver"))
            .withZoneSameLocal(ZoneOffset.UTC);
    Date finalDate = Date.from(converted.toInstant());
    return finalDate;
}

1 个答案:

答案 0 :(得分:1)

java.util.Date个对象has no timezone information。它只有一个long值,这是1970-01-01T00:00:00Z的毫秒数(也称为" unix epoch" 或只是&# 34;时期" )。这个值完全独立于时区(你可以说"它在UTC"以及它)。

当您致电Logger.info("finalDate:: " + finalDate);时,它会调用toString()的{​​{1}}方法,此方法会在幕后使用系统的默认时区,给人的印象是日期对象本身有一个时区 - 但它没有

检查java.util.DatefinalDate.getTime()的值,您会发现它们几乎相同 - "几乎"因为currentdate.getTimeInMillis()没有分数,所以你失去了毫秒精度(SimpleDateFormat方法创建format没有毫秒,String方法在字段不存在时将其设置为零)。如果我将格式化程序更改为此,但是:

parse

输出结果为:

  

Local :: Mon Jul 03 17:34:34 UTC 2017年   America / Denver :: 2017-07-03 11:34:34.508
  finalDate :: Mon Jul 03 17:34:34 UTC 2017

// using ".SSS" to don't lose milliseconds when formatting DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); finalDate.getTime()都具有完全相同的值(请注意,currentdate.getTimeInMillis()不会打印毫秒,因此您无法知道&#39 ;它们的价值 - 只有比较Date.toString()你知道它们是否相同的值。

结论:只需将格式化程序更改为使用毫秒(getTime()),解析/格式化即可。它在另一个时区显示日期的事实是实现细节(.SSS方法使用系统的默认时区),但毫秒值是正确的。

如果您希望在UTC获得11小时,则必须创建另一个格式化程序并将其时区设置为UTC:

toString()

然后,DateFormat parser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); parser.setTimeZone(TimeZone.getTimeZone("UTC")); finalDate = parser.parse(formattedDate); 的时间在UTC时的价值为11小时:

  

finalDate :: Mon Jul 03 11:34:34 UTC 2017

新Java日期/时间API

旧类(finalDateDateCalendar)有lots of problemsdesign issues,并且它们被新API取代

如果您使用 Java 8 ,请考虑使用new java.time API。它更容易,less bugged and less error-prone than the old APIs

如果您正在使用 Java< = 7 ,则可以使用ThreeTen Backport,这是Java 8新日期/时间类的绝佳后端。对于 Android ThreeTenABP(更多关于如何使用它here)。

以下代码适用于两者。 唯一的区别是包名称(在Java 8中为SimpleDateFormat而在ThreeTen Backport(或Android的ThreeTenABP中)为java.time),但类和方法名称是一样的。

要做你需要的,你可以使用org.threeten.bp(日期和时间+时区)并转换到另一个时区,保持相同的日期/时间值:

ZonedDateTime

输出将是:

  

2017-07-03T11:34:34.508Z

如果您想要其他格式,请使用// current date/time in Denver ZonedDateTime denverNow = ZonedDateTime.now(ZoneId.of("America/Denver")); // convert to UTC, but keeping the same date/time values (like 11:34) ZonedDateTime converted = denverNow.withZoneSameLocal(ZoneOffset.UTC); System.out.println(converted); // 2017-07-03T11:34:34.508Z

DateTimeFormatter

输出将是:

  

Mon Jul 03 11:34:34 UTC 2017

如果您仍需要使用DateTimeFormatter fmt = new DateTimeFormatterBuilder() // pattern for day/hour .appendPattern("EEE MMM dd HH:mm:ss ") // UTC offset .appendOffset("+HHMM", "UTC") // year .appendPattern(" yyyy") // create formatter .toFormatter(Locale.ENGLISH); System.out.println(fmt.format(converted)); ,则可以轻松地从/转换为新的API。

在Java> = 8:

java.util.Date

在Java< = 7(ThreeTen Backport)中,您可以使用// convert your Calendar object to ZonedDateTime converted = currentdate.toInstant() .atZone(ZoneId.of("America/Denver")) .withZoneSameLocal(ZoneOffset.UTC); // converted is equals to 2017-07-03T11:34:34.508Z // from ZonedDateTime to Date and Calendar (date will be 11:34 UTC) Date d = Date.from(converted.toInstant()); Calendar cal = Calendar.getInstance(); cal.setTime(d); // to get a Date that corresponds to 11:34 in Denver Date d = Date.from(converted.withZoneSameLocal(ZoneId.of("America/Denver")).toInstant()); Calendar cal = Calendar.getInstance(); cal.setTime(d); 类:

org.threeten.bp.DateTimeUtils