【问题标题】:How to convert GMT +09:00 to local time?如何将 GMT +09:00 转换为当地时间?
【发布时间】:2019-11-06 01:28:22
【问题描述】:

当我打印从服务器获取的日期时,它显示Mon Jun 24 16:15:31 GMT+09:00 2019

val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val date: Date? = formatter.parse(checkedDate) // date from server
val transformedDate = ("${String.format("%02d", date!!.month + 1)}.${String.format("%02d", date!!.date)}.${date.year + 1900}")
val title: String? = ("$transformedDate")

val longGmtTime = date.time
val mZone = TimeZone.getDefault()
val offset = mZone.getOffset(longGmtTime)
val longLocalTime = longGmtTime + offset - (9 * HOUR)

val localDate = Date() // local date
localDate.time = longLocalTime
val localFormatTime = formatter.format(localDate)
val transformedLocalDate = ("${String.format("%02d", localDate!!.month + 1)}.${String.format("%02d", localDate!!.date)}.${localDate.year + 1900}")

它给了我server time: 2019-06-24 16:15:31 -> 06.24.2019, local time(Asia/Seoul)-> 2019-06-25 01:15:30 ->06.25.2019 的结果。

服务器时间和本地时间必须相同。但当地时间显示在其他地方。

有什么问题?

【问题讨论】:

  • 在 UTC 中工作并转换两者?
  • 什么意思?
  • 如果您没有收到带有时间戳的时区,则必须将其视为当地时间。
  • 你想做什么? Mon Jun 24 16:15:31 GMT+09:00 2019 不是已经当地时间了吗?你需要做什么吗? (除了考虑现代日期和时间 API)
  • 这是服务器时间。我想把它转换成当地时间。

标签: java android datetime kotlin android-jodatime


【解决方案1】:

有什么问题?

严重问题列表包括:

  • 您正在使用设计不佳且早已过时的 Java 日期和时间类 DateTimeZoneSimpleDateFormat
  • 您正在使用Date 类的已弃用方法getMonthgetDategetYear。这些方法跨时区运行不可靠,这是它们被弃用的主要原因。
  • 您正在使用加法、减法和乘法手动进行时区转换。日期和时间数学很容易出错,您应该始终将其留给经过验证的库方法。
  • 您从 Date.getTime 获得的毫秒数是自 1970-01-01T00:00:00 UTC 的纪元以来。这是一个独特的时刻,与时区无关,因此添加和减去毫秒计数以进行时区转换是没有意义的。
  • 当我将 JVM 的默认时区设置为 Asia/Seoul 并假设 HOUR 为 0(或 0 到 111 范围内的某个值)时,我可以重现您的结果。我假设您希望 HOUR 表示一小时内的毫秒数,即 3 600 000(至少通常存在例外)。
  • 您通过将调用结果连接到Strirg.format 来格式化您的日期。最好将格式化留给专门的日期格式化程序。

修复:java.time

    ZoneId serverTimeZone = ZoneId.of("Asia/Seoul");
    DateTimeFormatter serverFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
    ZoneId clientTimeZone = ZoneId.systemDefault();

    String checkedDate = "2019-06-24 16:15:31";
    ZonedDateTime serverDateTime = LocalDateTime.parse(checkedDate, serverFormatter)
            .atZone(serverTimeZone);
    ZonedDateTime clientDateTime = serverDateTime.withZoneSameInstant(clientTimeZone);
    System.out.println("clientDateTime: " + clientDateTime);

对不起,我只能编写和运行 Java 代码,我相信你会翻译。由于我的 JVM 时区仍设置为亚洲/首尔,我得到:

clientDateTime: 2019-06-24T16:15:31+09:00[亚洲/首尔]

服务器时间和客户端时间是一样的,正如你所要求的。相反,如果我保留自己的时区,我会得到:

clientDateTime:2019-06-24T09:15:31+02:00[欧洲/哥本哈根]

因此发生了转换。

格式化日期:

    DateTimeFormatter displayFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
            .withLocale(Locale.forLanguageTag("ko-KR"));
    String transformedLocalDate = clientDateTime.format(displayFormatter);
    System.out.println("transformedLocalDate: " + transformedLocalDate);

transformedLocalDate: 2019. 6. 24.

或者如果你坚持要month.date.year:

    DateTimeFormatter displayFormatter = DateTimeFormatter.ofPattern("MM.dd.u");

transformedLocalDate: 06.24.2019

进一步的建议是让您的服务器以 UTC 格式以 ISO 8601 格式提供日期时间字符串。在示例中使用的那一刻就像2019-06-24T07:15:31Z

问题:我可以在 Android 上将 java.time 与 minSdk API 级别 23 一起使用吗?

是的,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 导入日期和时间类以及子包。

链接

【讨论】:

  • 这种方式需要minSdk API 26。我的minSdk是API 23。有没有其他方法..?
  • 它不需要 API 级别 26。对于 API 级别 23,它需要 ThreeTenABP 库。只需阅读直到答案结束。 :-)
【解决方案2】:

您应该指定设置服务器时区而不是您的设备(这是默认设置)

【讨论】:

  • 能详细解释一下吗?
猜你喜欢
  • 2018-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-14
  • 2012-08-28
  • 1970-01-01
  • 2013-10-29
相关资源
最近更新 更多