如何在 Java 8 中将 LocalDateTime 转换为 Date

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39628885/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 21:18:21  来源:igfitidea点击:

How convert LocalDateTime to Date in Java 8

javadatetimejava-8

提问by André Henriques

I'm using timezone Brazil by default, but when caught one LocalDateTime of New York and convert to java.tim.Instantthe instantis filled correctly. The problem is when I try to generate a Datewith Date.from (instantValue), instead of being generated a dateof New York, I end up getting the current date from Brazil.

我默认使用时区巴西,但是当捕获纽约的一个 LocalDateTime 并转换为java.tim.Instant 时即时被正确填充。问题是当我尝试使用Date.from (instantValue)生成日期时,而不是生成纽约的日期,我最终从巴西获取了当前日期。

ZoneId nyZone = ZoneId.of("America/New_York");
ZoneId brazilZone = ZoneId.of("America/Recife");

LocalDateTime ldtBrazil = LocalDateTime.now(brazilZone);
LocalDateTime ldtNY = LocalDateTime.now(nyZone);

Instant instantBrazil = ldtBrazil.toInstant(ZoneOffset.UTC);
Instant instantNY = ldtNY.toInstant(ZoneOffset.UTC);

System.out.println("-------LocalDateTime-------");
System.out.println("ldtBrazil    : "+ldtBrazil);
System.out.println("ldtNY        : "+ldtNY);

System.out.println("\n-------Instant-------");
System.out.println("instantBrazil: "+instantBrazil);
System.out.println("instantNY    : "+instantNY);

long milliBrazil = instantBrazil.toEpochMilli();
long milliNY = instantNY.toEpochMilli();

System.out.println("\n----------Milli----------");
System.out.println("miliBrazil : "+milliBrazil);
System.out.println("miliNY     : "+milliNY);

Date dateBrazil = Date.from(instantBrazil);
Date dateNY = Date.from(instantNY);

System.out.println("\n---------Date From Instant---------");
System.out.println("dateBrazil: "+dateBrazil);
System.out.println("dateNY    : "+dateNY);

System.out.println("\n---------Date From Milli---------");
System.out.println("dateBrazil: "+new Date(milliBrazil));
System.out.println("dateNY    : "+new Date(milliNY));

Result

结果

-------LocalDateTime-------
ldtBrazil    : 2016-09-21T22:11:52.118
ldtNY        : 2016-09-21T21:11:52.118

-------Instant-------
instantBrazil: 2016-09-21T22:11:52.118Z
instantNY    : 2016-09-21T21:11:52.118Z

----------Milli----------
miliBrazil : 1474495912118
miliNY     : 1474492312118

---------Date From Instant---------
dateBrazil: Wed Sep 21 19:11:52 BRT 2016
dateNY    : Wed Sep 21 18:11:52 BRT 2016 //this data must be related to   NY LocalDateTime, but reiceved a same date of Brazil.

---------Date From Milli---------
dateBrazil: Wed Sep 21 19:11:52 BRT 2016
dateNY    : Wed Sep 21 18:11:52 BRT 2016

采纳答案by Basil Bourque

LocalDateTimemeans no zone

LocalDateTime意味着没有区域

You seem to misunderstand the purpose of LocalDateTime.

你似乎误解了 的目的LocalDateTime

This class has no time zone and no offset-from-UTC. It is nota point on the timeline. Rather it represents a vague idea about possible moments. The name “Local…” may be counter-intuitive as it does notrepresent any particular locality, but rather anylocality.

此类没有时区,也没有offset-from-UTC。这不是时间线上的一个点。相反,它代表了一个关于可能时刻的模糊想法。命名为“本地...”可能是违反直觉的,因为它不会表示任何特定地区,而是任何地方。

For example, Christmas this year is midnight at start of December 25, 2016, or 2016-12-25T00:00. This has no meaning until you apply a time zone to get Christmas in Auckland NZ or Kolkata IN or Paris FR or Montréal CA, each being a different point on the timeline, getting later and later as you go westward.

例如,今年的圣诞节是 2016 年 12 月 25 日开始的午夜,或2016-12-25T00:00。除非您在新西兰奥克兰或加尔各答或巴黎 FR 或加州蒙特利尔应用时区来获得圣诞节,否则这没有任何意义,每个时区都是时间线上的不同点,随着您向西走,时间会越来越晚。

Never use LocalDateTimebecause you think it will save you the hassle of zones and offsets. Just the opposite, you'll be digging yourself into a hole with ambiguous date-time values.

永远不要使用,LocalDateTime因为您认为它会为您省去区域和偏移量的麻烦。恰恰相反,您将陷入一个日期时间值不明确的坑中。

Focus on UTC

专注于UTC

Most of your business logic, logging, data storage, and data exchange should all be in UTC. Think of UTC as the one true time; all the other zones and offsets are masquerading as dressed-up UTC values.

您的大部分业务逻辑、日志记录、数据存储和数据交换都应采用UTC格式。将 UTC 视为唯一的真实时间;所有其他区域和偏移量都伪装成精心设计的 UTC 值。

In java.time, that means the Instantclass is your go-to class, the basic building-blocks of date-time objects. The Instantclass represents a moment on the timeline in UTCwith a resolution of nanoseconds.

在 java.time 中,这意味着Instant该类是您的首选类,是日期时间对象的基本构建块。该Instant级表示时间轴上的时刻UTC,分辨率为纳秒

Instant now = Instant.now();

ZonedDateTime

ZonedDateTime

Adjust into time zones only where required to access the wall-clock timeof some region. Apply a ZoneIdto get a ZonedDateTimeobject.

仅在需要访问某些地区的挂钟时间时才调整到时区。应用 aZoneId来获取一个ZonedDateTime对象。

ZoneId zNewYork = ZoneId.of("America/New_York");
ZoneId zRecife = ZoneId.of("America/Recife");

ZonedDateTime zdtNewYork = now.atZone( zNewYork );
ZonedDateTime zdtRecife = now.atZone( zRecife );

All three of these objects, now, zdtNewYork, and zdtRecife, are all the very some moment, the same simultaneous point on the timeline. All three share the same count-from-epoch. The only difference is the lens through which we see their wall-clock time.

所有这三个对象,nowzdtNewYorkzdtRecife,都是某个时刻,时间线上的同一个同时点。所有三个共享相同的纪元计数。唯一的区别是我们看到挂钟时间的镜头。

Avoid legacy date-time classes

避免遗留的日期时间类

Avoid using the troublesome old date-time classes bundled with the earliest versions of Java. So, avoid java.util.Dateand java.util.Calendar. They really are that bad. Stick with java.time classes.

避免使用与最早版本的 Java 捆绑在一起的麻烦的旧日期时间类。所以,避免java.util.Datejava.util.Calendar。他们真的很糟糕。坚持使用 java.time 类。

If you must interact with old code not yet updated for java.time types, you can convert to/from java.time types. Look for new methods added to the old classes. The java.util.Date.frommethod takes an Instant. We can extract an Instantfrom a ZoneDateTime(or from OffsetDateTime).

如果您必须与尚未针对 java.time 类型更新的旧代码进行交互,则可以在 java.time 类型之间进行转换。寻找添加到旧类的新方法。该java.util.Date.from方法采用Instant. 我们可以Instant从 a ZoneDateTime(或 from OffsetDateTime)中提取 an 。

java.util.Date utilDate = java.util.Date.from( zdtNewYork.toInstant() );

And going the other direction.

并走向另一个方向。

Instant instant = utilDate.toInstant();

For more info on converting, see my Answerto the Question, Convert java.util.Date to what “java.time” type?

有关转换的更多信息,请参阅对问题的回答将 java.util.Date 转换为什么“java.time”类型?

Avoid count-from-epoch

避免从纪元开始计数

Avoid using the count-from-epoch numbers such as milliseconds-since-start-of-1970-in-UTC. There are various granularities used for the count (milliseconds, microseconds, nanoseconds, whole seconds, and more). There are at least a couple dozen epochs in use by various computer systems besides 1970. The numbers have no meaning when read by humans, so bugs may go undetected.

避免使用 count-from-epoch 数字,例如毫秒自 1970 年开始的 UTC 时间。有多种用于计数的粒度(毫秒、微秒、纳秒、整秒等)。除了 1970 年之外,各种计算机系统至少使用了几十个纪元。这些数字在人类阅读时没有任何意义,因此可能无法检测到错误。

You might find them useful when practicing. Call getEpochSecondand getNanoon Instant, or for a truncated value call toEpochMilli.

您可能会发现它们在练习时很有用。调用getEpochSecondgetNanoon Instant,或为截断值调用toEpochMilli



About java.time

关于java.time

The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.

现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

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

You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*classes.

您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*

Where to obtain the java.time classes?

从哪里获得 java.time 类?

The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多

回答by Dawood ibn Kareem

It seems to me that you're confused about the difference between a LocalDateTimeand an Instant(or a Date, which is essentially the same thing as an Instant). These are completely different objects.

在我看来,您对 aLocalDateTime和 an Instant(或 a Date,本质上与 an 相同Instant)之间的区别感到困惑。这些是完全不同的对象。

A LocalDateTimeis a particular calendar date and a particular clock time. You can think of it like this picture.

ALocalDateTime是特定的日历日期和特定的时钟时间。你可以把它想象成这张图片。

LocalDateTime

本地日期时间

Or you can think of it as a year, month, day, hour, minute and second. But it has no time zone. It's just what the calendar says and what the clock says.

或者您可以将其视为年、月、日、小时、分钟和秒。但它没有时区。这就是日历和时钟所说的。

An Instantis a moment in time. For example, the moment when Neil Armstrong first stepped on the moon could be represented as an Instant. So could the moment JFK was shot.

AnInstant是一个时刻。例如,尼尔·阿姆斯特朗 (Neil Armstrong) 第一次踏上月球的那一刻可以表示为Instant. 肯尼迪被枪杀的那一刻也是如此。

Again, there's no time zone. But it's something different from a LocalDateTime. You can't write down what time an Instantis unless you know which time zone to write it down for. Oh, and a Dateis the same thing as an Instant.

同样,没有时区。但它与LocalDateTime. 你不能写下来的什么时候Instant是,除非你知道哪个时区把它写下来。哦,a 和 aDate是一样的Instant

Therefore, to convert between a LocalDateTimeand an Instant, you need to reference a particular time zone. So to express the moment Neil Armstrong stepped on the moon as a year, month, date, hour, minute and second; you need to know what time zone to use. If you use UTC, it was 2:56am on 21 July 1969. If you use Pacific Standard Time, it was 6:56pm on 20 July 1969.

因此,要在 aLocalDateTime和 an之间进行转换Instant,您需要引用特定的时区。因此,将尼尔·阿姆斯特朗踏上月球的那一刻表示为年、月、日、时、分和秒;您需要知道要使用的时区。如果使用 UTC,则为 1969 年 7 月 21 日凌晨 2:56。如果使用太平洋标准时间,则为 1969 年 7 月 20 日下午 6:56。

Armed with that knowledge, let's analyse your code. You started with a couple of LocalDateTimeobjects.

有了这些知识,让我们分析您的代码。您从几个LocalDateTime对象开始。

  • ldtBrazil is the current time in Brazil - 22:11:52 on 21 September.
  • ldtNY is the current time in New York - 21:11:52 on 21 September.
  • ldtBrazil 是巴西当前时间 - 9 月 21 日 22:11:52。
  • ldtNY 是纽约的当前时间 - 9 月 21 日 21:11:52。

Now, you use UTC to convert these to Instantobjects.

现在,您使用 UTC 将这些转换为Instant对象。

  • instantBrazil is the moment at which it was 22:11:52 in Timbuktu (which uses UTC all year round).
  • instantNY is the moment at which it was 21:11:52 in Timbuktu (an hour earlier than instantBrazil).
  • InstantBrazil 是廷巴克图(全年使用 UTC)的 22:11:52 时刻。
  • InstantNY 是廷巴克图 21:11:52 的时刻(比 InstantBrazil 早一个小时)。

Then you print these out. We need to know a timezone to be able to do this, but that's OK. An Instantgets printed in UTC, no matter what. That's what the Zmeans.

然后你把这些打印出来。我们需要知道一个时区才能做到这一点,但没关系。Instant无论如何,An都会以 UTC 打印。就是这个Z意思。

Now, you convert the Instantobjects to a number of milliseconds. Fine. This is the number of milliseconds since midnight on 1 January 1970, UTC. milliNY is obviously 3.6 million less than milliBrazil, because it corresponds to an Instantthat's an hour earlier.

现在,您将Instant对象转换为毫秒数。美好的。这是自 UTC 时间 1970 年 1 月 1 日午夜以来的毫秒数。millNY 显然比milliBrazil 少360 万,因为它对应于Instant一个小时前的a。

Then you convert the Instantobjects to Dateobjects. This doesn't really change anything, since a Dateand an Instantrepresent the same thing, even though they get printed out differently.

然后将Instant对象转换为Date对象。这并没有真正改变任何东西,因为 aDate和 anInstant代表相同的东西,即使它们的打印方式不同。

You print out those converted Dateobjects. They get printed in Brazilian time, because that's your locale. And it just so happens that dateNYis an hour earlier than dateBrazil; but they still both get printed in Brazilian time, which is three hours behind UTC. So you get 19:11:52 and 18:11:52 respectively.

您打印出这些转换后的Date对象。它们以巴西时间打印,因为那是您的语言环境。碰巧dateNY比 早了一个小时dateBrazil;但它们仍然以巴西时间打印,比UTC晚三个小时。所以你分别得到 19:11:52 和 18:11:52。

Lastly, you make a couple of more Dateobjects, from the numbers of milliseconds. But these new Dateobjects are exactly equal to the dateBraziland dateNYthat you already have, since you made them from the same number of milliseconds. And again, they get printed in Brazilian time.

最后,Date根据毫秒数创建更多对象。但是这些新Date对象dateBrazildateNY您已经拥有的和完全相同,因为您从相同的毫秒数中创建了它们。再一次,它们以巴西时间印刷。