Visonge
Visonge

Reputation: 99

How to convert from Hijri Date to Georgian Date and vice versa

I am looking for a way to calculate for example how many days it is from now, to a specific Date AND that I can use to determine whether I am in a specific time period (eg. Muharram +- 5days) or not

I have been looking for over 10hours now, and the best things I found were the "HijrahDate" library "java.time.chrono.HijrahDate" and something called "Joda Date", which I had difficulties to use.

Upvotes: 3

Views: 2023

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 339679

tl;dr

HijrahDate
.from
(
    LocalDate.of( 2020 , Month.JANUARY , 23 ) 
)
.plus
(
    Period.ofDays( 5 ) 
)
.isBefore
(
    someOtherDate
)

Details

The modern approach uses the java.time classes built into Java 8 and later, and Android 26 and later. For earlier versions, see the ThreeTen-Backport and ThreeTenABP projects.

The Joda-Time project is the predecessor of java.time. Both are founded and led by the same man, Stephen Colebourne.

The HijrahChronology is part of java.time. The HijrahChronology follows the rules of the Hijrah calendar system. The Hijrah calendar is a lunar calendar supporting Islamic calendars.

The HijrahDate class represents a date in the Hijrah calendar system.

Search Stack Overflow to learn more, as this has been covered multiple times already.

I am not an expert on Islamic calendars or HijrahChronology, but I believe you can convert between a Hijrah date and a Gregorian (proleptic) date by calling the from method on HijrahDate and LocalDate classes.

LocalDate localDate1 = LocalDate.of( 2020 , Month.JANUARY , 23 ) ;
HijrahDate hijrahDate = HijrahDate.from( localDate1 ) ;

…and…

LocalDate localDate2 = LocalDate.from( hijrahDate ) ;

Both date classes offer plus and minus methods that take a Period object.

LocalDate later = localDate2.plus( Period.ofDays( 5 ) ) ;

Compare with isEqual, isBefore, and isAfter.

boolean match = localDate1.isEqual( localDate2 ) ;

Dump to console.

System.out.println( "localDate1.toString(): " + localDate1 ) ;
System.out.println( "hijrahDate.toString(): " + hijrahDate ) ;
System.out.println( "localDate2.toString(): " + localDate2 ) ;
System.out.println( "match: " + localDate1.isEqual( localDate2 ) ) ;
System.out.println( "later.toString(): " + later ) ;

See this code run live at IdeOne.com.

localDate1.toString(): 2020-01-23

hijrahDate.toString(): Hijrah-umalqura AH 1441-05-28

localDate2.toString(): 2020-01-23

match: true

later.toString(): 2020-01-28

Here is a complete example. The comparison method for a span-of-time used here is Half-Open, where the beginning is inclusive while the ending is exclusive. This approach is usually best in date-time handling. This approach lets date ranges neatly abut one another without gaps or overlaps.

LocalDate localDate = LocalDate.of( 2020 , Month.JANUARY , 23 );
HijrahDate hijrahDate = HijrahDate.from( localDate );

// Target range is five days before and after some specific date.
HijrahDate target = HijrahDate.from( LocalDate.of( 2020 , Month.MARCH , 14 ) );
Period period = Period.ofDays( 5 );
LocalDate start = LocalDate.from( target ).minus( period );
LocalDate end = LocalDate.from( target ).plus( period );

// Tip: A shorter way of asking "Is equal to or later" is "Is not before".
boolean withinTargetRange = ( ! hijrahDate.isBefore( start ) ) && hijrahDate.isBefore( end );

Dump to console.

System.out.println( "localDate = " + localDate );
System.out.println( "hijrahDate = " + hijrahDate );
System.out.println( "target = " + target );
System.out.println( "withinTargetRange = " + withinTargetRange );

localDate = 2020-01-23

hijrahDate = Hijrah-umalqura AH 1441-05-28

target = Hijrah-umalqura AH 1441-07-19

withinTargetRange = false

ThreeTen-Extra

If doing much of this work, I suggest adding the ThreeTen-Extra library, also founded and led by Stephen Colebourne. The LocalDateRange class in that library represents a span of time as a pair of LocalDate objects. This class includes methods such as contains, abuts, overlaps, and more. I do not know how well this library works in Android. If not working well in Android, you may want to pull a copy of the class’s source code into your codebase, provided you can abide by the terms of its BSD-3 licensing.

Here is an example using LocalDateRange::contains.

LocalDate localDate = LocalDate.of( 2020 , Month.JANUARY , 23 );
HijrahDate hijrahDate = HijrahDate.from( localDate );

HijrahDate target = HijrahDate.from( LocalDate.of( 2020 , Month.MARCH , 14 ) );
Period period = Period.ofDays( 5 );
LocalDate start = LocalDate.from( target ).minus( period );
LocalDate end = LocalDate.from( target ).plus( period );
LocalDateRange range = LocalDateRange.of( start , end );

boolean withinTargetRange = range.contains( LocalDate.from( hijrahDate ) );
localDate = 2020-01-23
hijrahDate = Hijrah-umalqura AH 1441-05-28
target = Hijrah-umalqura AH 1441-07-19
range = 2020-03-09/2020-03-19
withinTargetRange = false

Upvotes: 2

Meno Hochschild
Meno Hochschild

Reputation: 44071

Which variation of Hijri calendar do you want to use?

If you opt for the official calendar of Saudi-Arabia then the solution based on java.time.HijrahDate would work. But this class requires at least API level 26 on Android. Example:

HijrahDate hd1 = HijrahDate.now();
HijrahDate hd2 = HijrahDate.from(LocalDate.of(2020, 5, 1));
long days = ChronoUnit.DAYS.between(hd1, hd2);

There are also comparison methods like isAfter() or isBefore() inherited from the interface ChronoLocalDate and standard plus()-methods in order to determine if your date is in a specific time period.

Backport of java.time:

There is also a backport called ThreetenABP for lower Android-versions. But be aware of the pitfall that its implementation of HijrahDate is different and does NOT use the calendar of Saudi-Arabia (so you have to tolerate differences in date conversion).

About Joda-Time:

If you opt for that (rather outdated) library then you should choose the library version adapted for android. However, it does not support the calendar of Saudi-Arabia, too, but offers four different other variations. You would need to specify the algorithmic leap year pattern.

ICU4J (embedded in Android):

Its class IslamicCalendar offers a style similar to old calendar classes java.util.Calendar and also several variants including that of Saudi-Arabia. The minimum required API level is 24.

Time4A:

That is a library written by myself (as adaptation of Time4J for Android). It offers the class HijriCalendar with several variations including the Joda-variants but also including the calendar of Saudi-Arabia (variant ummalqura). It offers all needed features like date arithmetic (by plus()- or minus()-method), date comparison (by isAfter() etc.). Example:

String variant = HijriCalendar.VARIANT_UMALQURA;
StartOfDay startOfDay = StartOfDay.definedBy(SolarTime.ofMecca().sunset());
HijriCalendar today = HijriCalendar.nowInSystemTime(variant, startOfDay);
HijriCalendar hcal = // gregorian to Hijri conversion
    PlainDate.of(2020, 5, 1).transform(HijriCalendar.class, variant);
long days = CalendarDays.between(today, hcal).getAmount();

Features like sunset as start of day are not supported by other libraries. Example for your Muharram +- 5days-request might look like:

CalendarDays tolerance = CalendarDays.of(5);
HijriCalendar htemp = today.with(HijriCalendar.MONTH_OF_YEAR, HijriMonth.MUHARRAM);
HijriCalendar h1 = htemp.with(HijriCalendar.DAY_OF_MONTH.minimized()).minus(tolerance);
HijriCalendar h2 = htemp.with(HijriCalendar.DAY_OF_MONTH.maximized()).plus(tolerance);
boolean inTimePeriod = !(today.isBefore(h1) || today.isAfter(h2));

Upvotes: 5

ControlAltDel
ControlAltDel

Reputation: 35096

Understand that dates and times are represented internally in computers as an offset from an epoch: https://en.wikipedia.org/wiki/Epoch_(computing)

In Java, you can get this value using System.currentTimeMillis();

You can also calculate day difference my substracting two date numbers and applying division to do unit conversion.

long days = (date2 - date1) 
  / 1000 // MS
  / 60 // Secs
  / 60 // Mins
  / 24 // Hours

Upvotes: 0

Related Questions