如何将回历日期转换为公历日期,反之亦然

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

我正在寻找一种方法来计算例如从现在到特定日期还有多少天,并且我可以使用它来确定我是否处于特定时间段(例如回历 +- 5 天)与否

我现在已经找了 10 多个小时,我找到的最好的东西是“HijrahDate”库“java.time.chrono.HijrahDate”和一个叫“Joda Date”的东西,我用起来有困难。

了解日期和时间在计算机内部表示为与纪元的偏移量:https://en.wikipedia.org/wiki/Epoch_(computing)

在 Java 中,您可以使用 System.currentTimeMillis();

获取此值

你也可以计算日差我减去两个日期数字并应用除法进行单位换算。

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

tl;博士

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

详情

现代方法使用 java.time classes 内置于 Java 8 和更高版本,以及 Android 26 和之后。对于早期版本,请参阅 ThreeTen-BackportThreeTenABP 项目。

Joda-Time 项目是 java.time 的前身。两者均由同一个人 Stephen Colebourne 创立和领导。

HijrahChronologyjava.time 的一部分。 HijrahChronology 遵循 Hijrah 日历系统的规则。回历是支持伊斯兰历的阴历。

HijrahDate class 表示回历系统中的日期。

搜索 Stack Overflow 以了解更多信息,因为这已被多次介绍。

我不是伊斯兰历或 HijrahChronology 方面的专家,但我相信您可以通过在 [=22] 上调用 from 方法在回历日期和公历(预想)日期之间进行转换=] 和 LocalDate classes.

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

……和……

LocalDate localDate2 = LocalDate.from( hijrahDate ) ;

两个日期 classes 都提供了 plusminus 方法,它们采用 Period 对象。

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

isEqualisBeforeisAfter 比较。

boolean match = localDate1.isEqual( localDate2 ) ;

转储到控制台。

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 ) ;

看到这个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

这是一个完整的例子。这里使用的时间跨度的比较方法是Half-Open,开始是inclusive,结束是exclusive。这种方法通常最适合日期时间处理。这种方法可以让日期范围彼此整齐地相邻,没有间隙或重叠。

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 );

转储到控制台。

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 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

这里是一个使用 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

您想使用哪种回历?

如果您选择沙特阿拉伯的官方日历,那么基于 java.time.HijrahDate 的解决方案就可以了。但是这个 class 需要在 Android 上至少 API 26 级。示例:

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

还有一些比较方法,例如 isAfter()isBefore() 继承自接口 ChronoLocalDate 和标准的 plus() 方法,以确定您的日期是否在特定时间期间。

java.time 的反向移植:

对于较低的 Android 版本,还有一个名为 ThreetenABP 的向后移植。但要注意它的 HijrahDate 实现不同并且不使用沙特阿拉伯日历的陷阱(因此您必须容忍日期转换的差异)。

关于 Joda-Time:

如果您选择那个(相当过时的)库,那么您应该选择库版本 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(嵌入Android):

它的 class IslamicCalendar 提供了一种类似于旧日历 classes java.util.Calendar 的风格,还有包括沙特阿拉伯日历在内的几种变体。所需的最低 API 等级是 24。

Time4A:

这是我自己编写的库(如 adaptation of Time4J for Android). It offers the class HijriCalendar 有多种变体,包括 Joda 变体,但也包括沙特阿拉伯日历(变体 ummalqura)。它提供了所有需要的功能,如日期算法(通过 plus()- 或 minus()- 方法),日期比较(通过 isAfter() 等)。示例:

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();

其他库不支持日落作为一天的开始等功能。 Muharram +- 5days-request 的示例可能如下所示:

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));