Java 8 java.time:在Instant vs LocalDateTime中添加TemporalUnit [英] Java 8 java.time: Adding TemporalUnit in Instant vs LocalDateTime

查看:223
本文介绍了Java 8 java.time:在Instant vs LocalDateTime中添加TemporalUnit的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Java 8中的新java.time包。我有一个遗留数据库,它给了我 java.util.Date ,我转换为即时

I'm playing around with the new java.time package in Java 8. I have a legacy database that gives me java.util.Date, which I convert to Instant.

我要做的是添加一段基于另一个数据库标志的时间。我可以添加几天,几周,几个月或几年。我不想关心我要添加的内容,我希望将来可以添加更多选项。

What I am trying to do is add a period of time that is based off of another database flag. I could be adding days, weeks, months, or years. I don't want to have to care what I am adding, and I would like to be able to add more options in the future.

我的第一个想法是 Instant.plus(),但是对于大于一天的值,这给了我一个 UnsupportedTemporalTypeException 。瞬间显然不支持大单位时间的操作。好吧,不管怎样, LocalDateTime 呢。

My first thought was Instant.plus(), but that gives me an UnsupportedTemporalTypeException for values greater than a day. Instant apparently does not support operations on large units of time. Fine, whatever, LocalDateTime does.

所以这给了我这段代码:

So that gives me this code:

private Date adjustDate(Date myDate, TemporalUnit unit){
    Instant instant = myDate.toInstant();
    LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    dateTime = dateTime.plus(1, unit);
    Instant updatedInstant = dateTime.atZone(ZoneId.systemDefault()).toInstant();
    return new Date(dueInstant.toEpochMilli());
}

现在,这是我第一次使用新的时间API,所以我可以在这里错过了什么。但对我来说似乎很蠢,我必须去:

Now, this is my first time using the new time API, so I may have missed something here. But it seems clunky to me that I have to go:

Date --> Instant --> LocalDateTime --> do stuff--> Instant --> Date.

即使我不必使用日期部分,我仍然认为这有点尴尬。所以我的问题是这个,我这样做完全错了,最好的办法是什么?

Even if I did not have to use the Date part, I would still think it was a bit awkward. So my question is this, am I doing this completely wrong and what is the best way to do this?

编辑:扩展评论中的讨论。

Edit: Expanding on the discussion in the comments.

我想我现在更好地了解了LocalDateTime和Instant如何使用java.util.Date和java.sql.Timestamp。谢谢大家。

I think I have a better idea now about how LocalDateTime and Instant are playing with java.util.Date and java.sql.Timestamp. Thanks everyone.

现在,更实际的考虑。假设用户向我发送了一个日期,无论他们身在何处,都是任意时区。他们发给我 2014-04-16T13:00:00 我可以解析为LocalDateTime。然后我将它直接转换为java.sql.Timestamp并在我的数据库中保留。

Now, a more practical consideration. Let's say a user sends me a date from wherever they are in the world, arbitrary time zone. They send me 2014-04-16T13:00:00 which I can parse into a LocalDateTime. I then convert this directly to a java.sql.Timestamp and persist in my database.

现在,我没有做任何其他事情,我从我的java中获取java.sql.timestamp数据库,使用 timestamp.toLocalDateTime()转换为 LocalDateTime 。都好。然后我使用ISO_DATE_TIME格式将此值返回给我的用户。结果是 2014-04-16T09:00:00

Now, without doing anything else, I pull my java.sql.timestamp from my database, convert to LocalDateTime using timestamp.toLocalDateTime(). All good. Then I return this value to my user using the ISO_DATE_TIME formatting. The result is 2014-04-16T09:00:00.

我认为这种差异是因为某种类型隐式转换为/来自UTC。我认为我的默认时区可能会应用于该值(EDT,UTC-4),这可以解释为什么数字会被关闭4小时。

I assume this difference is because of some type of implicit conversion to/from UTC. I think my default time zone may be getting applied to the value (EDT, UTC-4) which would explain why the number is off by 4 hours.

新问题( S)。从本地时间到UTC的隐式转换在哪里?保留时区的更好方法是什么。我不能直接从本地时间作为字符串(2014-04-16T13:00:00)转到 LocalDateTime 吗?我应该期待用户输入的时区吗?

New question(s). Where is the implicit conversion from local time to UTC happening here? What is the better way to preserve time zones. Should I not be going directly from Local time as a string (2014-04-16T13:00:00) to LocalDateTime? Should I be expecting a time zone from the user input?

推荐答案

我将继续根据我的最终解决方案发布答案这是一个很长的评论链的总结。

I will go ahead and post an answer based on my final solution and a sort of summary of the very long comment chain.

首先,整个转换链:

Date --> Instant --> LocalDateTime --> Do stuff --> Instant --> Date

是否需要保留时区信息并仍然对类似日期的对象执行操作日历及其中的所有上下文。否则我们冒着隐式转换到本地时区的风险,如果我们试图将其置于人类可读日期格式中,则时间可能会因此而改变。

Is necessary to preserve the time zone information and still do operations on a Date like object that is aware of a Calendar and all of the context therein. Otherwise we run the risk of implicitly converting to the local time zone, and if we try to put it into a human readable date format, the times may have changed because of this.

例如, java.sql.Timestamp 类上的 toLocalDateTime()方法隐式转换为默认时间区。这对我的目的来说是不可取的,但不一定是坏行为。但是,重要的是要意识到这一点。这是直接从旧的Java日期对象转换为 LocalDateTime 对象的问题。由于传统对象通常被假定为UTC,因此转换使用本地时区偏移。

For example, the toLocalDateTime() method on the java.sql.Timestamp class implicitly converts to the default time zone. This was undesirable for my purposes, but is not necessarily bad behavior. It is important, however, to be aware of it. That is the issue with converting directly from a legacy java date object into a LocalDateTime object. Since legacy objects are generally assumed to be UTC, the conversion uses the local timezone offset.

现在,假设我们的程序接受 2014的输入-04-16T13:00:00 并以 java.sql.Timestamp 保存到数据库。

Now, lets say our program takes the input of 2014-04-16T13:00:00 and save to a database as a java.sql.Timestamp.

//Parse string into local date. LocalDateTime has no timezone component
LocalDateTime time = LocalDateTime.parse("2014-04-16T13:00:00");

//Convert to Instant with no time zone offset
Instant instant = time.atZone(ZoneOffset.ofHours(0)).toInstant();

//Easy conversion from Instant to the java.sql.Timestamp object
Timestamp timestamp = Timestamp.from(instant);

现在我们采用时间戳并为其添加一些天数:

Now we take a timestamp and add some number of days to it:

Timestamp timestamp = ...

//Convert to LocalDateTime. Use no offset for timezone
LocalDateTime time = LocalDateTime.ofInstant(timestamp.toInstant(), ZoneOffset.ofHours(0));

//Add time. In this case, add one day.
time = time.plus(1, ChronoUnit.DAYS);

//Convert back to instant, again, no time zone offset.
Instant output = time.atZone(ZoneOffset.ofHours(0)).toInstant();

Timestamp savedTimestamp = Timestamp.from(output);

现在我们只需输出一个人类可读的字符串,格式为 ISO_LOCAL_DATE_TIME

Now we just need to output as a human readable String in the format of ISO_LOCAL_DATE_TIME.

Timestamp timestamp = ....
LocalDateTime time = LocalDateTime.ofInstant(timestamp.toInstant(), ZoneOffset.ofHours(0));
String formatted = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(time);

这篇关于Java 8 java.time:在Instant vs LocalDateTime中添加TemporalUnit的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆