为什么这不长 [英] Why is this not casting to long

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

问题描述

我今天遇到了来自这样的代码的奇怪的 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被评估为整数并溢出.

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.

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

我认为 java 应该将整个表达式转换为 Long,因为第一个操作数是 Long System.currentTimeMillis() 但由于某种我不明白的原因,这里没有发生.硬编码的常量是否有一些例外是 int ?

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

由于 3 月有 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 * 31int 值组成.是的,整数文字具有 int 类型,除非它们具有 L 后缀.因为乘法是在减法之前执行的(正如你已经预料到的),结果也是一个 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.

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

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