问题
I am looking for a Library that can give me the needed tools, 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.
If anyone can help me with that, it would be much appreciated.
回答1:
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));
回答2:
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
回答3:
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
来源:https://stackoverflow.com/questions/61503812/is-there-a-hijri-date-to-georgian-date-conv-and-vice-versa-which-is-reliable