如何在 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
How convert LocalDateTime to Date in Java 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
LocalDateTime
means 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 LocalDateTime
because 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 Instant
class is your go-to class, the basic building-blocks of date-time objects. The Instant
class 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 ZoneId
to get a ZonedDateTime
object.
仅在需要访问某些地区的挂钟时间时才调整到时区。应用 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.
所有这三个对象,now
,zdtNewYork
和zdtRecife
,都是某个时刻,时间线上的同一个同时点。所有三个共享相同的纪元计数。唯一的区别是我们看到挂钟时间的镜头。
Avoid legacy date-time classes
避免遗留的日期时间类
Avoid using the troublesome old date-time classes bundled with the earliest versions of Java. So, avoid java.util.Date
and java.util.Calendar
. They really are that bad. Stick with java.time classes.
避免使用与最早版本的 Java 捆绑在一起的麻烦的旧日期时间类。所以,避免java.util.Date
和java.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.from
method takes an Instant
. We can extract an Instant
from 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 getEpochSecond
and getNano
on Instant
, or for a truncated value call toEpochMilli
.
您可能会发现它们在练习时很有用。调用getEpochSecond
和getNano
on 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 类?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6and Java SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.timeclasses.
- For earlier Android (<26), the ThreeTenABPproject adapts ThreeTen-Backport(mentioned above). See How to use ThreeTenABP….
- Java SE 8、Java SE 9、Java SE 10、Java SE 11及更高版本 - 标准 Java API 的一部分,具有捆绑实现。
- Java 9 添加了一些小功能和修复。
- Java SE 6和Java SE 7
- 多的java.time功能后移植到Java 6和7在ThreeTen-反向移植。
- 安卓
- java.time类的更高版本的 Android 捆绑实现。
- 对于早期的 Android(<26),ThreeTenABP项目采用了ThreeTen-Backport(上面提到过)。请参阅如何使用ThreeTenABP ...。
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 的试验场。你可能在这里找到一些有用的类,比如Interval
,YearWeek
,YearQuarter
,和更多。
回答by Dawood ibn Kareem
It seems to me that you're confused about the difference between a LocalDateTime
and 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 LocalDateTime
is a particular calendar date and a particular clock time. You can think of it like this picture.
ALocalDateTime
是特定的日历日期和特定的时钟时间。你可以把它想象成这张图片。
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 Instant
is 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 Instant
is unless you know which time zone to write it down for. Oh, and a Date
is the same thing as an Instant
.
同样,没有时区。但它与LocalDateTime
. 你不能写下来的什么时候Instant
是,除非你知道哪个时区把它写下来。哦,a 和 aDate
是一样的Instant
。
Therefore, to convert between a LocalDateTime
and 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 LocalDateTime
objects.
有了这些知识,让我们分析您的代码。您从几个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 Instant
objects.
现在,您使用 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 Instant
gets printed in UTC, no matter what. That's what the Z
means.
然后你把这些打印出来。我们需要知道一个时区才能做到这一点,但没关系。Instant
无论如何,An都会以 UTC 打印。就是这个Z
意思。
Now, you convert the Instant
objects 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 Instant
that's an hour earlier.
现在,您将Instant
对象转换为毫秒数。美好的。这是自 UTC 时间 1970 年 1 月 1 日午夜以来的毫秒数。millNY 显然比milliBrazil 少360 万,因为它对应于Instant
一个小时前的a。
Then you convert the Instant
objects to Date
objects. This doesn't really change anything, since a Date
and an Instant
represent the same thing, even though they get printed out differently.
然后将Instant
对象转换为Date
对象。这并没有真正改变任何东西,因为 aDate
和 anInstant
代表相同的东西,即使它们的打印方式不同。
You print out those converted Date
objects. They get printed in Brazilian time, because that's your locale. And it just so happens that dateNY
is 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 Date
objects, from the numbers of milliseconds. But these new Date
objects are exactly equal to the dateBrazil
and dateNY
that you already have, since you made them from the same number of milliseconds. And again, they get printed in Brazilian time.
最后,Date
根据毫秒数创建更多对象。但是这些新Date
对象dateBrazil
与dateNY
您已经拥有的和完全相同,因为您从相同的毫秒数中创建了它们。再一次,它们以巴西时间印刷。