【问题标题】:Date TimeZone conversion日期时区转换
【发布时间】:2016-10-10 11:49:01
【问题描述】:

我已经完成了从 UTC 字符串到本地时区日期的转换方法,但它只返回与字符串中相同的日期。这里有什么问题?

 public static Date getUTCToDate(String utc){
    // String exampleOfUTCTime = "2016-09-27T19:35:32.717";

    try{
        Log.d("asd-timeBefore", "getUTCToDate: " + utc);
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
        formatter.setTimeZone(TimeZone.getDefault());
        Date d = formatter.parse(utc);
        Log.d("asd-timeAfter", "getUTCToDate: " + d);
        return d;
    } catch (ParseException e){
        e.printStackTrace();
    }
    return null;
}

【问题讨论】:

  • 您为格式化程序设置了错误的时区
  • 你想要的时区偏移量是多少?
  • 我需要使用本地时区,因为应用程序将在各个国家/地区使用

标签: java date datetime date-format simpledateformat


【解决方案1】:

尝试更改您的代码,像这样。它将UTC时区转换为本地时区:

public static Date getUTCToDate(String utc){
    // String exampleOfUTCTime = "2016-09-27T19:35:32.717";

    try{
        Log.d("asd-timeBefore", "getUTCToDate: " + utc);
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
        formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
        Date d = formatter.parse(utc);
        Log.d("asd-timeAfter", "getUTCToDate: " + d);
        return d;
    } catch (ParseException e){
        e.printStackTrace();
    }
    return null;
}

【讨论】:

  • 有效!但是怎么做?我收到像exampleOfUTCTime 这样的字符串,所以我想我需要将它转换为本地时区,但似乎Android/Java 自己关心本地时区。
  • 这个转换是系统自动完成的。如果您正在设置 UTC 时区 -> SimpleDateFormat 的想法是“好的,这是 UTC”,但是当您将其提供给 Date 时 -> 它会自动转换为本地时区。认为日期没有时区->内部函数具有使用默认时区(本地时区)的“SimpleDateFormatter”
【解决方案2】:

如果你想以 UTC 格式获取格式化的日期和时间,那么你应该这样做

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

【讨论】:

    【解决方案3】:

    setTimeZone 的答案是正确的,但作为替代方案,您可以尝试在字符串本身中指定 UTC 并表明您使用的是 SimpleDateFormat 类中的时区,例如:

    public static Date getUTCToDate(String utc){
        // String exampleOfUTCTime = "2016-09-27T19:35:32.717 UTC";
    
        try{
            System.out.println("getUTCToDate: " + utc);
            DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS z");
            Date d = formatter.parse(utc);
            System.out.println("getUTCToDate: " + d);
            return d;
        } catch (ParseException e){
            e.printStackTrace();
        }
        return null;
    }
    

    【讨论】:

      【解决方案4】:

      我需要使用本地时区,因为应用程序将在各个国家/地区使用。

      如果您想在服务器端使用客户端的时区格式化日期,那么您将必须以分钟为单位传递与 GMT 时间的偏移量,来自客户端。使用此 JavaScript 代码:

      var offset = new Date().getTimezoneOffset();
      

      然后将此偏移量作为参数传递给您的方法:

      public static Date getUTCToDate(String utc, int offsetInMinutes) {
          // String exampleOfUTCTime = "2016-09-27T19:35:32.717";
      
          try {
              Log.d("asd-timeBefore", "getUTCToDate: " + utc);
              DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z");
              long offset = -1L*60*1000*offsetInMinutes;
              String[] timezones = TimeZone.getAvailableIDs(offset);
              formatter.setTimeZone(timezones[0]);
              Date d = formatter.parse(utc);
              Log.d("asd-timeAfter", "getUTCToDate: " + d);
              return d;
          } catch (ParseException e){
              e.printStackTrace();
          }
          return null;
      }
      

      评论:

      您会注意到我在您的SimpleDateFormat 中包含了Z 作为日期格式参数。这将包括显示为从 GMT 时间偏移的时区。

      Java Date 只是一个时间点,不考虑偏移量。如果您想从客户那里获得时区信息,您必须自己提供。

      【讨论】:

        【解决方案5】:

        tl;博士

        LocalDateTime.parse( "2016-09-27T19:35:32.717" ).atZone( ZoneOffset.UTC )
        

        详情

        您的输入字符串不是 UTC 值:2016-09-27T19:35:32.717。该字符串缺少有关offset-from-UTCtime zone 的任何信息。

        您正在使用麻烦的旧日期时间类,现在是遗留的,被 java.time 类取代。

        LocalDateTime

        将该字符串解析为缺少任何偏移量或时区的 LocalDateTime 对象。

        该输入字符串恰好符合日期时间字符串的ISO 8601 标准。 java.time 类在解析/生成字符串时默认使用 ISO 8601 格式。所以不需要指定格式模式。

        LocalDateTime ldt = LocalDateTime.parse( "2016-09-27T19:35:32.717" );
        

        OffsetDateTime

        如果根据上下文您确定该字符串是为了表示 UTC 中的某个时刻,则应用偏移量以获取 OffsetDateTime。使用预定义的常量ZoneOffset.UTC

        OffsetDateTime odt = ldt.atZone( ZoneOffset.UTC );
        

        如果需要,您可以从那里使用DateTimeFormatter 生成各种格式的字符串。

        ZonedDateTime

        如果您想通过某个特定地区的时区镜头查看同一时刻,请申请ZoneId 以获取ZonedDateTime

        时区是与 UTC 的偏移量加上一组用于处理诸如夏令时 (DST) 等异常情况的规则。

        continent/region 的格式指定proper time zone name。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

        ZoneId z = ZoneId.of( "America/Montreal" );
        ZonedDateTime zdt = odt.atZoneSameInstant( z );
        

        如果需要,您可以获取用户当前的默认时区。但请注意,此默认值可能随时更改,即使 在运行时。因此,如果很重要,您应该询问用户预期/期望的时区,而不是假设。

        ZoneId z = ZoneId.systemDefault();
        

        关于java.time

        java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date.Calendarjava.text.SimpleDateFormat

        Joda-Time 项目现在位于 maintenance mode,建议迁移到 java.time。

        要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

        从哪里获得 java.time 类?

        ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

        【讨论】:

        • 这已经绰绰有余了。必须检查这些 - 看起来很有趣!
        猜你喜欢
        • 2019-10-24
        • 2013-01-17
        • 1970-01-01
        • 1970-01-01
        • 2019-12-21
        • 2016-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多