在Android中将UTC日期转换为当地时间?

Rev*_*eva 0 java timezone datetime android jodatime

我有一个String类似的日期2017-09-16T05:06:18.157,我想将其转换为当地时间 (IST)。在印度标准时间,它将在2017-09-16 10:36:18

使用 Joda-Time,我尝试将其转换为本地,但我无法做到。

下面是我的代码:

private String getConvertDate(String date_server) {
    DateTimeFormatter inputFormatter = DateTimeFormat
            .forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
            .withLocale(Locale.US);

    DateTime parsed = inputFormatter.parseDateTime(date_server);

    DateTimeFormatter outputFormatter = DateTimeFormat
            .forPattern("yyyy-MM-dd HH:mm:ss")
            .withLocale(Locale.US)
            .withZone(DateTimeZone.getDefault());

    return outputFormatter.print(parsed);
}
Run Code Online (Sandbox Code Playgroud)

小智 6

很好,你找到了一个解决方案SimpleDateFormat。我只想添加更多关于它的见解(主要是因为旧类(Date,CalendarSimpleDateFormat)有很多问题设计问题,并且它们正在被新的 API 取代)。

输入String( 2017-09-16T05:06:18.157) 仅包含日期(年/月/日)和时间(时/分/秒/毫秒),但不包含时区信息。所以,当调用parseDateTime,Joda-Time 只是假设它位于 JVM 默认时区。

如果您知道输入是 UTC,但输入本身没有关于它的信息,您必须告诉它。一种方法是在格式化程序中设置:

// set the formatter to UTC
DateTimeFormatter inputFormatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
    .withZone(DateTimeZone.UTC);

// DateTime will be in UTC
DateTime parsed = inputFormatter.parseDateTime("2017-09-16T05:06:18.157");
Run Code Online (Sandbox Code Playgroud)

另一种选择是首先将输入解析为 a org.joda.time.LocalDateTime(表示没有时区的日期和时间的类),然后将其转换为DateTimeUTC 格式的 a:

// parse to LocalDateTime
DateTime = parsed = LocalDateTime.parse("2017-09-16T05:06:18.157")
    // convert to a DateTime in UTC
    .toDateTime(DateTimeZone.UTC);
Run Code Online (Sandbox Code Playgroud)

两者产生相同的DateTime,对应于 UTC 2017-09-16T05:06:18.157Z

要将其格式化为“IST 时区”(实际上不是时区 - 更多内容见下文),您还可以在格式化程序中设置时区:

// convert to Asia/Kolkata
DateTimeFormatter outputFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
    .withZone(DateTimeZone.forID("Asia/Kolkata"));
System.out.println(outputFormatter.print(parsed));
Run Code Online (Sandbox Code Playgroud)

或者您可以DateTime使用以下withZone()方法将 转换为另一个时区:

DateTimeFormatter outputFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
// convert to Asia/Kolkata
System.out.println(outputFormatter.print(parsed.withZone(DateTimeZone.forID("Asia/Kolkata"))));
Run Code Online (Sandbox Code Playgroud)

两者都会打印:

2017-09-16 10:36:18

在您使用的代码中DateTimeZone.getDefault(),它获取 JVM 默认时区(带有一些棘手的细节)。但是默认时区可以在没有通知的情况下更改,即使在运行时也是如此,因此最好指定要使用的时区。

另外,请记住,像IST这样的短名称不是真正的时区。始终更喜欢使用IANA 时区名称(始终采用 格式Region/City,如Asia/KolkataEurope/Berlin)。

避免使用 3 个字母的缩写(如ISTPST),因为它们含糊不清且不标准。只需在此列表中检查IST 可以是“印度标准时间”、“以色列标准时间”和“爱尔兰标准时间”。

您可以通过调用获取可用时区列表(并选择最适合您系统的时区)DateTimeZone.getAvailableIDs()


Java 新的日期/时间 API

Joda-Time 处于维护模式,正在被新的 API 取代,所以我不建议用它开始一个新项目。甚至在joda 的网站上也写着:“请注意,Joda-Time 被认为是一个很大程度上“完成”的项目。没有计划进行重大改进。如果使用 Java SE 8,请迁移到 java.time(JSR-310)。” .

如果您不能(或不想)从 Joda-Time 迁移到新 API,则可以忽略此部分。

在 Android 中,您可以使用ThreeTen Backport,这是 Java 8 新日期/时间类的一个很好的向后移植。为了让它工作,你还需要ThreeTenABP(更多关于如何使用它在这里)。

这个新 API为每种情况提供了许多不同的日期/时间类型

首先,您可以将输入解析为 a org.threeten.bp.LocalDateTime,然后我使用 aorg.threeten.bp.ZoneOffset将其转换为 UTC,从而生成org.threeten.bp.OffsetDateTime.

然后,我使用 aorg.threeten.bp.ZoneId将其转换为另一个时区,并使用 a 对其org.threeten.bp.format.DateTimeFormatter进行格式化(这基本上是@Ole VV 的评论所建议- 只是为了表明它是多么简单,因为没有什么不同的事情要做):

// parse to LocalDateTime
OffsetDateTime parsed = LocalDateTime.parse("2017-09-16T05:06:18.157")
    // convert to UTC
    .atOffset(ZoneOffset.UTC);

// convert to Asia/Kolkata
ZoneId zone = ZoneId.of("Asia/Kolkata");
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(outputFormatter.format(parsed.atZoneSameInstant(zone)));
Run Code Online (Sandbox Code Playgroud)

输出是:

2017-09-16 10:36:18