【问题标题】:Date() does not catch a time zone changeDate() 没有捕捉到时区变化
【发布时间】:2018-10-10 13:28:05
【问题描述】:

我的应用程序从我的服务器获得了过去事件的日期和时间的响应。然而,我的服务器在另一个时区,这里的事情变得有点棘手。服务器时区是UTC +01:00,而我的是UTC +03:00。当我收到来自服务器的响应时,它们带有UTC +01:00 的时间戳。首先,我尝试以String 的形式接收日期,对其进行子串化,设置其时区,然后以适当的时间格式和时区返回它。 (我剪掉了 milisec 的最后 4 位,因为 DateFormat 否则无效。)

private String getFormattedDate(String date) {
    DateFormat serverDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
    DateFormat finalDateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
    Calendar calendar = Calendar.getInstance();
    TimeZone timeZone = calendar.getTimeZone();
    serverDateFormat.setTimeZone(timeZone);
    String cutoutDate = date.substring(0,23);
    String cutoutZone = date.substring(27, date.length());
    String dateInProperFormat = cutoutDate + cutoutZone;
    Date finalDate = serverDateFormat.parse(dateInProperFormat);
    return finalDateFormat.format(finalDate);
}

这会正确读取并转换所有内容:

服务器响应:2018-04-30T07:26:55.1524511+01:00 -> 子字符串响应:2018-04-30T07:26:55.152+01:00 -> 最终格式:30-04-2018 09:26:55

但是,milisec 并不总是 7,所以当发生这种情况时,我收到了 Unparsable date 错误。这让我读到的日期不是String,而是Date。这将代码减少到只有 5 行:

private String getFormattedDate(Date date) {
    SimpleDateFormat finalDateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
    Calendar calendar = Calendar.getInstance();
    TimeZone timeZone = calendar.getTimeZone();
    finalDateFormat.setTimeZone(timeZone);
    return finalDateFormat.format(date);
}

但是现在,时间总是在UTC +01:00。我尝试像这样获取时区:

TimeZone timeZone = TimeZone.getDefault();

但这并没有改变任何东西。我在第二种方法中到底做错了什么?如果需要,我准备分享更多我的代码。

【问题讨论】:

  • 我一直不鼓励使用旧的 DateFormatSimpleDateFormatCalendarTimeZoneDate 类,因为它们设计得很糟糕而且经常很麻烦。在这种情况下更是如此,因为java.time, the modern Java date and time API, 更适合您的特定任务。我建议您将ThreeTenABP 添加到您的项目中,以便您可以使用OffsetDateTimeZoneId 和他们的朋友。 java.time 通常也更好用。

标签: android date datetime timezone


【解决方案1】:

试试下面的代码。这是一个变通的解决方案

   public String getFormattedDate(String date) {
    DateFormat serverDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
    DateFormat finalDateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
    Calendar calendar = Calendar.getInstance();
    TimeZone timeZone = calendar.getTimeZone();
    serverDateFormat.setTimeZone(timeZone);
    String[] splitTime=date.split("\\+");
    String cutoutDate="";
    if (splitTime[0].length()>23)cutoutDate = date.substring(0,23);
    else cutoutDate=splitTime[0];
    String cutoutZone = "+"+splitTime[1];
    String dateInProperFormat = cutoutDate + cutoutZone;
    Date finalDate = null;
    try {
        finalDate = serverDateFormat.parse(dateInProperFormat);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return finalDateFormat.format(finalDate);
}

【讨论】:

  • 在尝试了多种方法之后,这个解决方法是唯一适用于任何返回结果的方法。谢谢!
【解决方案2】:

java.time

private static DateTimeFormatter finalDateTimeFormatter
        = DateTimeFormatter.ofPattern("dd-MM-uuuu HH:mm:ss");
private static ZoneId zone = ZoneId.of("Europe/Istanbul");

private static String getFormattedDate(String dateTime) {
    return OffsetDateTime.parse(dateTime)
            .atZoneSameInstant(zone)
            .format(finalDateTimeFormatter);
}

让我们用您问题的示例服务器响应来试试吧:

    System.out.println(getFormattedDate("2018-04-30T07:26:55.1524511+01:00"));

这会输出所需的:

30-04-2018 09:26:55

注意事项:

  • 单参数OffsetDateTime.parse 在秒上接受 1 到 9 位小数,因此您无需在解析之前以任何方式操作字符串。
  • 不要使用UTC +03:00 的UTC 偏移量作为时区。使用非洲/内罗毕、欧洲/莫斯科、亚洲/卡塔尔等时区或适当的时区。它更好地记录了你为什么要做你正在做的事情,并且在偏移量发生变化的情况下它是面向未来的。这种情况发生的频率超出您的想象。

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

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

  • 在 Java 8 及更高版本以及更新的 Android 设备上(据我所知,从 API 级别 26 开始)现代 API 是内置的。
  • 在 Java 6 和 7 中,获取 ThreeTen Backport,即新类的后向端口(对于 JSR 310,ThreeTen;请参阅底部的链接)。
  • 在(较旧的)Android 上使用 ThreeTen Backport 的 Android 版本。它被称为 ThreeTenABP。并确保从 org.threeten.bp 导入日期和时间类以及子包。

链接

【讨论】:

  • 我已经尝试过使用jora-time,但我没有在String 中获得时间,而是以Date 接收它,这让事情变得更加混乱。这比我的解决方案优雅得多!非常感谢您花时间更详细地解释它!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-21
  • 2016-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多