jodatime truncates remaining months when interval is greater than a year - java

I am trying to check if a given interval is greater than 12 months using the following code:
public void testMonths() throws Exception {
DateTimeFormatter format = DateTimeFormat.forPattern("yyyy-mm");
DateTime from = format.parseDateTime("2010-01");
DateTime until = format.parseDateTime("2011-06");
int months = Months.monthsBetween(from, until).getMonths();
assertTrue(months > 12); // months = 12 for some reason.
}
Whenever the given interval is more then a year it will truncate the remaining months in the last year.
Input I've tried running:
15 months will return 12 months.
25 months will return 24 months.
36 months will return 36 months.
37 months will return 36 months.

The problem is your text pattern. "mm" means "minutes" not "months". If you change your pattern to "yyyy-MM" you'll find it works fine.
As a guiding principle the first thing I would do in a situation like this is try to isolate this to the smallest possible problem. So take text parsing and the complexity of DateTime (time zones etc) out of the equation:
LocalDate from = new LocalDate(2010, 1, 1);
LocalDate to = new LocalDate(2011, 6, 1);
int months = Months.monthsBetween(from, to).getMonths();
Now you'll see it's 17. So then the next step would be to go back to your original code, and print out the values of from and to... and you'll see something like:
2010-01-01T00:01:00.000Z
2011-01-01T00:06:00.000Z
Basically, avoid text parsing unless that's fundamentally part of the problem you're trying to diagnose.

Related

Calculating time difference between 2 dates in JodaTime

I using JodaTime and I need to check if 2 dates are in in range of 3 months difference. So I wrote simple method to check this
private boolean inRangeOf3Months(Pair<BusinessData, BusinessData> pair) {
return pair.getKey().getDateTimeValue() != null && pair.getValue().getDateTimeValue() != null ?
new Period(pair.getKey().getDateTimeValue(), pair.getValue().getDateTimeValue()).getMonths() <= 3 : false;
}
Now I'm writing tests and this one is fine
#Test
public void shouldReturnTrueWhenInRangeOf3Months() {
BusinessData closingDateFrom = businessData("closingDateFrom");
closingDateFrom.setDateTimeValue(DateTime.now());
BusinessData closingDateTo = businessData("closingDateTo");
closingDateTo.setDateTimeValue(DateTime.now().plusMonths(3));
ReportingSearchCriteria criteria = criteriaOf(closingDateFrom, closingDateTo);
Assert.assertTrue(validator.isSufficient(criteria));
}
But that one is not, I'm setting first date to now() and second one to now().plusMonths(3).plusDays(1). So its over my range, it shouldn't be allowed.
#Test
public void shouldReturnFalseWhenOverRangeOf3Months() {
BusinessData closingDateFrom = businessData("closingDateFrom");
closingDateFrom.setDateTimeValue(DateTime.now());
BusinessData closingDateTo = businessData("closingDateTo");
closingDateTo.setDateTimeValue(DateTime.now().plusMonths(3).plusDays(1));
ReportingSearchCriteria criteria = criteriaOf(closingDateFrom, closingDateTo);
Assert.assertFalse(validator.isSufficient(criteria));
}
Period of 3 months and a few days still have a difference of 3 months.
So if you want to make it 3 months inclusive you can add one day to last date and use just less than (instead of less than or equal):
new Period(pair.getKey().getDateTimeValue(), pair.getValue().getDateTimeValue().plusDays(1)).getMonths() < 3
Also, pay attention that the second date should be later the first one (otherwise it won't work).
If i understand your comparison must be on total days not on months because for example let's consider today's date as first date and second date with addition of 3 months plus 25 days
DateTime date1 = DateTime.now();
System.out.println(date1);
DateTime date2 = DateTime.now().plusMonths(3).plusDays(25);
System.out.println(date2);
Period p = new Period(date1,date2);
System.out.println(p.getMonths());
Output
2019-08-09T04:31:07.400-05:00
2019-12-04T04:31:07.449-06:00
3
Still it returns difference of months is 3 because the difference is 3 months and 25 days were 4 months not completed yet. Now if you add 3 months plus 30 days to second date it will return difference as 4 months (some times you might need to add 31 days because it depends on month that has 31 days)
DateTime date1 = DateTime.now();
System.out.println(date1);
DateTime date2 = DateTime.now().plusMonths(3).plusDays(30);
System.out.println(date2);
Period p = new Period(date1,date2);
System.out.println(p.getMonths());
Output
2019-08-09T04:34:29.530-05:00
2019-12-09T04:34:29.579-06:00
4
From the above approach you can't even take the months of two days and check whether difference is 3 months or not, because second date may return third month in some cases (like above if date is middle of month and if you add couple of days to it).
I will suggest compare the total days, for example total no of days between two days > 90 or > 91 for this you can use Duration
DateTime date1 = DateTime.now();
System.out.println(date1);
DateTime date2 = DateTime.now().plusMonths(3).plusDays(1);
System.out.println(date2);
Duration d = new Duration(date1, date2);
System.out.println(d.getStandardDays());
Output
2019-08-09T04:40:47.334-05:00
2019-11-10T04:40:47.381-06:00
93
Seems like the easiest is to just compare the 3 month away marks (buth past and future) to the other date.
public boolean areWithin3Months(DateTime dateTime1, DateTime dateTime2) {
return !dateTime1.minusMonths(3).isAfter(dateTime2)
&& !dateTime1.plusMonths(3).isBefore(dateTime2);
}

Different time interval util.date and DAYS.between(Localtime)

Something doesn't seem right and i just dont know how I can fix it.
I want to know the difference in days between 2 dates. Now I implemented a function, which calculates the differences from milliseconds to days for util.date objects
public long calculateNumberOfDays(Date from, Date to) {
return (to.getTime() - from.getTime()) / (1000*60*60*24);
}
My jUnit test told me, there was an error with this function, so I rewrote it using LocalDate and the ChronoUnit.DAYS.between function. It worked like a charm.
Wanting to know what the differences between those two functions were, I wrote this little test:
for(int numberDays = 1; numberDays<10; numberDays++){
LocalDate fromLD = LocalDate.now();
LocalDate toLD = fromLD.plusDays(numberDays);
Date fromD = Date.valueOf(fromLD);
Date toD = Date.valueOf(toLD);
long diffMS = toD.getTime() - fromD.getTime();
double diffDays = diffMS/(1000*60*60*24);
long numDaysDate = DAYS.between(fromLD, toLD);
System.out.println(numberDays+" = "+diffDays+"/"+numDaysDate);
}
It resulted in the following output:
1 = 1.0/1
2 = 2.0/2
3 = 3.0/3
4 = 4.0/4
5 = 4.0/5
6 = 5.0/6
7 = 6.0/7
8 = 7.0/8
9 = 8.0/9
Can someone explain to me, how this is possible? (1-4 it works, 5-9 util.date has lost a day)
Dates are hard. A java Date is a date and time, so when you set it to an actual date, it means midnight on that date.
Daylight savings time kicks in any day now (at least over here), so midnight on Monday will be 23 hours after midnight on Sunday.
Dividing integers rounds down, so 4 days and 23 hours is 4 days
Casting the result of an integer division to a double is too late; you need to cast either or both of the inputs:
double diffDays = diffMS/(1000*60*60*24);
4.0
double diffDays = diffMS/(1000.0*60*60*24);
4.958333...

Remaining years, months, days using joda time (Android)

I am trying to obtaining remaining years, months, and days between two dates:
So I have used Joda Time to do so:
DateTime endDate = new DateTime(2018,12,25,0,0);
DateTime startDate = new DateTime();
Period period = new Period(startDate,endDate,PeriodType.yearMonthDay());
PeriodFormatter formatter = new PeriodFormatterBuilder().appendYears().appendSuffix(" Year ").
appendMonths().appendSuffix(" Month ").appendDays().appendSuffix(" Day ").appendHours()..toFormatter();
String time = formatter.print(period);
This gives me string time: 2 Year 4 Month 22 Day
However, I want integer values of each number of remaining years, months, days.
So, Instead of "2 Year 4 Month 22 Day", I want to set my variables:
int year = 2
int month = 4
int day = 22
Is there any way to obtain these values separately instead of obtaining one string? Thank you so much! :)
i had the same requirement once ,here is the code snippet
LocalDate d=LocalDate.of(yy,mm,dd);
LocalDate d2=LocalDate.of(yy, mm, dd);
Period p=Period.between(d, d2);
long day,month,year;
day=p.getDays();
month=p.getMonths();
year=p.getYears();
System.out.println(day+" : "+month+" : "+year);
Invoke the methods provided by the DateTime class and just subtract them. An example for years is below:
int year = (int) dateTime#year#getField() - (int) dateTime2#year#getField()
UNTESTED code!! I'll be looking into it later but the general idea is the same, get the field information then just subtract it to get a value

Time between Dates using LocalDate and Period

If I do:
public static void main(String[] args) {
LocalDate d1 = LocalDate.of(2015, Month.MARCH, 12);
LocalDate d2 = LocalDate.of(2015, Month.APRIL, 13);
System.out.println(d1.until(d2).getDays());
// Prints 11
LocalDate d3 = LocalDate.of(2015, Month.APRIL, 25);
// Prints 23.
Both of which are incorrect. The second output makes sense as there is 1 month and 23 days between them.
How do I get the total number of days between?
I would want the first output to be 32 Days and the second to be 44 days (the total number of days between
the two dates).
What am I doing wrong? I don't see a totalDays() method.
You should probably not use a period (which has year and month components) if you are only interested in days. One solution to your question is:
System.out.println(DAYS.between(d1, d2)); //32
or alternatively:
System.out.println(d1.until(d2, DAYS)); //32
Note: I'm using import static java.time.temporal.ChronoUnit.DAYS;
I don't know how much you want to do with dates and possible you don't need it but I really recommend Joda Time and here is how to get number of days between two dates.
In Java 8 we finally have good Dates library but if you don't use Java 8 then you have to get Joda Time

How to calculate age in year and month between 2 dates in Java [duplicate]

This question already has answers here:
How do I calculate someone's age in Java?
(28 answers)
Closed 9 years ago.
I am a newbie and appreciate if someone help me out.
When I tried to calculate age using the below source , it does not give me the value of what I want . For example : date->29/12/2010 , dob->30/12/1992 , it will give me 18 instead of 17.
Is there any method that I can code to return me 17yrs 11mths based on the above 2 dates instead of 18yrs0mths?
public double getAgeAsOf( Date date ) {
return ((date.getTime() - dob.getTime())/(1000*60*60*24))/365;
}
Thanks.
You can use Joda Time and compute a Period between two LocalDate values (which is what you've got here) using months and years as the units.
Sample code:
import org.joda.time.*;
public class Test {
public static void main(String[] args) {
LocalDate dob = new LocalDate(1992, 12, 30);
LocalDate date = new LocalDate(2010, 12, 29);
Period period = new Period(dob, date, PeriodType.yearMonthDay());
System.out.println(period.getYears() + " years and " +
period.getMonths() + " months");
}
}
(This uses a period type which includes days as well, but that won't affect the answer.)
In general, Joda Time is a much better API than using Date/Calendar - and you really don't want to get into the business of performing date calculations yourself if you can avoid it. It gets messy really quickly.
As per aioobe's answer, if you divide two integer expressions the arithmetic will be performed in integer arithmetic, which may not be what you want - but for date and time arithmetic, just let someone else do the hard work in the first place :)
The code above will use the ISO-8601 calendar by the way, which is basically the Gregorian calendar. If you want to use something else, specify it as another constructor argument after the year/month/day for LocalDate.
You have a few problems with your code:
You're doing integer division, which truncates the result to the closest lower integer.
For example, if you divide 729 by 365 you'll get 1 (and you've lost the fractional part, which you would need when calculating months etc)
Another problem is that you're using 365 days for one year, while it is actually closer to 365.25 (when including extra days due to leap years).
Here's a slightly improved snippet of code:
import java.util.Date;
public class Test {
static double msPerGregorianYear = 365.25 * 86400 * 1000;
static Date dob = new Date(1992, 12, 30);
public static double getAgeAsOf(Date date) {
return (date.getTime() - dob.getTime()) / msPerGregorianYear;
}
public static void main(String[] args) {
double years = getAgeAsOf(new Date(2010, 12, 29));
// years == 17.99315537303217
int yy = (int) years;
int mm = (int) ((years - yy) * 12);
// Prints "17 years and 11 moths."
System.out.printf("%d years and %d moths.", yy, mm);
}
}
If you're ever doing anything more complicated than figuring out the number of years given the number of milliseconds, I suggest you turn to some time-library such as Joda time as suggested by Jon Skeet.

Categories