【问题标题】:Java UTC to Local time not working [duplicate]Java UTC到当地时间不起作用[重复]
【发布时间】:2018-02-10 12:29:50
【问题描述】:

我正在尝试将 UTC 转换为本地时间,

下面是我正在使用的代码,

public static String utcToLocalDateFormat(String dateString) {

        Log.i("DateFormat", "utcToLocal:Before===>" + dateString);

        String formattedDate = null;
        if (dateString != null) {
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            dateFormat.setTimeZone(TimeZone.getDefault());
            Date date = null;
            try {

                Log.i("DateFormat", "getTimeZone===>" +dateFormat.getTimeZone());
                date = dateFormat.parse(dateString);
                System.out.println(date);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            formattedDate = dateFormat.format(date);
            Log.i("DateFormat", "utcToLocal:After===>" + formattedDate);

        }
        return formattedDate;
    }

但问题是时区转换时间前后相同。它没有将UTC转换为本地时间。 任何帮助表示赞赏。

以下是我的输入: 1)2017-08-31 20:40:59 2)2017-09-01 11:16:24.024

以下是输出: 1)2017-08-31 20:40:59 2)2017-09-01 11:16:24

【问题讨论】:

  • 您能否提供一些输入和输出(预期与您得到的)?
  • 你的dateFormat将输入解析为本地TZ可以吗?
  • 在您的日期格式模式中,您没有将在哪个时区传递给您的方法的信息。所以字符串被解析,因为它已经在默认时区。
  • 在解析前将dateFormat的时区设置为UTC,以获得正确的UTC时间。然后在格式化之前将其设置为您当地的时区。
  • 类似的问题已经被问过很多次了。我想知道您是否可以通过例如Java Convert GMT/UTC to Local time doesn't work as expectedJava: How do you convert a UTC timestamp to local time? 更快地找到答案。通过发布您自己的问题表示感谢。

标签: java android date timezone simpledateformat


【解决方案1】:

换行

dateFormat.setTimeZone(TimeZone.getDefault());

dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));

【讨论】:

    【解决方案2】:

    当你这样做时:

    dateFormat.setTimeZone(TimeZone.getDefault());
    

    然后解析String,你对格式化程序说:“我会给你一个带有这个时区日期和时间的字符串”。当您使用TimeZone.getDefault() 时,它将使用JVM 的默认时区。所以第一件事就是告诉格式化程序在解析时使用UTC:

    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    // use UTC to parse
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    ....
    date = dateFormat.parse(dateString);
    

    我正在测试 dateString 等于 2017-08-01 10:00:00。因此,date 将等同于 2017-08-01 10:00:00 UTC。当您使用System.out.println 打印日期时,它会调用toString() 并将其转换为JVM 的默认时区。

    在我使用的JVM中,默认时区是America/Sao_Paulo,所以当我调用这个时:

    System.out.println(date);
    

    打印出来:

    2017 年 8 月 1 日星期二 07:00:00 BRT

    因为在 8 月 1 日st,UTC 的上午 10 点相当于圣保罗的上午 7 点。 这将根据您的 JVM 的默认时区而改变

    如果您想打印此日期,但日期和时间与另一个时区(UTC 除外)相同,则需要另一个设置不同时区的格式化程序:

    DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    // use my default timezone to format (America/Sao_Paulo)
    dateFormat2.setTimeZone(TimeZone.getDefault());
    formattedDate = dateFormat2.format(date);
    

    这将打印:

    2017-08-01 07:00:00

    您可以使用任何您想要的时区来代替默认时区(我以America/New_York 为例):

    DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    // use New York timezone
    dateFormat2.setTimeZone(TimeZone.getTimeZone("America/New_York"));
    formattedDate = dateFormat2.format(date);
    

    这会将日期/时间转换为纽约的时区:

    2017-08-01 06:00:00

    如果您想以 UTC 格式打印日期/时间,则无需创建另一个格式化程序,只需使用第一个格式化程序(因为它已设置为 UTC)。


    JVM 的默认时区can be changed without notice, even at runtime,因此最好使用特定的时区而不是仅使用getDefault()

    首选使用IANA timezones names(始终采用Region/City 的格式,如America/Sao_PauloEurope/Berlin)。 避免使用三个字母的缩写(如CSTPST),因为它们是ambiguous and not standard

    您可以致电TimeZone.getAvailableIDs() 获取可用时区列表(并选择最适合您系统的时区)。


    新的日期/时间 API

    旧的类(DateCalendarSimpleDateFormat)有 lots of problemsdesign issues,它们正在被新的 API 取代。

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

    此 API 更易于使用。首先创建一个org.threeten.bp.format.DateTimeFormatter 并将输入String 解析为org.threeten.bp.LocalDateTime

    然后将其转换为 UTC(创建 org.threeten.bp.ZonedDateTime),然后转换为您想要的时区,并使用另一个格式化程序来输出它:

    // date/time with optional milliseconds
    DateTimeFormatter parser = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.SSS]");
    // parse to LocalDateTime
    LocalDateTime dt = LocalDateTime.parse(dateString, parser);
    
    // convert to UTC
    ZonedDateTime z = dt.atZone(ZoneOffset.UTC);
    
    // convert to another timezone
    z = z.withZoneSameInstant(ZoneId.of("America/New_York"));
    // format it
    // date/time without milliseconds
    DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    System.out.println(fmt.format(z));
    

    您还可以使用ZoneId.systemDefault() 使用默认时区,并使用ZoneId.getAvailableZoneIds() 获取所有可用时区。

    如果您想要 UTC 日期/时间,您可以跳过对withZoneSameInstant() 的调用。


    要将其转换为java.util.Date,您可以使用org.threeten.bp.DateTimeUtils 类:

    // convert ZonedDateTime to java.util.Date
    Date d = DateTimeUtils.toDate(z.toInstant());
    

    【讨论】:

    • 谢谢,但我不想像你提到的那样指定时区 (TimeZone.getTimeZone("America/New_York")),我的应用程序使用了它应该根据该时区工作的世界任何地方。跨度>
    • @Joe 我已经更新了答案以使其更加清晰。
    猜你喜欢
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 2015-09-26
    • 2019-08-25
    • 2016-02-15
    • 2020-01-13
    • 1970-01-01
    • 2014-07-06
    相关资源
    最近更新 更多