在 Java 中使用日历对象设置和格式化时区,然后返回日期对象



>我有一个函数,我需要获取当前日期,设置为另一个时区,并将转换/格式化的日期作为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;
}

java.util.Date对象没有时区信息。它只有一个long值,即从1970-01-01T00:00:00Z开始的毫秒数(也称为"unix 纪元">或简称为"纪元">(。此值完全独立于时区(您也可以说"它采用 UTC"(。

当你调用Logger.info("finalDate:: " + finalDate);时,它会调用toString()方法java.util.Date,并且此方法在后台使用系统的默认时区,给人的印象是日期对象本身具有时区 -但它没有

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

// using ".SSS" to don't lose milliseconds when formatting
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

输出为:

本地:: 周一 七月 03 17:34:34 UTC 2017 美国/丹佛:: 2017-07-03 11:34

:34.508
final日期:: 周一 七月 03 17:34:34 UTC 2017

finalDate.getTime()currentdate.getTimeInMillis()的值完全相同(请注意,Date.toString()不会打印毫秒,因此您无法知道它们的值是什么 - 只能通过比较getTime()值来知道它们是否相同(。

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

如果要在 UTC 时获取 11h,则必须创建另一个格式化程序并将其时区设置为 UTC:

DateFormat parser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
parser.setTimeZone(TimeZone.getTimeZone("UTC"));
finalDate = parser.parse(formattedDate);

然后,finalDate的时间在 UTC 时的值为 11h:

final日期:: 星期一 七月 03 11:34:34 UTC 2017


新的 Java 日期/时间 API

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

如果您使用的是Java 8,请考虑使用新的 java.time API。它比旧的 API 更容易、更少错误且更不容易出错。

如果你使用的是Java<= 7,你可以使用ThreeTen Backport,这是Java 8新的日期/时间类的一个很好的反向移植。对于Android,有ThreeTenABP(更多关于如何使用它(。

下面的代码适用于这两种情况。 唯一的区别是包名(在Java 8中是java.time,在ThreeTen Backport(或Android的ThreeTenABP(中是org.threeten.bp(,但类和方法是相同的。

要执行所需的操作,您可以使用ZonedDateTime(日期和时间 + 时区(并转换为保持相同日期/时间值的另一个时区:

// 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

输出将是:

2017-07-03T11:34:34.508Z

如果需要其他格式,请使用DateTimeFormatter

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

输出将是:

周一 七月 03 11:34:34 UTC 2017


如果您仍然需要使用java.util.Date,您可以轻松地从/转换为新的 API。

在 Java 中>= 8:

// 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);

在Java <= 7(ThreeTen Backport(中,您可以使用org.threeten.bp.DateTimeUtils类:

// convert Calendar to ZonedDateTime 
converted = DateTimeUtils.toInstant(currentdate)
.atZone(ZoneId.of("America/Denver"))
.withZoneSameLocal(ZoneOffset.UTC);
// converted is equals to 2017-07-03T11:34:34.508Z
// convert ZonedDateTime to Date (date will be 11:34 UTC)
Date d = DateTimeUtils.toDate(converted.toInstant());
Calendar c = DateTimeUtils.toGregorianCalendar(converted);
// to get a Date that corresponds to 11:34 in Denver
Date d = DateTimeUtils.toDate(converted.withZoneSameLocal(ZoneId.of("America/Denver")).toInstant());
Calendar c = DateTimeUtils.toGregorianCalendar(converted.withZoneSameLocal(ZoneId.of("America/Denver")));

最新更新