java.time
Instant convertInstant = Instant.parse(date);
Instant(就像Date)表示独立于时区的时间点。所以你很好。作为额外的好处,您的 2018-09-20T17:00:00Z 字符串暂时采用 ISO 8601 格式,因此 Instant 类无需指定格式即可对其进行解析。
编辑:在英国夏令时将其格式化为人类可读的字符串,并使用明确的 UTC 偏移量,例如:
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss Z yyyy", Locale.UK);
ZonedDateTime dateTime = convertInstant.atZone(ZoneId.of("Europe/London"));
String formatted = dateTime.format(formatter);
System.out.println(formatted);
这个代码sn-p打印出来:
2018 年 9 月 20 日星期四 18:00:00 +0100
18:00 是偏移 +01:00 处的正确时间。原始字符串末尾的Z 表示偏移量零,也称为“祖鲁时区”,偏移量零处的 17 与偏移量 +01:00 处的 18:00 是同一时间点。我从您自己的答案中接管了格式模式字符串。
编辑 2
我想向您提出我的建议,即根据您自己的答案重写 Fixture 类:
public class Fixture implements Comparable<Fixture> {
private static DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss Z yyyy", Locale.UK);
public Instant date;
/** @param date Date string from either web service or persistence */
public Fixture(String date) {
this.date = Instant.parse(date);
}
/** @return a string for persistence, e.g., Firebase */
public String getDateForPersistence() {
return date.toString();
}
/** @return a string for the user in the default time zone of the device */
public String getFormattedDate() {
return date.atZone(ZoneId.systemDefault()).format(formatter);
}
@Override
public int compareTo(Fixture other) {
return date.compareTo(other.date);
}
@Override
public String toString() {
return "Fixture [date=" + date + "]";
}
}
此类具有自然排序(即按日期和时间),因为它实现了Comparable,这意味着您不再需要您的DateSorter 类。几行代码来演示新的getXx 方法的使用:
String date = "2018-09-24T11:30:00Z";
Fixture fixture = new Fixture(date);
System.out.println("Date for user: " + fixture.getFormattedDate());
System.out.println("Date for Firebase: " + fixture.getDateForPersistence());
当我在欧洲/伦敦时区运行这个 sn-p 时,我得到:
Date for user: Mon Sep 24 12:30:00 +0100 2018
Date for Firebase: 2018-09-24T11:30:00Z
因此,正如我认为您所要求的那样,用户可以使用他或她自己的 UTC 偏移量来获取日期和时间。在欧洲/柏林时区尝试相同的 sn-p:
Date for user: Mon Sep 24 13:30:00 +0200 2018
Date for Firebase: 2018-09-24T11:30:00Z
我们看到德国的用户被告知比赛时间是 13:30 而不是 12:30,这与他或她的时钟一致。在 Firebase 中持久化的日期是不变的,这也是你想要的。
你的代码出了什么问题
您的格式模式字符串中有两个错误,yyyy-MM-dd'T'hh:mm:ss'Z':
- 小写
hh 表示从 01 到 12 的 AM 或 PM 中的小时,并且仅对 AM/PM 标记有意义。在实践中你会得到正确的结果除了解析一个小时 12,它会被理解为 00。
- 通过将
Z 解析为文字,您不会从字符串中获取UTC 偏移信息。相反,SimpleDateFormat 将使用 JVM 的时区设置。这显然因一种设备而异,并解释了为什么您在不同的设备上得到不同且相互冲突的结果。
您的代码中发生的另一件事是 Date.toString 的特殊行为:此方法获取 JVM 的时区设置并将其用于生成字符串。因此,当一台设备设置为 Europe/London 而另一台设置为 GMT+01:00 时,相等的 Date 对象将在这些设备上以不同方式呈现。这种行为让很多人感到困惑。
问题:我可以在 Android 上使用 java.time 吗?
是的,java.time 在较旧和较新的 Android 设备上都能很好地工作。它只需要至少 Java 6。
- 在 Java 8 及更高版本以及更新的 Android 设备上(据我所知,从 API 级别 26 开始),现代 API 是内置的。
- 在 Java 6 和 7 中,获得 ThreeTen Backport,即新类的后向端口(对于 JSR 310,ThreeTen;请参阅底部的链接)。上面的代码是使用来自 backport 的
org.threeten.bp.Duration 开发和运行的。
- 在(较旧的)Android 上使用 ThreeTen Backport 的 Android 版本。它被称为 ThreeTenABP。并确保从
org.threeten.bp 导入日期和时间类以及子包。
链接