【问题标题】:Convert hour minute string time to utc and vice versa将小时分钟字符串时间转换为UTC,反之亦然
【发布时间】:2019-03-20 00:50:57
【问题描述】:

我正在尝试采用“HH:mm”格式的字符串并将其从本地转换为 utc,反之亦然。到目前为止,这是我所拥有的:

    private String doTimeConversion(String time, boolean type) {

    DateFormat dfLocal = new SimpleDateFormat("HH:mm");
    DateFormat dfUTC   = new SimpleDateFormat("HH:mm");
    TimeZone local =  TimeZone.getDefault();
    TimeZone utc   =  TimeZone.getTimeZone("UTC");

    dfLocal.setTimeZone(local);
    dfUTC.setTimeZone(utc);

    Date date;
    String newTime = "00:00";
    try {
        //If true: local to utc/If false: utc to local
        if (type) {
            date = dfLocal.parse(time);
            newTime = dfUTC.format(date);
        } else {
            date = dfUTC.parse(time);
            newTime = dfLocal.format(date);
        }

    } catch (ParseException e) {
        e.printStackTrace();
    }
    return newTime;
}

这似乎主要工作,但我遇到的问题是,虽然我应该使用 TimeZone.getDefault() 来获取设备时间,但它没有考虑夏令时。不是将 12:00(UTC) 更改为 08:00(EDT),而是将其更改为 07:00(EST)。

总的来说,我只是希望能够花费用户输入的时间(字符串)并使用设备时区来假设用户输入的内容是根据他们的时区并将其转换为 utc 以及从UTC 回到设备时区。

【问题讨论】:

  • 那么我们应该假设今天的日期还是哪个日期?为了知道我们是否在夏令时(DST)。 (SimpleDateFormat 假设为 1970 年 1 月 1 日。)
  • 仅供参考,java.util.Date、java.util.Calendar 和 java.text.SimpleDateFormat 等麻烦的旧日期时间类现在已被 java.time 类所取代。大多数 java.time 功能在 ThreeTen-Backport 项目中被反向移植到 Java 6 和 Java 7。在ThreeTenABP 项目中进一步适用于早期的Android。见How to use ThreeTenABP…。

标签: java android datetime timezone


【解决方案1】:

java.time

import org.threeten.bp.LocalDate;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.LocalTime;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;

public class ConvertTimeToAndFromUtc {

    /** @param type If true: local to utc/If false: utc to local */
    private static String doTimeConversion(String time, boolean type) {
        ZoneId localZone = ZoneId.systemDefault();
        LocalTime lt = LocalTime.parse(time);
        LocalDateTime ldt = LocalDate.now(localZone).atTime(lt);
        ZonedDateTime resultTime;
        if (type) {
            resultTime = ldt.atZone(localZone).withZoneSameInstant(ZoneOffset.UTC);
        } else {
            resultTime = ldt.atOffset(ZoneOffset.UTC).atZoneSameInstant(localZone);
        }
        LocalTime newTime = resultTime.toLocalTime();
        return newTime.toString();
    }

    public static void main(String[] args) {
        System.setProperty("user.timezone", "Asia/Gaza");

        System.out.println("09.21 local to UTC: " + doTimeConversion("09:21", true));
        System.out.println("23:13 UTC to local: " + doTimeConversion("23:13", false));
    }

}

今天打印出上述程序(在 Java 7 上测试):

09.21 local to UTC: 06:21
23:13 UTC to local: 02:13

加沙地带的偏移量在每年的这个时候是 +03:00,在标准/正常时间是 +02:00,因此转换似乎考虑了夏令时 (DST)(后一种转换是经过午夜)。

我正在使用 java.time,现代 Java 日期和时间 API。您使用的日期时间类DateFormat、SimpleDateFormat、TimeZone 和Date 都早已过时,并带有一系列设计问题。而且它们也不是真正适合手头的问题。

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

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

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

链接

【讨论】:

  • 这似乎运作良好,我现在已经实现了 ThreeTenABP,但我遇到了一个奇怪的问题,“America/New_York”的偏移量与 -04:56:02[America/ New_York] 当我非常肯定时,它应该只是-04:00:00。但是,您示例中的时区可以正常工作。
  • @KentJ。直到 1882 年,纽约的偏移量为 -4:56:02!您的日期时间会落在这段历史时期吗? Time Zone in New York, New York, USA,从下拉列表中选择 1800–1849 或 1850–1899。
  • 是的,当将年份传递给我的 LocalDateTime 时,我给了它一个 2 位数字(从格式为 MM/dd/yy 的字符串解析),我猜这使它相信年份是 0018 而不是 2018。难以置信。感谢您的帮助。
【解决方案2】:

使用 ThreeTenABP 我能够将我的代码转换为以下内容:

    /**
     * @param d      int arr that holds date vals
     * @param from   Time zone to convert from
     * @param to     Time zone to convert to
     * @return       Converted date as String
     */
    protected String doConvertTime(int[] d, ZoneId from, ZoneId to, DateTimeFormatter format){
        LocalDateTime before = LocalDateTime.of(d[0], d[1], d[2], d[3], d[4]);
        ZonedDateTime beforeTime = ZonedDateTime.of(before, from);
        ZonedDateTime afterTime = beforeTime.withZoneSameInstant(to);
        return afterTime.format(format);
    }

int[] d:

我正在解析保存值的字符串片段,并将它们放入一个整数数组中,该数组传递给上面显示的函数。这似乎比直接从字符串解析更容易,因为我正在使用多个字符串。通过这种方式,我能够确保所有数据都集中在一个区域中。

ZoneId from & ZoneId to:

我在 main 函数的开头初始化了两个 ZoneId,这样我可以互换使用它们。例如。本地到 utc:从 = 本地,到 = utc / utc 到本地:从 = utc,到 = 本地。实际上可以使用任何两个时区。

DateTimeFormatter 格式:

我只想返回格式为“MM/dd/yy”或“HH:mm”的字符串,因为这就是我之前保存这些值的字符串是如何分开的。但是,我需要有关日期的所有数据,以确保使用正确的时区,并且不会因时区更改而更改日期、月份甚至年份。例如。 2018-12-31 22:00 (EST) "America/New_York" --> 2019-01-01 03:00 (UTC) (-05:00 offset) 如果我只有时间 (HH:mm) 值那么日期不会改变。

【讨论】:

  • 感谢分享您的解决方案。将字符串片段解析为 ints 是非标准的,我不一定相信这是最好的解决方案,但无论对你有用并让你开心……
  • 毫无疑问,将我的字符串解析为ints 并不是最好的解决方案,我当然不建议其他人这样做。这正是目前对我有用的方法,也许稍后我会回来寻找更好的方法。
猜你喜欢
  • 2016-03-03
  • 1970-01-01
  • 2016-09-20
  • 1970-01-01
  • 2019-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多