在DatePicker上显示相同的日期,而忽略设备的TimeZone

时间:2019-07-16 13:13:23

标签: android date datepicker timezone utc

我正在显示一个日期。日期随设备更改的时区而变化。例如-时区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);

我正在使用具有DatePicker方法(而非setDate(date))的自定义android.widget.DatePicker

我已经检查了许多类似的问答,但是没有运气。谢谢

1 个答案:

答案 0 :(得分:1)

使用java.util.Date不可能

使用java.util.Date无法做到。尽管有类名Date并不代表日期。这是一个时间点。因此,自创建Date以来,JVM的默认时区可能已更改,因此无法检测创建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月1日星期五欧洲中部时间

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

是的,java.time在较新和较旧的Android设备上均可正常运行。它只需要至少 Java 6

  • 在Java 8和更高版本以及更新的Android设备(API级别26以上)中,内置了现代API。
  • 在Java 6和7中,获得了ThreeTen反向端口,这是现代类的反向端口(JSR 310的ThreeTen;请参见底部的链接)。
  • 在(较旧的)Android上,使用Android版本的ThreeTen Backport。叫做ThreeTenABP。并确保您使用子包从org.threeten.bp导入日期和时间类。

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

链接