Получить григорианское свидание из строк хиджры
Я хотел бы получить григорианскую дату из индексов хиджры.
например
getDate(1436, "SHawwal", 18)
Это должно вернуться
3rd August 2015
Как я мог сделать преобразование?
1 ответ
Сожалею, что вам плохо посоветовали. Многие люди слепо рекомендуют известные библиотеки, такие как Joda-Time, даже не проверяя, может ли это решить вашу проблему и удовлетворить ваши требования.
Какое требование? Вы заявили:
значение кортежа (1436, "SHawwal", 18) => григорианская дата в виде строки ("3 августа 2015 года")
Давайте сначала продемонстрируем, что Joda-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 сделает это, так как предполагается, что это бэкпорт java.time
(JSR-310) на Android?
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 относительно календаря Хиджры, вы увидите большую разницу. ThreetenBP НЕ использует календарь Umalqura! Это де-факто эквивалентно модели високосного года LEAP_YEAR_16_BASED для Joda-Time. Что ж, в качестве (неудобного) обходного пути вы можете настроить ThreetenBP таким образом, чтобы сообщать об отклонениях, определяя описанный здесь файл конфигурации. Но я сильно подозреваю, что это будет работать только на Java-платформах, потому что ThreetenABP (Android-миграция ThreetenBP) не заботится об определении такого файла в каталоге assets данного приложения Android.
Что насчет ICU4J?
ICU4J (международные компоненты для Unicode), кажется, работает, по крайней мере, с тремя вариантами: ISLAMIC, ISLAMIC_TBLA и ISLAMIC_UMALQURA. Все 3 варианта дают "2015-08-03". Таким образом, вы должны тщательно решить, какой использовать, потому что эти варианты будут отличаться в другие дни! Что касается варианта TBLA, это полуакадемическое приближение, аналогичное LEAP_YEAR_16_BASED для Joda-Time (но с использованием четверговой эпохи - разница в один день все время). Вариант под названием ISLAMIC - это упрощенная астрономическая симуляция лунных циклов. Мое подозрение, что вы скорее хотите Umalqura-календарь Саудовской Аравии, верно???
В любом случае, у ICU4J есть один большой недостаток. Он не очень хорошо разработан для платформы Android и очень большой (10,7 МБайт). Некоторые люди сообщили, что не смогли запустить это программное обеспечение на Android.
Моя рекомендация: используйте Time4A
Результатом моего анализа текущей поддержки календаря Hijri на платформе Android стала разработка альтернативной библиотеки под названием Time4A, которая также поможет людям, использующим календарь Hijri на этой платформе. Эта библиотека (версия v3.6-2015f) поддерживает 8 моделей високосного года, в том числе tbla (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<HijriCalendar> 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<PlainDate> 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
Но вам все еще нужно подумать о том, какой вариант календаря хиджры вам действительно нужен. Никакое интеллектуальное программное обеспечение не может решить это за вас.