从Hijri日期字符串获取格里高利日期

我想从Hijri日期索引中得到一个格里高利日期。

例如

getDate(1436, "SHawwal", 18) 

这应该回来了

 3rd August 2015 

我怎么能进行转换?

我很遗憾你不明智。 许多人盲目推荐像Joda-Time这样的知名图书馆,甚至没有检查这是否能解决您的问题并符合您的要求

哪个要求? 你说过了:

value元组(1436,“SHawwal”,18)=>格里高利日期为字符串(“2015年8月3日”)

让我们首先certificateJoda-Time无法进行此转换。 Shawwal(“شوال”)是伊斯兰农历的第十个月。 所以我们可以尝试这个Joda-Time代码:

 Chronology hijri = IslamicChronology.getInstance(DateTimeZone.UTC, IslamicChronology.LEAP_YEAR_INDIAN); LocalDate dtHijri = new LocalDate(1436, 10, 18, hijri); Chronology iso = ISOChronology.getInstanceUTC(); LocalDate dtIso = // Joda does not offer a direct conversion, sorry dtHijri.toDateTimeAtStartOfDay(DateTimeZone.UTC) .withChronology(iso).toLocalDate(); System.out.println("hijri-to-gregorian: " + dtHijri + "=>" + dtIso); // hijri-to-gregorian: 1436-10-18=>2015-08-04 

Joda-Time提供的所有闰年模式(LEAP_YEAR_15_BASED,LEAP_YEAR_16_BASED,LEAP_YEAR_HABASH_AL_HASIB或LEAP_YEAR_INDIAN)产生的结果相同“2015-08-04”,比您的预期晚一天。 我已经明确测试了所有四种闰年模式。

Java-8是另一种选择吗?

 HijrahDate hd = HijrahChronology.INSTANCE.date(HijrahEra.AH, 1436, 10, 18); LocalDate ld = LocalDate.from(hd); System.out.println("java-8: " + ld); // java-8: 2015-08-03 

这很好,但我认为你需要在Android上完成这项工作。 那里你会失败,因为Java-8类根本不可用。

顺便说一句:为什么Java-8在这里产生正确的结果? 它使用沙特阿拉伯的Umalqura日历数据,而Joda-Time使用伊斯兰日历的四个半学术近似值。 实际上,伊斯兰日历存在于许多本地变体中(我上面的评论针对这一点要求您询问您要使用哪种变体)。

那么ThreetenABP会不会这样做,因为它应该是Android上的java.time (JSR-310)的java.time

 HijrahDate hd = HijrahChronology.INSTANCE.date(HijrahEra.AH, 1436, 10, 18); org.threeten.bp.LocalDate ld = org.threeten.bp.LocalDate.from(hd); System.out.println("threeten-bp: " + ld); // threeten-bp: 2015-08-04 

令人惊讶的是,后端失败了。 如果您注意ThreetenBP和Java-8关于Hijri日历的文档,那么您将看到一个很大的不同。 ThreetenBP不使用Umalqura日历! 它事实上相当于Joda-Time的闰年模式LEAP_YEAR_16_BASED。 好吧,作为(笨拙的)解决方法,您可以配置ThreetenBP,以便通过定义此处描述的配置文件来告知偏差。 但我强烈怀疑这只适用于Java平台,因为ThreetenABP ( ThreetenBP的Android迁移)并不关心在给定Android应用程序的assets-directory中定义这样的文件。

ICU4J怎么样?

ICU4J(Unicode的国际组件)似乎起作用,至少有三种变体 :ISLAMIC,ISLAMIC_TBLA和ISLAMIC_UMALQURA。 所有3种变体产生“2015-08-03”。 因此,您必须仔细决定使用哪一个,因为这些变体在其他日子会有所不同! 关于TBLA变体,这是半学术近似,类似于Joda-Time的LEAP_YEAR_16_BASED(但使用星期四时代 – 一直有一天的差异)。 称为ISLAMIC的变体是月球周期的简化天文模拟。 我怀疑你宁愿想要沙特阿拉伯的Umalqura日历,对吧?

无论如何,ICU4J有一个很大的缺点。 它不是为Android平台设计的,非常大(10.7 MByte)。 据报道有些人无法在Android上运行该软件。

我的建议: 使用Time4A

我分析当前对Android平台上Hijri日历的支持的结果是开发了一个名为Time4A的替代库,以帮助人们在该平台上使用Hijri日历。 该库(版本v3.6-2015f)支持8个半学术闰年模式,包括tbla-variant(HijriAlgorithm.WEST_ISLAMIC_ASTRO),沙特阿拉伯的Umalqura日历和ICU4J的天文模拟。 重要的是:Time4A还将理解阿拉伯语月份名称(使用new Locale("ar") )。 例:

 HijriCalendar hijri = HijriCalendar.of(HijriCalendar.VARIANT_UMALQURA, 1436, HijriMonth.SHAWWAL, 18); PlainDate iso = hijri.transform(PlainDate.class); System.out.println("Time4A: " + iso); // Time4A: 2015-08-03 

现在,最终的代码解决方案处理您的需求中的一些奇怪之处

 int hijriYear = 1436; String hijriMonth = "SHawwal"; int hijriDayOfMonth = 18; ChronoFormatter inputFormat = ChronoFormatter.setUp(HijriCalendar.class, Locale.ENGLISH) .addPattern("yyyyMMMMd", PatternType.NON_ISO_DATE).build(); HijriCalendar hijriDate = inputFormat .with(Attributes.PARSE_CASE_INSENSITIVE, true) .withCalendarVariant(HijriCalendar.VARIANT_UMALQURA) .parse(hijriYear + hijriMonth + hijriDayOfMonth); PlainDate iso = hijriDate.transform(PlainDate.class); ChronoFormatter outputFormat = ChronoFormatter.setUp(PlainDate.class, Locale.ENGLISH) .addEnglishOrdinal(PlainDate.DAY_OF_MONTH) .addPattern(" MMMM uuuu", PatternType.CLDR).build(); String s = outputFormat.format(iso); System.out.println(s); // 3rd August 2015 

但是你仍然需要考虑你真正想要的Hijri日历的哪个版本。 没有智能软件可以为您决定。