Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validation of Hijri Date (Islamic Calendar) on Java 6

I want to validate Hijri date. In my application Hijri date will come as in the format of dd/MM/YYYY. I want to validate whether date is valid or not in Joda Time API.

For example, I have the date:

String date = "30/02/1403";
String Pattern = "dd/MM/YYYY";

Can you please help me to validate Hijri date.

My restrictions are:

  • I want to validate in Java 6. I can't use in Java 8.
  • I have to validate with Islamic calendar. validate with Hijri date. My date is already in Hijri format. I have to validate that date is valid or not with Islamic calendar.
  • In the Islamic calendar 30/02/1403 is a valid date of 2nd month.
like image 801
Rameez Kandhar Avatar asked Jan 28 '23 04:01

Rameez Kandhar


2 Answers

java.time

java.time, the modern Java date and time API, can do this:

    DateTimeFormatter hijrahFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy")
                .withChronology(HijrahChronology.INSTANCE);
    try {
        HijrahDate date = hijrahFormatter.parse("30/02/1403", HijrahDate::from);
        System.out.println("A valid date: " + date);
    } catch (DateTimeParseException dtpe) {
        System.out.println("Not a valid date: " + dtpe.getMessage());
    }

The output from this snippet is:

A valid date: Hijrah-umalqura AH 1403-02-30

Format pattern letters are case sensitive. You need lowercase yyyy for calendar year (or uuuu for proleptic year).

Java 6? Three options.

I want to validate in Java 6. I can't use in Java 8.

That’s old now (Java 11 is out). My suggestions are:

  1. Use ThreeTen Backport, the backport of java.time to Java 6 and 7. It turns out that it doesn’t work perfectly for your case, but you can.
  2. Use Joda-Time as you asked about from the outset.
  3. Use Time4J.

The first two options will reject your date of 30/02/1403, though, believing there are only 29 days in the 2nd month of 1403.

ThreeTen Backport

    DateTimeFormatter hijrahFormatter = DateTimeFormatter.ofPattern("dd/MM/uuuu")
            .withChronology(HijrahChronology.INSTANCE);
    String dateString = "30/02/1403";
    try {
        TemporalAccessor parsed = hijrahFormatter.parse(dateString);
        HijrahDate date = HijrahChronology.INSTANCE.date(parsed.get(ChronoField.YEAR),
                parsed.get(ChronoField.MONTH_OF_YEAR),
                parsed.get(ChronoField.DAY_OF_MONTH));
        if (date.format(hijrahFormatter).equals(dateString)) {
            System.out.println("A valid date: " + date);
        } else {
            System.out.println("Not a valid date: " + dateString);
        }
    } catch (DateTimeParseException dtpe) {
        System.out.println("Not a valid date: " + dtpe.getMessage());
    }

Output:

Not a valid date: 30/02/1403

According to my understanding the following simpler way to construct the date ought to work, but doesn’t:

        HijrahDate date = HijrahDate.from(parsed);

I get org.threeten.bp.DateTimeException: Field not found: EpochDay. The way I construct the date instead is lenient, that is, it accepts that the day of month is out of range and produces a date of Hijrah-umalqura AH 1403-03-01. So to complete the validation I format the date back and require that I get the original string again.

If instead of 30/02/1403 I try with 29/02/1403, I get

A valid date: Hijrah-umalqura AH 1403-02-29

Joda-Time

    DateTimeFormatter islamicFormatter = DateTimeFormat.forPattern("dd/MM/yyyy")
            .withChronology(IslamicChronology.getInstance());
    try {
        LocalDate date = LocalDate.parse("30/02/1403", islamicFormatter);
        System.out.println("A valid date: " + date);
    } catch (IllegalArgumentException iae) {
        System.out.println("Not a valid date: " + iae.getMessage());
    }

Joda-Time too thinks there are 29 days in this month and states that very clearly:

Not a valid date: Cannot parse "30/02/1403": Value 30 for dayOfMonth must be in the range [1,29]

With a string of 29/02/1403 I got:

A valid date: 1403-02-29

Joda-Time’s Islamic chronology comes with four different leap year patterns. I tried all four. They all yield 29 days in the second month of 1403. I am sorry, this as close as I can get.

From the Joda-Time homepage:

Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).

Time4J

I refer you to the knowledgeable answer by Meno Hochschild, the author of Time4J. It would seem to me that Time4J version 3.50 solves your issue according to your requirements and on Java 6.

But is that date valid or not?

But If you will check the Islamic calendar it is a valid date of 2nd month.

You’re much more an expert than I am. I seem to understand that variants of the Hijri calendar exist. According to your variant 30/02/1403 is a perfectly valid date. The version given by alhabib Islamic web services agrees with yours: Safar 30, 1403 is the same day as December 16, 1982 in the Gregorian calendar. On the other hand according to searchtruth.com, there are only 29 days in the month of Safar 1403 (Safar 29, 1403 corresponds to December 15, 1982 Gregorian and is followed by Rabi Al-Awwal 1, 1403 corresponding to December 16).

Links

  • Oracle tutorial: Date Time explaining how to use java.time.
  • Java Specification Request (JSR) 310, where java.time was first described.
  • ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
  • ThreeTenABP, Android edition of ThreeTen Backport
  • Joda-Time homepage
  • Time4J - Advanced Date, Time, Zone and Interval Library for Java
  • Answer by Meno Hochschild (just for the sake of completeness)
  • Islamic (Hijri) Calendar Year 1982 CE Based on Global Crescent Moon Sighting Probability on alhabib islamic web services
  • Hijri Islamic Calendar November 1982 - 1403 التقويم الهجري والميلادي on searchtruth.com
like image 56
Ole V.V. Avatar answered Jan 29 '23 19:01

Ole V.V.


As supplement to the answer of Ole, I enumerate here some variants of Hijri calendar and the validation results using my lib Time4J which offers more support for variants and also offers an extra static validation method:

String variant;
for (HijriAlgorithm ha : HijriAlgorithm.values()) {
    variant = ha.getVariant();
    System.out.println(variant + "=>" + HijriCalendar.isValid(variant, 1403, 2, 30));
}
variant = HijriCalendar.VARIANT_DIYANET;
System.out.println(variant + "=>" + HijriCalendar.isValid(variant, 1403, 2, 30));
variant = HijriCalendar.VARIANT_UMALQURA;
System.out.println(variant + "=>" + HijriCalendar.isValid(variant, 1403, 2, 30));

The output is:

islamic-eastc=>false

islamic-easta=>false

islamic-civil=>false

islamic-tbla=>false

islamic-fatimidc=>false

islamic-fatimida=>false

islamic-habashalhasibc=>false

islamic-habashalhasiba=>false

islamic-diyanet=>true

islamic-umalqura=>true

So we can see that all algorithmic variants of Hijri calendar don't support your expectation but the diyanet and the umalqura variant. Probably you want the umalqura variant (the official calendar of Saudi-Arabia, but please clarify if you have more details about your expectations).

About your wish to solve your problem with Joda-Time, sorry, there is no chance to validate 1403-02-30 as valid because Joda-Time only supports four algorithmic variants (as subset of what Time4J supports). The same can be said for the Threeten-Backport which supports only "islamic-tbla" (or "islamic-civil" - here the API is not well documented). The java.time-package only supports one variant, too, but that variant (umalqura) matches your expectation. However, java.time does not run on Java 6.

If you are willing to consider an alternative to Joda-Time which matches your expectations about validation then I see mainly two ways:

  • my lib Time4J (backport version v3.50 which runs on Java 6+7)
  • msarhan
like image 44
Meno Hochschild Avatar answered Jan 29 '23 17:01

Meno Hochschild