gpt4 book ai didi

java - 在 Java 中使用 Calendar 对象设置和格式化时区,然后返回一个 Date 对象

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:50:05 25 4
gpt4 key购买 nike

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

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


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

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 对象 has no timezone information .它只有一个 long 值,即从 1970-01-01T00:00:00Z 开始的毫秒数(也称为 “unix epoch” 或只是“纪元”)。该值完全独立于时区(您也可以说“它在 UTC 中”)。

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

检查 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");

输出是:

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

并且 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:

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


新的 Java 日期/时间 API

旧类(DateCalendarSimpleDateFormat)有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 中是 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));

输出将是:

Mon Jul 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")));

关于java - 在 Java 中使用 Calendar 对象设置和格式化时区,然后返回一个 Date 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44890999/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com