What's wrong with the Java Date constructor Date(long date)? - java

I have two objects, p4 and p5, that have a Date property. At some points, the constructor works fine:
p4.setClickDate(new Date(System.currentTimeMillis() - 86400000 * 4));
Sets the date to Sun Jul 31 11:01:39 EDT 2011
And in other situations it does not:
p5.setClickDate(new Date(System.currentTimeMillis() - 86400000 * 70));
Sets the date to Fri Jul 15 04:04:26 EDT 2011
By my calculations, this should set the date back 70 days, no?
I can get around this using Calendar, but I'm curious as to why Date behaves this way.
Thanks!

That's caused by an integer overflow. Integers have a maximum value of Integer.MAX_VALUE which is 2147483647. You need to explicitly specify the number to be long by suffixing it with L.
p5.setClickDate(new Date(System.currentTimeMillis() - 86400000L * 70));
You can see it yourself by comparing the results of
System.out.println(86400000 * 70); // 1753032704
System.out.println(86400000L * 70); // 6048000000
See also:
Java Tutorials - Language Basics - Primitive Data Types

the number is too big and you have overflow you should add L at the end to make it long.\8640000l (java numbers are int by default)

Related

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 ?
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
Oracle tutorial: Date Time explaining how to use java.time.
Math.multiplyExact​() documentation

Java, How to subtract Date objects whilst considering DST

I have a piece of code that is used to calculate the number of days between two Date objects, and in most instances, it works fine.
However, if the date range between the two objects includes the end of March, the result is always 1 less than it should be. e.g March 31 2014 - March 29 2014 = 1, whereas it should be 2.
I understand that this is due to the fact that March has 30 days of 24 hours and 1 day of 23 hours due to DST, which is the cause of the value being 1 less.
However, I am not sure the best way to account for the missing hour.
// This was what I have initially
int numDays = (int) ((dateTo.getTime() - dateFrom.getTime()) / (1000 * 60 * 60 * 24));
// I have tried rounding, since it should have 23 hours left over, but it didn't actually work.
int numDays = (Math.round(dateTo.getTime() - dateFrom.getTime()) / (1000 * 60 * 60 * 24));
Any help/pointers would be greatly appreciated.
I am and have to use Java 7 and I am not able to use Jodatime unfortunately.
Your second example is very close. Your parentheses for Math.round() only surround the subtraction, though, so since that's already an integer (well, a long really), nothing happens, and then you divide. The other problem with your second bit of code is that you are doing integer division which always truncates the part after the decimal point. Try this:
long numDays2 = Math.round((dateTo.getTime() - dateFrom.getTime()) / (1000.0 * 60 * 60 * 24));
(As indicated, I changed the Math.round() parens, and made it floating point division by making the divisor a double.)
As indicated by the comments, though, this is a hack. In particular, it will tell you that there are two days between 6AM March 5 and 8PM March 6. It's probably not really what you want. Try this on for size instead:
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
Calendar cal = Calendar.getInstance();
cal.setTime(fmt.parse("2014-03-29"));
long start = cal.getTimeInMillis();
start += cal.getTimeZone().getOffset(start);
cal.setTime(fmt.parse("2014-03-31"));
long end = cal.getTimeInMillis();
end += cal.getTimeZone().getOffset(end);
System.out.println((end - start)/86400000.0);
Is it ugly? Yes. Is it weird? Yes. Does it work? Yes (I think so). Note that I'm providing a double as a result; you can apply any rounding you want to this result.

Java - Convert Unix epoch time to date

I need to convert some epoch time stamps to the real date and have used some of the methods I found on stack overflow, but they give the wrong answer.
As an example, one date is "129732384262470907" in epoch time, which is "Mon, 20 Jan 6081 05:24:22 GMT" using http://www.epochconverter.com/
However, my code generates: "Wed Dec 24 14:54:05 CST 19179225"
String epochString = token.substring(0, comma);
long epoch = Long.parseLong(epochString);
Date logdate = new Date(epoch * 1000);
BufferedWriter timewrite = new BufferedWriter(new FileWriter(tempfile, true));
timewrite.write(logdate);
timewrite.flush();
timewrite.close();
The initial timestamp is in miliseconds, which in the examples I saw here I am supposed to multiply by 1000.
If I don't multiply by 1000, I get: "Mon Aug 08 01:14:30 CDT 4113025"
Both of which are wrong.
So where have I made my error?
129732384262470907 is actually in microseconds since the epoch if it's meant to be 6081, so you need to divide by 1000 if that's real input.
Note that epochconverter.com doesn't even handle that value - it only allows you to enter 129732384262470 which it then treats as milliseconds since the epoch.
You need to multiply by 1000 if your data is seconds since the epoch. Basically all you need to know is that Java expects milliseconds since the epoch; the rest should be plain sailing, assuming you know what your input data actually means.
If you could provide your real data, and what it's meant to represent, it's probably going to be easy to fix your problems.
If you look carefully, epochconverter.com truncated that number because it was too long for the entry field.
I suggest you print the current value of System.currentMillis() to see what approximate range a "current" epoch-based timestamp has, and re-scale your input number to match. I think you'll probably have to divide by 1000.
In fact, looking closer, if you divide by 10,000, you get 1297323842624, which comes out to a date in 2011. So it's not at all clear what units the number you've given are in.

Java - get differences between given fortnight and current fortnight

For example:
Data Given :
Year-2010,
Month-2,
Fortnight-1
Current date
How do I get the difference in terms of number of fortnights between the two given dates?
This is what I figured out and its working fine...
Calendar c= Calendar.getInstance();
int year = 2011;
int month = 6;
int fortnight = 1;
int noofmonths=(c.get(Calendar.YEAR)-year)*12;
noofmonths=(noofmonths+((12-(month-1)+(c.get(Calendar.MONTH)-12)))-1)*2;
int nooffortnights=noofmonths+((2-(fortnight-1)+((c.get(Calendar.DAY_OF_MONTH)<15?1:2)-2)))-1;
System.out.println("nooffortnights : "+nooffortnights); //outputs 5
This depends on your definition of fortnights. If we are literal minded then a fortnight is defined as 14 days, so compute the number of days and divide by 14, job done.
I suspect that in your case we are actually using a special business calendar, where fortnights are a subdivision of quarters and hence there are some special cases - a year doesn't exactly divide into fortnights and perhaps the business year does not start on Jan 1st? So somewhere there will be a definitive list of the dates of the start of each fortnight in a year.
Let's suppose that the fortnight definitions have
17th Nov - 1st Dec
2nd Dec - 15th Dec
16th Dec - 31st Dec (note this is 15 days long)
Now what's the definition on how many fortnights from 17th Nov to 16th Dec? I guess 2. From 19th Nov to 16th Dec? I have no idea what answer you would expect.
So first, get really clear what the business requirements are. I'd be surprised is you will find off-the-shelf date packages that understand fortnights, but even if you do you need to check very carefully that they give the answers you need.
Assuming you want to do this without any 3rd Party libraries
Make 2 Calendar Objects (both with the given dates).
Calendar c1 = Calendar.getInstance(),c2 = Calendar.getInstance();
c1.add(Calendar.MONTH, 2);
int fortnights = (int)((c1.getTimeInMillis() - c2.getTimeInMillis()) / (14L * 24 * 60 * 60 * 1000));
System.out.println(fortnights); //output should be 4
Note, it's a rough approximation.

Calendar add() vs roll() when do we use it?

I know add() adds the specified (signed) amount of time to the given time field, based on the calendar's rules.
And roll() adds the specified (signed) single unit of time on the given time field without changing larger fields.
I can't think of an everyday usage of roll() I would do everything by add().
Can you help me out with examples when do we use roll() and when add()?
EDIT 1
Joda answers are not accepted!
add() - almost always, as you said
roll() - for example you want to "dispense" events in one month. The algorithm may be to proceed a number of days and place the event, then proceed further. When the end of the month is reached, it should start over from the beginning. Hence roll().
Found in jGuru
Calendar.roll()
Changes a specific unit
and leaves 'larger' (in terms of time-month
is 'larger' than day) units unchanged. The API example is that
given a date of August 31, 1999,
rolling by (Calendar.MONTH, 8) yields
April 30, 1999. That is, the DAY was
changed to meet April's maximum, but
the 'larger' unit, YEAR, was
unchanged.
roll(): Rolls up 8 months here i.e., adding 8 months to Aug will result in Apr but year remains unchanged(untouched).
Calendar.add()
Will cause the
next 'larger' unit to change, if
necessary. That is, given a date of
August 31, 1999, add(Calendar.MONTH,
8) yields April 30, 2000. add() also
forces a recalculation of milliseconds
and all fields.
add(): Adds months to the current date i.e., adding 8 months to Aug will give Apr of Next Year, hence forces the Year change.
I was just asking the same question (which is how I found this page) and someone at my work place (well done, DCK) came up with a suggestion:
The date selectors on many smart phones (and other similar interfaces) will "roll" the day from the 31st to the 1st without altering the month, similarly for the month field.
I can't think of another use ATM and this one could be implemented in other ways, but at least it's an example!
Tim
Here is an example that will not work. The condition in the loop will never be satisfied, because the roll, once reaching January 31, 2014, will go back to January 1, 2014.
Calendar start=new GregorianCalendar();
start.set(Calendar.YEAR, 2014);
start.set(Calendar.MONTH, 0);
start.set(Calendar.DAY_OF_MONTH, 1);
//January 2, 2014
Calendar end=new GregorianCalendar();
end.set(Calendar.YEAR, 2014);
end.set(Calendar.MONTH, 1);
end.set(Calendar.DAY_OF_MONTH, 2);
//February 2, 2014
while (start.getTime().before(end.getTime())){
start.roll(Calendar.DATE, 1);
}

Categories

Resources