为什么这不能持续很长时间 [英] Why is this not casting to long

查看:55
本文介绍了为什么这不能持续很长时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我今天从这样的代码中遇到了奇怪的java转换问题

I got strange java casting problem today coming from such code

new Date(System.currentTimeMillis()-1000 * 60 * 60 * 24 * 31)

该日期应该为现在的31天,但返回的日期为16天。这显然是因为
1000 * 60 * 60 * 24 * 31
被认为是Integer并且溢出。

This is supposed to give date 31 days before now, but returns date 16 days after. It obviously happens because 1000 * 60 * 60 * 24 * 31 is evaluated as Integer and overflows.

新日期(System.currentTimeMillis()-1000L * 60 * 60 * 24 * 31)
按预期工作

new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 31) works as expected

我认为Java应该将整个表达式强制转换为Long,因为第一个操作数是Long System.currentTimeMillis()但由于某种我不了解的原因,它并未在这里发生。

I think java should cast whole expression to Long because first operand is Long System.currentTimeMillis() but it's not happening here for some reason I don't understand. Is there some exception about hardcoded constants to be int ?

推荐答案

已经有人说过了,但是我认为应该将其放入回答。使用 ZonedDateTime 类,其中带有 ZoneId

It’s all been said, but I thought it deserved to go into an answer. Use the ZonedDateTime class with ZoneId.

    ZonedDateTime aMonthAgo = ZonedDateTime.now(ZoneId.of("Indian/Comoro")).minusMonths(1);

我的计算机上刚刚输出(4月11日):

Output on my computer just now (April 11):


2018-03-11T19:57:47.517032 + 03:00 [印度/科摩罗]

2018-03-11T19:57:47.517032+03:00[Indian/Comoro]

我减去一个月,所以这意味着28、29、30或31天,具体取决于我所在的月份和上个月的天数。如果您无条件地希望31天,当然可以:

I subtract a month, so that means 28, 29, 30 or 31 days depending on the month I’m in and the number of days in the previous month. If you want 31 days unconditionally, you can have that, of course:

    ZonedDateTime thirtyoneDaysAgo 
            = ZonedDateTime.now(ZoneId.of("Indian/Comoro")).minusDays(31);

由于三月份有31天,因此在这种情况下结果是相同的。

Since there were 31 days in March, the result is the same in this case. It won’t always be.

我正在使用并推荐 java.time ,现代的Java日期和时间API。与过时的 Date 类相比,使用它要好得多,而且出错率也低得多。

I am using and recommending java.time, the modern Java date and time API. It’s so much nicer to work with and much less error-prone than the outdated Date class.

这与运算符优先级 1000 * 60 * 60 * 24 * 31 int 值组成。是的,除非整数文字后缀为 L ,否则它们的类型为 int 。由于乘法是在减法之前进行的(正如您已经预期的那样),所以结果也是 int ,但是它会溢出,因为结果将大于 int 可以保存。不幸的是Java并没有通知您溢出的情况,它只是给您一个错误的结果,这里 -1616567296 ,大约-19天。减去这些后,您会得到大约19天后的日期和时间。

It’s about operator precedence. 1000 * 60 * 60 * 24 * 31 consists of int values. Yes, integer literals have type int unless they have the L suffix. Because multiplication is carried out before subtraction (as you had already expected), the result is an int too, but it overflows because the result would be greater than the maximum number that an int can hold. Unfortunately Java doesn’t inform you of the overflow, it just gives you a wrong result, here -1616567296, about -19 days. When subtracting these, you get a date and time about 19 days into the future.

习惯上,请使用括号 L 后缀和下划线分组以提高可读性。

As a habit, use parentheses, the L suffix, and underscore-grouping for readability.

( System.currentTimeMillis() - ( 1_000L * 60L * 60L * 24L * 31L ) )

如果想知道溢出,可以使用 Math.multiplyExact()用于您的乘法(自Java 8起)。幸运的是,现代的库类使您免于繁琐的工作。并发出任何溢出信号。

If you wanted to be made aware of overflow, you may use Math.multiplyExact​() for your multiplications (since Java 8). Fortunately, the modern library classes save you completely from multiplying. And signal any overflow.

  • Oracle tutorial: Date Time explaining how to use java.time.
  • Math.multiplyExact​() documentation

这篇关于为什么这不能持续很长时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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