【问题标题】:Converting UTC dates to other timezones将 UTC 日期转换为其他时区
【发布时间】:2011-08-30 15:12:56
【问题描述】:

我正在使用这种方法将 UTC 时间转换为另一个时区:

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date parsed = format.parse("2011-03-01 15:10:37");
TimeZone tz = TimeZone.getTimeZone("America/Chicago");
format.setTimeZone(tz);

String result = format.format(parsed);

所以输入是2011-03-01 15:10:37,但是这个(结果的值)的输出是2011-03-01 05:40:37。虽然它似乎关闭了,但根据this link,它应该是2011-03-01 09:10:37

我做错了什么?

【问题讨论】:

    标签: android datetime timezone


    【解决方案1】:

    事实证明代码几乎是正确的,我没有考虑到最初解析String以获取Date对象时,它使用默认系统TimeZone,所以源日期是不像我预期的那样在UTC。

    诀窍是在将日期解析为 UTC 时设置时区,然后将其设置为目的地 TimeZone。像这样的:

    SimpleDateFormat sourceFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    sourceFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    Date parsed = sourceFormat.parse("2011-03-01 15:10:37"); // => Date is in UTC now
    
    TimeZone tz = TimeZone.getTimeZone("America/Chicago");
    SimpleDateFormat destFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    destFormat.setTimeZone(tz);
    
    String result = destFormat.format(parsed);
    

    【讨论】:

    • 不要忘记try{} catch (ParseException e){} 周围的sourceFormat.parse()。此外,要获取手机所在的本地时区,请使用 TimeZone.getDefault() 以便您可以将 UTC 转换为本地时区
    • @hadi Eskandari 伙计,你刚刚救了我!我正在撕扯我的头发试图解决这个问题......!在显示到屏幕之前,我从我们的服务器中提取值并存储到数据库中。服务器日期存储在 AEST(澳大利亚东部标准)中,我遇到了您使用默认系统时区的确切问题,因此解释时间错误。当我尝试更改为另一个日期时,它总是错误的:) 我只需要在解析行之前formater.setTimeZone(TimeZone.getTimeZone(RBApplication.adjustTimezoneAEST));。干杯我在这个问题上花了几个小时!
    • @wired00 很高兴听到这对伴侣有帮助:)
    • SimpleDateFormat 中的“HH”是 24 小时而不是 12 小时,这占用了我 2 小时的调试时间
    【解决方案2】:

    将格式为“2011-06-23T15:11:32”的日期字符串转换为时区。

     private String getDate(String dateString) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
        Date value = null;
        try {
            value = formatter.parse(dateString);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        SimpleDateFormat dateFormatter = new SimpleDateFormat("dd/MM/yyyy hh:mmaa");
        dateFormatter.setTimeZone(TimeZone.getDefault());
        String dt = dateFormatter.format(value);
    
        return dt;
    }
    

    【讨论】:

      【解决方案3】:

      以下代码对我来说可以很好地将日期从一个 tz 更改为另一个。它也考虑了 DayLightSaving。

      public static Calendar changeTimezoneOfDate(Date date, TimeZone fromTZ, TimeZone toTZ) {
          Calendar calendar = Calendar.getInstance();
          calendar.setTime(date);
          long millis = calendar.getTimeInMillis();
          long fromOffset = fromTZ.getOffset(millis);
          long toOffset = toTZ.getOffset(millis);
          long convertedTime = millis - (fromOffset - toOffset);
          Calendar c = Calendar.getInstance();
          c.setTimeInMillis(convertedTime);
          return c;
      }
      

      【讨论】:

        【解决方案4】:

        您可以根据需要解析日期格式和时区。 试试这个sn-p的代码,希望对你有帮助。

        private String getFormattedDate(String OurDate) {
            try {
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); // According to your Server TimeStamp
                formatter.setTimeZone(TimeZone.getTimeZone("UTC")); //your Server Time Zone
                Date value = formatter.parse(OurDate); // Parse your date
        
                SimpleDateFormat dateFormatter = new SimpleDateFormat("MM-dd-yyyy"); //this format changeable according to your choice
                dateFormatter.setTimeZone(TimeZone.getDefault());
                OurDate = dateFormatter.format(value);
        
            } catch (Exception e) {
                OurDate = "00-00-0000 00:00";
        
            }
            return OurDate;
        }
        

        【讨论】:

          【解决方案5】:

          您需要考虑夏令时。我通过以毫秒为单位计算出偏移量(来自 UTC)来做到这一点。这样的事情应该可以工作。

          int currentOffsetFromUTC = tz.getRawOffset() + (tz.inDaylightTime(parsed) ? tz.getDSTSavings() : 0);
          String result = format.format(parsed.getTime() + currentOffsetFromUTC);
          

          inDayLightTime(...) 方法返回一个布尔值,并且必须传递一个 Date 对象,以便它决定该“日期”是否代表 DST 期间的日期。

          【讨论】:

            【解决方案6】:

            java.time

            考虑使用现代 Java 日期和时间 API java.time 进行日期和时间工作。

                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
                ZoneId targetZone = ZoneId.of("America/Chicago");
                
                LocalDateTime parsed = LocalDateTime.parse("2011-03-01 15:10:37", formatter);
                ZonedDateTime converted = parsed.atOffset(ZoneOffset.UTC).atZoneSameInstant(targetZone);
            
                String result = converted.format(formatter);
                System.out.println(result);
            

            输出是预期的:

            2011-03-01 09:10:37

            问题:java.time 不需要 Android API 26 级吗?

            java.time 在较旧和较新的 Android 设备上都能很好地工作。它只需要至少 Java 6

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

            链接

            【讨论】:

              【解决方案7】:

              我选择的简单顺序是将 UTC 时间解析为 LocalDateTime,然后创建一个带有所需时区的 ZonedDateTime。生成的ZonedDateTime 可用于获取Instant 以构造新的Date 对象。

              在下面的示例 sn-p 中,可以将 ZoneId.systemDefault() 替换为所需的时区 id。

              
              var instant = LocalDateTime.parse(serverDateTime, DateTimeFormatter.ISO_DATE_TIME)
                              .atZone(ZoneId.of("UTC")) //the current zone is UTC
                              .withZoneSameInstant(ZoneId.systemDefault()) //the new time zone
                              .toInstant();
              
              var date = Date.from(instant);
              
              

              注意:要在低于 26 的 Android API 级别中使用 LocalDateTime,您可以将 Android desugaring lib 添加到您的代码库中。

              【讨论】:

                猜你喜欢
                • 2021-03-15
                • 2021-03-12
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-09-07
                • 2021-03-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多