将LocalDateTime转换为UTC中的LocalDateTime

145

将LocalDateTime转换为UTC中的LocalDateTime。

LocalDateTime convertToUtc(LocalDateTime date) {

    //do conversion

}

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


6
你是否找到了LocalDateTime类的javadoc文档?其中写道:“该类不存储或表示时区。相反,它是一种日期描述方式,例如出生日期,与墙上时钟显示的本地时间结合。如果没有额外的信息,例如偏移量或时区,它无法表示时间线上的瞬间。” - aro_tech
1
你的问题没有意义 - 你应该解释一下这个方法的上下文以及你想要实现什么。看起来你对API的各种类别有基本的误解。 - assylias
3
如果您关心时区,您需要使用ZonedDateTime,它具有与ZoneSameLocal()和withZoneSameInstant()相关的时区转换方法。 - JodaStephen
嗯,我明白了。谢谢。 - skmaran.nr.iras
如果有人回答了你的问题,你可以接受以下任意一个答案。 - Snackoverflow
这个回答了这个问题:https://dev59.com/cFsW5IYBdhLWcg3wwZYP#64832898 - Habeeb Okunade
10个回答

184

我个人更喜欢

LocalDateTime.now(ZoneOffset.UTC);

因为它是最易读的选项。


61
这是否会创建一个新的时间(现在)?最初的问题是关于将已知时间转换为UTC。 - Evvo
我们如何将LocalDateTime转换为UTC-7:00? - Ashok kumar Ganesan
9
这不是被问问题的答案。 - Ashish
这个回答了这个问题:https://dev59.com/cFsW5IYBdhLWcg3wwZYP#64832898 - Habeeb Okunade

108

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());

2
这是正确的,虽然不是技术上包装的。ldt.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneId.of("UTC"))虽然简洁,但仍然传达了足够的含义,不需要使用时区实例变量。 - Brett Ryan
36
ZoneOffset.UTCZoneId.of("UTC") 的一个很好的替代品。 - ycomp
3
对于 UTC 时间,相比于 ZonedDateTime,使用 OffsetDateTime 更为合适。可以使用下面的语句:OffsetDateTime.now( ZoneOffset.UTC ) 或者 myInstant.atOffset( ZoneOffset.UTC ) - Basil Bourque

80

有一种更简单的方法。

LocalDateTime.now(Clock.systemUTC())

45
好的,但并没有回答原始问题。 - eirirlar
5
这个答案将UTC日期转换为本地日期。原始问题是如何将本地日期转换为UTC日期。 - Cypress Frankenfeld
我们如何将LocalDateTime转换为UTC-7:00? - Ashok kumar Ganesan

34

问题?

看起来问题已经被大幅修改,因此回答当前的问题:

将 LocalDateTime 转换为 UTC 中的 LocalDateTime。

时区?

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

系统默认时区

考虑到您无论如何都提出了问题,您可能指的是原始时间位于系统默认时区,并且您想将其转换为UTC。因为通常使用 LocalDateTime.now() 创建 LocalDateTime 对象,该方法返回系统默认时区的当前时间。在这种情况下,转换如下:

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。


2
感谢您提供的信息,关于LocalDateTime不存储任何有关时区的信息! LocalDateTime不存储任何有关时区的信息,它只是基本保存年、月、日、小时、分钟、秒和更小的单位的值。 - LiuWenbin_NO.
嗯,了解了。 - NSV.

16

这是一个简单的实用类,可以将本地日期时间从一个时区转换成另一个时区,包括一种直接将当前时区的本地日期时间转换为UTC的实用方法(带有主方法,以便您可以运行它并查看简单测试的结果):

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); - rjdkolb
如果您想将LocalDateTime.MIN转换为UTC LocalDateTime,则会出现以下异常:EpochDay的值无效(有效值为-365243219162 - 365241780471):-365243219163 java.time.DateTimeException: EpochDay的值无效(有效值为-365243219162 - 365241780471):-365243219163 - iamcrypticcoder

15

使用以下代码。它会将本地日期时间转换为UTC,并使用时区。您无需创建该函数。

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

如果你需要获取ZonedDateTime中的LocalDateTime部分,可以使用以下方法。

nowUTC.toLocalDateTime();

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

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

    return nowUTC.toLocalDateTime();
}

13

使用这种方法来尝试。

通过使用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();
}

5
简而言之,这是不可能的;如果你正在尝试这样做,那么你会错误地使用 LocalDateTime
原因是在实例创建后, LocalDateTime 不记录时区。你无法将没有时区的日期时间转换为基于特定时区的另一个日期时间。
事实上, LocalDateTime.now() 在生产代码中永远不应该被调用,除非你的目的是获取随机结果。当你像这样构造 LocalDateTime 实例时,此实例仅包含基于当前服务器时区的日期时间,这意味着如果它在具有不同时区配置的服务器上运行,则此代码片段将生成不同的结果。 LocalDateTime 可以简化日期计算。如果你想要一个真正通用的数据时间,请使用ZonedDateTime或OffsetDateTime:https://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html

LocalDateTime不记录时区,但您可以从其他地方获取此信息并在转换之前将其添加到您的LocalDateTime中。 - Tristan

-1
你可以实现一个辅助函数来完成类似这样的操作:
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。 - Tristan

-2
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); }


3
请不要教导年轻人使用早已过时且以问题闻名的SimpleDateFormat类,至少不应作为首选选项,并且不应毫无保留地使用。今天,我们有更好的选择,即java.time现代Java日期和时间API及其DateTimeFormatter - Ole V.V.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接