>我正在显示一个日期。日期因设备更改的时区而异。例如 - 1960 年 1 月 1 日时区 GMT +5.30 转换为 1959 年 12 月 31 日时区 GMT -5.00。我的要求是日期应与任何时区相同。我已将日期转换为 UTC 日期,但日期仍然根据时区更改。我尝试了如下代码-
//Convering given date to UTC date using SimpleDateFormat
try {
final DateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
final Date date = sdf.parse(givenDate + "");
datePicker.setDate(date);
} catch (ParseException exception) {
exception.printStackTrace();
}
或
// Converting given date into GMT date using Timezone defference
final TimeZone tzLocal = TimeZone.getDefault();
final long gmtMillis = givenDate.getTime() - (tzLocal.getRawOffset());
final Date date = new Date();
date.setTime(gmtMillis);
datePicker.setDate(date);
我正在使用具有setDate(date)
方法(不是android.widget.DatePicker
)的自定义DatePicker
。
我已经检查了许多类似的问答,但没有运气。谢谢
不可能使用 java.util.Date
有了java.util.Date
你不能。尽管类名,Date
并不表示日期。这是一个时间点。因此,当 JVM 的默认时区自创建Date
以来可能已更改时,无法检测创建Date
时使用了哪个时区。当然,您可以尝试所有可能的时区。这通常会给你两个,偶尔三个可能的日期。因为它在所有时区中都不是相同的日期。
它可能并不像听起来那么糟糕,因为Date
类设计不佳且早已过时,因此无论如何您都不应该再使用它。
解决方案:java.time 和 ThreeTenABP
java.time 是现代 Java 日期和时间 API,它提供了LocalDate
类。LocalDate
是没有一天中时间和时区的日期。因此,当您创建价值为 1960 年 1 月 1 日的LocalDate
时,它将始终明确地为 1960 年 1 月 1 日。
LocalDate date = LocalDate.of(1960, Month.JANUARY, 1);
System.out.println(date);
输出没有什么神秘的:
1960年01月01日
因此,第一个建议是将您的自定义DatePicker
类基于LocalDate
而不是Date
。
如果您现在负担不起进行该更改的费用,短期解决方案是在调用setDate
之前进行转换(因此仅在默认时区的最后一次更改发生之后):
Instant startOfDayInDefaultZone = date.atStartOfDay(ZoneId.systemDefault())
.toInstant();
Date oldFashionedDate = DateTimeUtils.toDate(startOfDayInDefaultZone);
System.out.println(oldFashionedDate);
我所在时区的输出是:
1960年1月01日星期五 00:00:00 CET
问:我可以在 Android 上使用 java.time 吗?
是的,java.time在较旧和较新的Android设备上运行良好。它只需要至少Java6。
- 在 Java 8 及更高版本以及较新的 Android 设备(从 API 级别 26)中,内置了现代 API。
- 在Java 6和7中获取ThreeTen Backport,现代类的反向移植(JSR 310的ThreeTen;请参阅底部的链接)。
- 在(较旧的)Android上使用Android版本的ThreeTen Backport。它被称为ThreeTenABP。并确保从带有子包的
org.threeten.bp
导入日期和时间类。
在上面的代码中,我使用来自反向端口的DateTimeUtils
从Instant
转换为Date
。如果您的Android版本内置了java.time,请改用Date.from(startOfDayInDefaultZone)
进行此转换。
链接
- 所有关于java.util.Date
- Oracle 教程:日期时间解释如何使用 java.time。
- Java 规范请求 (JSR) 310,其中首次描述了
java.time
。 - ThreeTen Backport 项目,将
java.time
向 Java 6 和 7 的反向移植(JSR-310 为 ThreeTen)。 - ThreeTenABP,ThreeTen Backport 的安卓版
- 问:如何在Android项目中使用ThreeTenABP,并进行了非常详尽的解释。