【问题标题】:Android UTC date string to local dateAndroid UTC日期字符串到本地日期
【发布时间】:2018-09-27 16:48:27
【问题描述】:

我在将 UTC 日期字符串转换为 Android 中的本地日期字符串时遇到问题。万一的例子是, 我已将 UTC 日期字符串输入为 2018-02-28T02:42:41Z

我在 PST 时区,但是当我尝试转换为本地时区时,它并没有改变。我得到February 28, 2018 02:42 AM 这是不正确的。

public static String convertUTCtoLocalTime(String utcDateString) throws Exception{

    SimpleDateFormat dateFormatter;

    //create a new Date object using the UTC timezone
    Log.v(TAG, "Input utc date:" + utcDateString);
    dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
    Date utcDate = dateFormatter.parse(utcDateString);

    //Convert the UTC date to Local timezone
    dateFormatter = new SimpleDateFormat("MMMM dd, yyyy hh:mm a");
    dateFormatter.setTimeZone(TimeZone.getDefault());
    String formattedDate = dateFormatter.format(utcDate);
    Log.v(TAG, "convertUTCtoLocalTime: local time:" + formattedDate);

    return lv_dateFormateInLocalTimeZone;
}

我不完全理解其中的区别,但类似的转换在“swift”中起作用,如下所示,

    static func utcDateToLocal(utcdate: String) -> String {
      let dateFormatter = DateFormatter()

      dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" //Input Format 2018-02-28T02:42:41Z
      dateFormatter.timeZone = NSTimeZone(name: "UTC")! as TimeZone
      let UTCDate = dateFormatter.date(from: utcdate)

      dateFormatter.dateFormat = "MMMM dd, yyyy hh:mm a" // Output Format
      dateFormatter.timeZone = TimeZone.current
      let UTCToCurrentFormat = dateFormatter.string(from: UTCDate!)
      return UTCToCurrentFormat
  }

Swift 示例给出了“2018 年 2 月 27 日 06:42 PM”,这是正确的。

Swift 正在使用 v3.x 和

Android 是 Studio 3.1.1 构建 #AI-173.4697961,构建于 2018 年 4 月 3 日 JRE:1.8.0_152-release-1024-b01 x86_64 JVM:JetBrains s.r.o 的 OpenJDK 64 位服务器 VM Mac OS X 10.13.4

我在同一台机器上运行这两个示例。 任何解决 Android 问题的提示都会非常有用。

【问题讨论】:

  • 我不知道为什么(这就是我不写答案的原因),但在这种情况下,getDefault() 返回的是 UTC 时区而不是 PST。如果您将getDefault() 切换为getTimeZone("PST"),它会返回正确的值。
  • 顺便考虑扔掉长期过时且臭名昭著的麻烦SimpleDateFormat和朋友,并将ThreeTenABP添加到您的Android项目中,以便使用java.time,现代Java日期和时间API .使用起来感觉好多了。
  • 您的转换是正确的。在我的电脑上,它通过convertUTCtoLocalTime: local time:February 27, 2018 06:42 PMLog.v()。你的问题是你的方法返回了一个你在方法中没有接触过的变量的值,lv_dateFormateInLocalTimeZone,所以它不可能保存转换后的值。另一件事,你确定TimeZone.getDefault() 返回 PST 吗? (而不是菲律宾标准时间??至少三个时区称为 PST。)
  • lv_dateFormateInLocalTimeZone 变量未使用。如果我设置,TimeZone tz =TimeZone.getTimeZone("America/Los_Angeles"); dateFormatter.setTimeZone(tz); 这将打印正确的本地日期字符串。我的应用程序在TimeZone.getDefault();?以外的移动设备上运行时如何获得正确的时区@

标签: java android timezone utc datetime-conversion


【解决方案1】:
static DateTimeFormatter formatter = DateTimeFormatter
        .ofLocalizedDateTime(FormatStyle.LONG, FormatStyle.SHORT)
        .withLocale(Locale.US);

public static String convertUTCtoLocalTime(String utcDateString) {

    Log.v(TAG, "Input utc date:" + utcDateString);

    String formattedDateTime = Instant.parse(utcDateString)
            .atZone(ZoneId.systemDefault())
            .format(formatter);

    Log.v(TAG, "convertUTCtoLocalTime: local time:" + formattedDateTime);

    return formattedDateTime;
}

试试看:

    System.out.println(convertUTCtoLocalTime("2018-02-28T02:42:41Z"));

输出:

2018 年 2 月 27 日下午 6:42

使用内置的本地化格式,而不是构建自己的格式模式字符串。它为您提供了一些确保该格式适合相关语言环境的保证,它也适用于其他语言环境,并且它使您免于编写正确的格式模式字符串的容易出错的任务。在美国语言环境中,长日期格式为您提供完整的月份名称(不仅仅是“Feb”),而短时间格式为您提供不带秒的时间。结合我理解的你想要的字符串。

Instant 类在没有任何显式格式化程序的情况下解析您的 UTC 字符串,这再次使您免于构建格式模式字符串。格式为 ISO 8601。Instant 类和我使用的其他日期时间类是现代 Java 日期和时间 API java.time 的一部分。这些类将 ISO 8601 解析为默认值。而且通常现代 API 更易于使用。

你的代码出了什么问题?

您的转换是正确的。当我在我的计算机上运行它时,它会将以下字符串传递给Log.v()convertUTCtoLocalTime: local time:February 27, 2018 06:42 PM。我相信这是你所期望的。我只能看到两个潜在问题:

  1. 如果您的默认时区(从TimeZone.getDefault() 获得)不是您认为的那样,您将得到错误的结果。但是,在这种情况下,您的 Swift 代码可能会给出相同的错误结果,而我上面的代码肯定会。
  2. 您的退货声明是:

         return lv_dateFormateInLocalTimeZone;
    

    在之前的内容中,您还没有接触过名为 lv_dateFormateInLocalTimeZone 的变量,因此该变量无法保存您格式化的日期时间。要退回它,您需要

         return formattedDate;
    

问题:我可以在 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 导入日期和时间类以及子包。

链接

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-07
    • 2021-04-19
    • 2014-02-22
    • 2016-02-25
    • 2011-06-13
    • 2020-02-03
    • 2012-10-29
    相关资源
    最近更新 更多