Hot questions for Using Joda-Time in gregorian calendar

Top Java Programmings / Joda-Time / gregorian calendar

Question:

I'm trying to use Joda library since count periods with Java native methods is a pain in the neck and all my attempts give unprecise results

I have seen this sample to

int n = Days.daysBetween(start.toLocalDate(), end.toLocalDate()).getDays();

since all my classes manage GregorianCalendar, I need that method that counts the days support GregorianCalendar, something like

 public int countDays(GregorianCalendar start, GregorianCalendar end){
     //convert to joda start and end
     ...
     return Days.daysBetween(start.toLocalDate(), end.toLocalDate()).getDays();
 }

So my question: How to convert and reconvert GregorianCalendar object to the object managed by Joda without side effects?


Answer:

Use the DateTime constructor that takes an Object, which can "include ReadableInstant, String, Calendar and Date." It specifically mentions GregorianCalendar, as well.

public int countDays(GregorianCalendar gregStart, GregorianCalendar gregEnd) {
    DateTime start = new DateTime(gregStart);
    DateTime end = new DateTime(gregEnd);
    return Days.daysBetween(start, end).getDays();
}

Question:

I am trying to convert an ISO (Gregorian) date into a hijri (Islamic) date and the compare the first to a hijri date.

What I do and it does not work is:

    Chronology iso = ISOChronology.getInstanceUTC();
    Chronology hijri = IslamicChronology.getInstanceUTC();

    DateTime dtISO = new DateTime("2015-03-12T10:04:43", iso);

    System.out.println("dtISO: " + dtISO);
    DateTime toHijri = new DateTime(dtISO, hijri);
    System.out.println("toHijri: " + toHijri); // 1436-05-21T10:04:43.000Z
    DateTimeFormatter formatter = DateTimeFormat.forPattern("YYYY-MM-dd HH-mm");

    DateTime hijriDt = new DateTime(formatter.parseDateTime("1442-05-21 10-10"), iso);

    if (hijriDt.isAfter(toHijri)) {
        System.out.println("hijriDt date is after toHijri date");
    }
    if (hijriDt.isBefore(toHijri)) {
        System.out.println("hijriDt date is before toHijri date");
    }
    if (hijriDt.isEqual(toHijri)) {
        System.out.println("hijriDt date is equal toHijri date");
    }

No matter what the hijri date is it always returns "hijriDt date is before toHijri date".

Now as I was experimenting I tried this:

    Chronology iso = ISOChronology.getInstanceUTC();
    Chronology hijri = IslamicChronology.getInstanceUTC();

    LocalDateTime toHijri = new LocalDateTime(new DateTime("2015-03-12T10:04:43", iso), hijri);
    System.out.println("toHijri: " + toHijri); // 1436-05-21T10:04:43.000Z
    DateTimeFormatter formatter = DateTimeFormat.forPattern("YYYY-MM-dd HH-mm");

    LocalDateTime hijriDt = new LocalDateTime(formatter.parseDateTime("1442-05-21 10-10"), iso);

    if (hijriDt.isAfter(toHijri)) {
        System.out.println("hijriDt date is after toHijri date");
    }
    if (hijriDt.isBefore(toHijri)) {
        System.out.println("hijriDt date is before toHijri date");
    }
    if (hijriDt.isEqual(toHijri)) {
        System.out.println("hijriDt date is equal toHijri date");
    }

which works like a charm. Notice how the toHijri date is constructed: LocalDateTime toHijri = new LocalDateTime(new DateTime("2015-03-12T10:04:43", iso), hijri);

A DateTime instance is wrapped inside a LocalDateTime.

Why is this happening? Why the first block does not work?


Answer:

This is not what you want:

DateTime hijriDt = new DateTime(formatter.parseDateTime("1442-05-21 10-10"), iso);

That's not using the Hijri calendar anywhere:

  • Your formatter is using ISO (by default)
  • You're parsing a date in year 1442 ISO, which isn't what you want
  • You're then "converting" that into the ISO calendar (which it already is)
  • Your variable name suggests that you're expecting it to be in the Hijri calendar, but it's not

I suspect you want:

DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH-mm")
    .withChronology(hijri);
DateTime hijriDt = formatter.parseDateTime("1442-05-21 10-10");

Question:

I have to implement a function that returns (month to month) the starting date and the final date of the last 12 months. For example:

In May of this year I want to show as a result:

01/05/2016 00: 00: 00: 000T / 30/04/2017 23: 59: 59: 999T.

I created the following function, wanted to ask if this is correct or is there another simpler solution?

public Interval getPeriod() {
    MutableDateTime fromDateTime = new MutableDateTime(new DateTime().withTimeAtStartOfDay());
     fromDateTime.addMonths(-12); // Start Month        
     fromDateTime.setDayOfMonth(1); // First day start month

    MutableDateTime toDateTime = new MutableDateTime(new DateTime().withTimeAtStartOfDay());
    toDateTime.addMonths(-1); // last month
    toDateTime.setDayOfMonth(1); // firt day last month

    DateTime firstDayStart = fromDateTime.toDateTime();

    DateTime firstDayLastMonth = toDateTime.toDateTime();
    DateTime lastDayLastMonth = firstDayLastMonth.dayOfMonth().withMaximumValue();
    DateTime lastInstantLastMonth = lastDayLastMonth.withTime(23, 59, 59, 999);
    log.debug("start: {} end: {}",firstDayStart, lastInstantLastMonth);
    return new Interval(firstDayStart, lastInstantLastMonth);
}

Answer:

A simpler solution would be to not create lots of MutableDateTime instances and use only DateTime's methods:

public Interval getPeriod() {
    DateTime d = new DateTime(); // current date
    DateTime start = d.withDayOfMonth(1).minusMonths(12) // day 1 of 12 months ago
                      .withTimeAtStartOfDay(); // start date
    DateTime end = d.minusMonths(1) // previous month
                    .dayOfMonth().withMaximumValue() // last day of month
                    .withTime(23, 59, 59, 999); // end date

    return new Interval(start, end);
}

Question:

I have 2 DateTime values: date1 = "1492-10-12" and date2 = "1992-10-12". When I use Years.yearsBetween(date1, date2).getYears(), I get 499. I was expecting 500. If I use date1 = "1892-10-12" and date2 = "1992-10-12", then I get 100.

In diagnosing the issue, I found that the problem first occurs when I have 2 DateTime values: date1 = "1492-10-12" and date2 = "1583-10-12". I get 90 years when I should be getting 91. When date2 = "1582-10-12" or earlier, then the calculation is correct.

I am assuming that this is because the Gregorian calendar started in 1582, but I'm not sure why we are 1 year off. Any ideas? Is 499 theoretically correct or is there a problem with with yearsBetween when 1582 falls within the start and end dates?

My code looks like:

Date date1 = null;
Date date2 = null;
try {
    date1 = sdf.parse("1492-10-12");
    date2 = sdf.parse("1992-10-12");
} 
catch (ParseException e) {
    e.printStackTrace();
}
int yrs = computeDiffInYears(date1, date2);  ?? yrs = 499

private static int computeDiffInYears(Date date1, Date date2) {
    DateTime dt1 = (new DateTime(date1));
    DateTime dt2 = (new DateTime(date2));
    return Years.yearsBetween(dt1, dt2).getYears();
}

UPDATE: If I rewrite the method, computeDiffInYears, as suggested by Anarki as:

private static int computeDiffInYears(Date date1, Date date2) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    DateTime dt1 = new DateTime(sdf.format(date1));
    DateTime dt2 = new DateTime(sdf.format(date2));
    return Years.yearsBetween(dt1, dt2).getYears();
}

then it works correctly


Answer:

You can try this :

public static void main(String[] args) throws ParseException {
    SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
    Date first = sdf.parse("12-10-1492");
    Date last = sdf.parse("12-10-1992");
    System.out.println(getDiffYears(first, last));
}

public static int getDiffYears(Date first, Date last) {
    Calendar a = getCalendar(first);
    Calendar b = getCalendar(last);
    int diff = b.get(Calendar.YEAR) - a.get(Calendar.YEAR);
    if (a.get(Calendar.MONTH) > b.get(Calendar.MONTH)
            || (a.get(Calendar.MONTH) == b.get(Calendar.MONTH) && a.get(Calendar.DATE) > b.get(Calendar.DATE))) {
        diff--;
    }
    return diff;
}

public static Calendar getCalendar(Date date) {
    Calendar cal = Calendar.getInstance(Locale.US);
    cal.setTime(date);
    return cal;
}

It print 500 witch is correct.

Edit

I just tried this (using Joda) :

public static void main(String[] args) throws ParseException {
    DateTime date1 = new DateTime("1492-10-12");
    DateTime date2 = new DateTime("1992-10-12");
    int yrs = computeDiffInYears(date1, date2);
    System.out.println(yrs);
}

private static int computeDiffInYears(DateTime date1, DateTime date2) {
    return Years.yearsBetween(date1, date2).getYears();
}

It also print 500, but when i try to make a conversion from Date to DateTime it print 499, so you should use only DateTime or Calendar.