在 DatePicker 上显示相同的日期,忽略设备的时区

Displaying the same date over DatePicker, ignoring device's TimeZone

我正在显示日期。日期因设备更改的时区而异。例如 - 时区 GMT +5.30 的 1960 年 1 月 1 日转换为时区 GMT -5.00 的 1959 年 12 月 31 日。我的要求是日期应该与任何时区相同。我已将我的日期转换为 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 你不能。尽管 class 名称 Date 不代表日期。这是一个时间点。因此,当创建 Date 后 JVM 的默认时区可能发生变化时,无法检测创建 Date 时使用的是哪个时区。当然,您可以尝试所有可能的时区。这通常会给你两个,偶尔三个可能的日期。因为所有时区的日期都不同。

它可能并不像听起来那么糟糕,因为 Date class 设计不佳且早已过时,所以无论如何您都不应该再使用它了。

解决方案:java.time和ThreeTenABP

java.time,现代 Java 日期和时间 API,提供 LocalDate class。 LocalDate 是没有时间和时区的日期。因此,当您创建一个值是 Jan 01, 1960 的 LocalDate 时,它将始终明确为 Jan 01, 1960。

    LocalDate date = LocalDate.of(1960, Month.JANUARY, 1);
    System.out.println(date);

输出没有什么神秘的:

1960-01-01

所以第一个建议是将您的自定义 DatePicker class 基于 LocalDate 而不是 Date

如果您现在无法承担更改费用,short-term 解决方案是在调用 setDate 之前进行转换(因此只有在默认时区的最后一次更改发生之后):

    Instant startOfDayInDefaultZone = date.atStartOfDay(ZoneId.systemDefault())
            .toInstant();
    Date oldFashionedDate = DateTimeUtils.toDate(startOfDayInDefaultZone);
    System.out.println(oldFashionedDate);

我所在时区的输出是:

Fri Jan 01 00:00:00 CET 1960

问题:我可以在 Android 上使用 java.time 吗?

是的,java.time 在新旧 Android 设备上都能很好地工作。它只需要至少 Java 6.

  • 在 Java 8 和更新的 Android 设备上(从 API 级别 26)现代 API 出现 built-in.
  • 在 Java 6 和 7 中获取 ThreeTen Backport,现代 classes 的 backport(ThreeTen 用于 JSR 310;请参阅底部的链接)。
  • 在(较旧的)Android 使用 ThreeTen Backport 的 Android 版本。它叫做 ThreeTenABP。并确保使用子包从 org.threeten.bp 导入日期和时间 classes。

在上面的代码中,我使用来自反向端口的 DateTimeUtilsInstant 转换为 Date。如果您的 Android 版本内置了 java.time,请改用 Date.from(startOfDayInDefaultZone) 进行此转换。

链接