【问题标题】:Convert LocalDateTime to LocalDateTime in UTC将 LocalDateTime 转换为 UTC 中的 LocalDateTime
【发布时间】:2016-04-10 03:29:16
【问题描述】:

将 LocalDateTime 转换为 UTC 中的 LocalDateTime。

LocalDateTime convertToUtc(LocalDateTime date) {

    //do conversion

}

我在网上搜索过。但没有得到解决方案

【问题讨论】:

  • 你找到 LocalDateTime 的 javadoc 了吗?它说:“这个类不存储或表示时区。相反,它是对日期的描述,用于生日,结合挂钟上的本地时间。它不能代表时间上的瞬间没有附加信息的时间线,例如偏移量或时区。"
  • 您的问题没有意义-您应该解释此方法的上下文以及您要实现的目标。您似乎对 API 的各个类所代表的含义存在根本性的误解。
  • 如果你关心时区,你需要使用 ZonedDateTime,它有时区之间的转换方法 withZoneSameLocal() 和 withZoneSameInstant()
  • 是的。我明白了。谢谢
  • 如果他们回答了问题,您可以接受以下答案之一。

标签: java java-8 utc java-time


【解决方案1】:

我个人比较喜欢

LocalDateTime.now(ZoneOffset.UTC);

因为它是最易读的选项。

【讨论】:

  • 这不是创造一个新的时间(现在)吗?最初的问题是关于将已知时间转换为 UTC
  • 我们如何将 LocalDateTime 转换为 UTC -7:00
  • 这不是问题的答案。
【解决方案2】:

LocalDateTime 不包含区域信息。 ZonedDatetime 可以。

如果要将 LocalDateTime 转换为 UTC,则需要用 ZonedDateTime 拳头换行。

你可以像下面这样转换。

LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt.toLocalTime());

ZonedDateTime ldtZoned = ldt.atZone(ZoneId.systemDefault());

ZonedDateTime utcZoned = ldtZoned.withZoneSameInstant(ZoneId.of("UTC"));

System.out.println(utcZoned.toLocalTime());

【讨论】:

  • 这是正确的,虽然在技术上没有包装。 ldt.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneId.of("UTC")) 虽然简洁仍然传达了足够的含义,不需要分区实例变量。
  • ZoneOffset.UTCZoneI‌​d.of("UTC") 的一个很好的替代品
  • 对于 UTC,OffsetDateTimeZonedDateTime 更合适。使用:OffsetDateTime.now( ZoneOffset.UTC )myInstant.atOffset( ZoneOffset.UTC )
【解决方案3】:

还有一个更简单的方法

LocalDateTime.now(Clock.systemUTC())

【讨论】:

  • 很好,但没有回答原来的问题。
  • 此答案将 UTC 日期转换为 LocalDate。最初的问题是如何将 LocalDate 转换为 UTC Date。
  • 我们如何将 LocalDateTime 转换为 UTC -7:00
【解决方案4】:

问题?

查看答案和问题,问题似乎已进行了重大修改。所以回答当前的问题:

将 LocalDateTime 转换为 UTC 中的 LocalDateTime。

时区?

LocalDateTime 不存储任何有关时区的信息,它只是基本保存年、月、日、小时、分钟、秒和更小单位的值。所以一个重要的问题是:原始LocalDateTime的时区是什么?它可能已经是UTC,因此不必进行转换。

系统默认时区

考虑到您还是问了这个问题,您可能意味着原始时间在您的系统默认时区中,并且您想将其转换为 UTC。因为通常LocalDateTime 对象是使用LocalDateTime.now() 创建的,它返回系统默认时区中的当前时间。在这种情况下,转换如下:

LocalDateTime convertToUtc(LocalDateTime time) {
    return time.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime();
}

转换过程的一个例子:

2019-02-25 11:39 // [time] original LocalDateTime without a timezone
2019-02-25 11:39 GMT+1 // [atZone] converted to ZonedDateTime (system timezone is Madrid)
2019-02-25 10:39 GMT // [withZoneSameInstant] converted to UTC, still as ZonedDateTime
2019-02-25 10:39 // [toLocalDateTime] losing the timezone information

显式时区

在任何其他情况下,当您明确指定要转换的时间的时区时,转换如下:

LocalDateTime convertToUtc(LocalDateTime time, ZoneId zone) {
    return time.atZone(zone).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime();
}

转换过程的一个例子:

2019-02-25 11:39 // [time] original LocalDateTime without a timezone
2019-02-25 11:39 GMT+2 // [atZone] converted to ZonedDateTime (zone is Europe/Tallinn)
2019-02-25 09:39 GMT // [withZoneSameInstant] converted to UTC, still as ZonedDateTime
2019-02-25 09:39 // [toLocalDateTime] losing the timezone information

atZone() 方法

atZone() 方法的结果取决于作为其参数传递的时间,因为它考虑了时区的所有规则,包括夏令时 (DST)。在示例中,时间是 2 月 25 日,在欧洲,这意味着冬季时间(没有 DST)。

如果我们使用不同的日期,比如去年的 8 月 25 日,考虑到 DST,结果会有所不同:

2018-08-25 11:39 // [time] original LocalDateTime without a timezone
2018-08-25 11:39 GMT+3 // [atZone] converted to ZonedDateTime (zone is Europe/Tallinn)
2018-08-25 08:39 GMT // [withZoneSameInstant] converted to UTC, still as ZonedDateTime
2018-08-25 08:39 // [toLocalDateTime] losing the timezone information

格林威治标准时间不变。因此调整其他时区的偏移量。在本例中,爱沙尼亚的夏令时为 GMT+3,冬令时为 GMT+2。

此外,如果您在将时钟更改回一小时的过渡中指定时间。例如。 2018 年 10 月 28 日 03:30 对爱沙尼亚来说,这可能意味着两个不同的时间:

2018-10-28 03:30 GMT+3 // summer time [UTC 2018-10-28 00:30]
2018-10-28 04:00 GMT+3 // clocks are turned back 1 hour [UTC 2018-10-28 01:00]
2018-10-28 03:00 GMT+2 // same as above [UTC 2018-10-28 01:00]
2018-10-28 03:30 GMT+2 // winter time [UTC 2018-10-28 01:30]

如果不手动指定偏移量(GMT+2 或 GMT+3),时区 Europe/Tallinn 的时间 03:30 可能意味着两个不同的 UTC 时间和两个不同的偏移量。

总结

如您所见,最终结果取决于作为参数传递的时间的时区。因为无法从LocalDateTime 对象中提取时区,所以您必须知道自己来自哪个时区才能将其转换为 UTC。

【讨论】:

  • 感谢有关 LocalDateTime 的信息不存储任何有关时区的信息! LocalDateTime does not store any information about the time-zone, it just basically holds the values of year, month, day, hour, minute, second, and smaller units.
【解决方案5】:

使用下面的。它采用本地日期时间并使用时区将其转换为 UTC。您不需要创建它的功能。

ZonedDateTime nowUTC = ZonedDateTime.now(ZoneOffset.UTC);
System.out.println(nowUTC.toString());

如果您需要获取 ZonedDateTime 的 LocalDateTime 部分,则可以使用以下内容。

nowUTC.toLocalDateTime();

这是我在应用程序中用于在 mysql 中插入 UTC 时间的静态方法,因为我无法将默认值 UTC_TIMESTAMP 添加到日期时间列。

public static LocalDateTime getLocalDateTimeInUTC(){
    ZonedDateTime nowUTC = ZonedDateTime.now(ZoneOffset.UTC);

    return nowUTC.toLocalDateTime();
}

【讨论】:

    【解决方案6】:

    这是一个简单的小实用程序类,可用于将本地日期时间从区域转换为区域,包括一个实用方法直接将本地日期时间从当前区域转换为 UTC(使用 main 方法,以便您可以运行它并查看简单测试的结果):

    import java.time.LocalDateTime;
    import java.time.ZoneId;
    import java.time.ZoneOffset;
    import java.time.ZonedDateTime;
    
    public final class DateTimeUtil {
        private DateTimeUtil() {
            super();
        }
    
        public static void main(final String... args) {
            final LocalDateTime now = LocalDateTime.now();
            final LocalDateTime utc = DateTimeUtil.toUtc(now);
    
            System.out.println("Now: " + now);
            System.out.println("UTC: " + utc);
        }
    
        public static LocalDateTime toZone(final LocalDateTime time, final ZoneId fromZone, final ZoneId toZone) {
            final ZonedDateTime zonedtime = time.atZone(fromZone);
            final ZonedDateTime converted = zonedtime.withZoneSameInstant(toZone);
            return converted.toLocalDateTime();
        }
    
        public static LocalDateTime toZone(final LocalDateTime time, final ZoneId toZone) {
            return DateTimeUtil.toZone(time, ZoneId.systemDefault(), toZone);
        }
    
        public static LocalDateTime toUtc(final LocalDateTime time, final ZoneId fromZone) {
            return DateTimeUtil.toZone(time, fromZone, ZoneOffset.UTC);
        }
    
        public static LocalDateTime toUtc(final LocalDateTime time) {
            return DateTimeUtil.toUtc(time, ZoneId.systemDefault());
        }
    }
    

    【讨论】:

    • 另外添加:final LocalDateTime backToLocal = DateTimeUtil.toZone(utc,ZoneOffset.UTC,ZoneId.systemDefault()); System.out.println("返回本地:" + backToLocal);
    【解决方案7】:

    用这个方法试试。

    使用 of 方法将您的 LocalDateTime 转换为 ZonedDateTime 并传递系统默认时区,或者您可以使用 ZoneId你的区域就像ZoneId.of("Australia/Sydney");

    LocalDateTime convertToUtc(LocalDateTime dateTime) {
      ZonedDateTime dateTimeInMyZone = ZonedDateTime.
                                            of(dateTime, ZoneId.systemDefault());
    
      return dateTimeInMyZone
                      .withZoneSameInstant(ZoneOffset.UTC)
                      .toLocalDateTime();
      
    }
    

    要转换回您所在区域的本地日期时间,请使用:

    LocalDateTime convertFromUtc(LocalDateTime utcDateTime){
        return ZonedDateTime.
                of(utcDateTime, ZoneId.of("UTC"))
                .toOffsetDateTime()
                .atZoneSameInstant(ZoneId.systemDefault())
                .toLocalDateTime();
    }
    

    【讨论】:

      【解决方案8】:

      tldr:根本没有办法做到这一点;如果您尝试这样做,您会得到 LocalDateTime 错误。

      原因是LocalDateTime在实例创建后没有记录时区。您不能将没有时区的日期时间转换为基于特定时区的另一个日期时间。

      事实上,LocalDateTime.now() 绝不应该在生产代码中调用,除非您的目的是获得随机结果。当您像这样构造 LocalDateTime 实例时,该实例仅包含基于当前服务器时区的日期时间,这意味着如果运行具有不同时区的服务器,这段代码将产生不同的结果配置。

      LocalDateTime 可以简化日期计算。如果您想要一个真正普遍可用的数据时间,请使用 ZonedDateTime 或 OffsetDateTime:https://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html

      【讨论】:

      • LocalDateTime 不记录时区,但您可能从其他地方获得此知识,并在转换前将此信息添加到您的 LocalDateTimes 中。
      【解决方案9】:

      你可以实现一个助手做类似的事情:

      public static LocalDateTime convertUTCFRtoUTCZ(LocalDateTime dateTime) {
          ZoneId fr = ZoneId.of("Europe/Paris");
          ZoneId utcZ = ZoneId.of("Z");
          ZonedDateTime frZonedTime = ZonedDateTime.of(dateTime, fr);
          ZonedDateTime utcZonedTime = frZonedTime.withZoneSameInstant(utcZ);
          return utcZonedTime.toLocalDateTime();
      }
      

      【讨论】:

      • UTC fr 到 UTC Z ?没有任何意义。 UTC = Z,UTC fr
      【解决方案10】:
      public static String convertFromGmtToLocal(String gmtDtStr, String dtFormat, TimeZone lclTimeZone) throws Exception{
              if (gmtDtStr == null || gmtDtStr.trim().equals("")) return null;
              SimpleDateFormat format = new SimpleDateFormat(dtFormat);
              format.setTimeZone(getGMTTimeZone());
              Date dt = format.parse(gmtDtStr);
              format.setTimeZone(lclTimeZone);
              return
      

      format.format(dt); }

      【讨论】:

      • 请不要教年轻人使用陈旧而臭名昭著的SimpleDateFormat类。至少不是第一选择。而且不是没有任何保留。今天我们在java.time, the modern Java date and time API 和它的DateTimeFormatter 中做得更好。
      猜你喜欢
      • 2014-11-16
      • 1970-01-01
      • 2021-11-26
      • 1970-01-01
      • 1970-01-01
      • 2020-05-08
      • 2020-01-11
      • 2020-05-19
      相关资源
      最近更新 更多