Java, How to subtract Date objects whilst considering DST - java

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.

Related

TimeDelta java?

I am trying to convert code from Python to Java. I need to rewrite the timedelta function in Java. Here is the code in Python:
def timeDate(date):
return (timedelta(seconds=date * 3600 % 86400))
Does anyone have any idea on how to make a function that acts the same?
double hours = 21.37865107050986;
long nanos = Math.round(hours * TimeUnit.HOURS.toNanos(1));
Duration d = Duration.ofNanos(nanos);
// Delete any whole days
d = d.minusDays(d.toDays());
System.out.println(d);
This prints:
PT21H22M43.143853836S
Which means: a duration of 21 hours 22 minutes 43.143853836 seconds.
Assumptions: I understand that you want a duration (the docs you link to say “A timedelta object represents a duration”). I have taken date to be a floating-point number of hours, and your modulo operation lead me to believe that you want the duration modulo 1 day (so 26 hours should come out as a duration of 2 hours).
The Duration class in Java is for durations, hence is the one that you should use. It doesn’t accept a floating point number for creation, so I converted your hours so nanoseconds and rounded to whole number. For the conversion I multiplied by the number of nanoseconds in 1 hour, which I got from the call to TimeUnit (this gives clearer and less error-prone code than multiplying out ourselves).
The code above will tacitly give incorrect results for numerically large numbers of hours, so you should check the range before using it. Up to 2 500 000 hours (100 000 days or nearly 300 years) you should be safe.
Please note: if date was a time of day and not a duration, it’s a completely different story. In this case you should use LocalTime in Java. It’s exactly for a time of day (without date and without time zone).
nanos = nanos % TimeUnit.DAYS.toNanos(1);
LocalTime timeOfDay = LocalTime.ofNanoOfDay(nanos);
System.out.println(timeOfDay);
21:22:43.143853836
Link: Documentation of the Duration class
As far as I know, Java doesn't have a built in DeltaTime function. However you can easily make your own.long startTime;
long delta; public void deltaTime(){ long currentTime = System.currentTimeMillis(); delta = currentTime - startTime;}
Whenever you want to start your DeltaTime timer, you just do time = System.currentTimeMillis;. This way, the variable "delta" is the amount of time between when you started the DeltaTime timer and when you end it using ClassNameHere.deltaTime();.
private static LocalTime timeDate(double d) {
//converts into a local time
return LocalTime.ofSecondOfDay((long)(d*3600%86400));
}
Input (d):
36.243356711275794
Output:
21:22:43

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

How to check the number of fixed time segments between two dates?

Two Dates are given:
Let's say,
Date dt1 = 22 June 2013 8:00 PM
Date dt2 = 24 June 2013 6:00 AM
Given the two dates, I want to determine that how many segments from 1 am to 5 am are between these two dates.
For above, there are two segments:
23 June 1 am to 5am
24 June 1am to 5am
So the answer should be 2.
I can get the difference between the two times,
var time1 = new Date(dt1).getTime();
var time2 = new Date(dt2).getTime();
var diff = new Date(time1 - time2);
And the number of hours, min and seconds,
var hours = diff.getHours();
var minutes = diff.getMinutes();
var seconds = diff.getMinutes();
But this only gives difference as expected.
What approach is needed to do so ?
Like everything else in computer science: break the problem down into a series of smaller problems that you're able to solve.
For example, in this problem you might simply determine if there's at least one of your "segments" in the time span. If there is, you might remove the first 24 hours from the full time span, then repeat the process for as long as there exists 24 hours to remove. Remember to count along the way.
Another approach might be to check
if time1.getHours() before or equal to 1am then result=1
if time2.getHours() after 5am then resutl++
result+= diff.getDays() - 1

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.

Java date jump to the next 10th minute

I need a fast implementation of a "Date jump" algorithm that is to be included in an event management system.
An event is triggered and sets a date (in a synchronized method) to the next 10th minute.
For instance
Event occurs at "2010-01-05 13:10:12" and sets the
next date to be "2010-01-05 13:20:00"
and if an event occurs exactly (supposedly) at a 10th minute, the next one must be set
Event occurs at "2010-01-05 13:30:00" and sets the
next date to be "2010-01-05 13:40:00"
(unlikely since the date goes down to the 1/1000th of a second, but just in case...).
My first idea would be to get the current Date() and work directly with the ms from the getTime() method, via integer (long) division, like ((time / 10mn)+1)*10mn.
Since it has to be fast, and also reliable, I thought I'll ask my fellow OSers prior to the implementation.
You can use / adapt my answer to a very similar question:
How to round time to the nearest quarter in java?
Something like this:
int unroundedMinutes = calendar.get(Calendar.MINUTE);
int mod = unroundedMinutes % 10;
calendar.add(Calendar.MINUTE, mod == 0 ? 10 : 10 - mod);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Your approach with the epoch time in ms will not work for arbitrary time zones, since some time zones have a N*15 minutes offset from GMT. Within these time zones, your code would move the interval 5-14 to 15, 15-24 to 25 and so on.
Have you actually tested the performance when manipulating the appropriate fields in the GregorianCalendar class and concluded that the performance is insufficient, or are you trying to reinvent a wheel just for the fun of it?

Categories

Resources