Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
114 views
in Technique[技术] by (71.8m points)

java - Why is this not casting to long

I got strange java casting problem today coming from such code

new Date(System.currentTimeMillis() - 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) works as expected

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 ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

Output on my computer just now (April 11):

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

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

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

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.

What went wrong in your code?

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.

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

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

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.

Links


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

56.9k users

...