我有一个函数,我需要获取当前日期,设置为另一个时区,并将转换/格式化的日期作为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;
}
答案 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.Date
和finalDate.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
旧类(finalDate
,Date
和Calendar
)有lots of problems和design 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