<commit_before>/*
 * -----------------------------------------------------------------------
 * Copyright © 2013-2016 <NAME>, <http://www.menodata.de/>
 * -----------------------------------------------------------------------
 * This file (HijriCalendar.java) is part of project Time4J.
 *
 * Time4J is free software: You can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * Time4J is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Time4J. If not, see <http://www.gnu.org/licenses/>.
 * -----------------------------------------------------------------------
 */

package net.time4j.calendar;

import net.time4j.GeneralTimestamp;
import net.time4j.Moment;
import net.time4j.PlainTime;
import net.time4j.Weekday;
import net.time4j.Weekmodel;
import net.time4j.base.MathUtils;
import net.time4j.base.TimeSource;
import net.time4j.calendar.service.GenericDatePatterns;
import net.time4j.calendar.service.StdEnumDateElement;
import net.time4j.calendar.service.StdIntegerDateElement;
import net.time4j.calendar.service.StdWeekdayElement;
import net.time4j.engine.AttributeQuery;
import net.time4j.engine.CalendarDays;
import net.time4j.engine.CalendarFamily;
import net.time4j.engine.CalendarVariant;
import net.time4j.engine.ChronoElement;
import net.time4j.engine.ChronoEntity;
import net.time4j.engine.ChronoException;
import net.time4j.engine.ChronoMerger;
import net.time4j.engine.ChronoUnit;
import net.time4j.engine.DisplayStyle;
import net.time4j.engine.ElementRule;
import net.time4j.engine.FormattableElement;
import net.time4j.engine.StartOfDay;
import net.time4j.engine.ValidationElement;
import net.time4j.engine.VariantSource;
import net.time4j.format.Attributes;
import net.time4j.format.CalendarType;
import net.time4j.format.Leniency;
import net.time4j.format.LocalizedPatternSupport;
import net.time4j.tz.TZID;
import net.time4j.tz.Timezone;

import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.time.chrono.Chronology;
import java.time.chrono.HijrahDate;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQueries;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * <p>Represents the Hijri calendar used in many islamic countries. </p>
 *
 * <p>It is a lunar calendar which exists in several variants and is mainly for religious purposes.
 * The variant used in Saudi-Arabia is named &quot;islamic-umalqura&quot; and is based on data partially
 * observed by sighting the new moon, partially by astronomical calculations/predictions. Note that the
 * religious authorities in most countries often publish dates which deviate from such official calendars
 * by one or two days. </p>
 *
 * <p>The calendar year is divided into 12 islamic months. Every month usually has either 29 or 30 days. The length
 * of the month in days shall reflect the date when the new moon appears. However, for every variant there
 * are different data or rules how to determine if a month has 29 or 30 days. The Hijri calendar day starts
 * in the evening. New variants can be configured by a file named &quot;{variant-name}.data&quot; in the
 * data-subdirectory of resource class path (where hyphens are replaced by underscores). Format details see
 * the file &quot;islamic_umalqura.data&quot;. </p>
 *
 * <p>Following elements which are declared as constants are registered by
 * this class: </p>
 *
 * <ul>
 *  <li>{@link #DAY_OF_WEEK}</li>
 *  <li>{@link #DAY_OF_MONTH}</li>
 *  <li>{@link #DAY_OF_YEAR}</li>
 *  <li>{@link #MONTH_OF_YEAR}</li>
 *  <li>{@link #YEAR_OF_ERA}</li>
 *  <li>{@link #ERA}</li>
 * </ul>
 *
 * <p>Furthermore, all elements defined in {@code EpochDays} and {@link CommonElements} are supported. </p>
 *
 * <p>Example of usage: </p>
 *
 * <pre>
 *     ChronoFormatter&lt;HijriCalendar&gt; formatter =
 *       ChronoFormatter.setUp(HijriCalendar.class, Locale.ENGLISH)
 *       .addPattern(&quot;EEE, d. MMMM yy&quot;, PatternType.NON_ISO_DATE).build()
 *       .withCalendarVariant(HijriCalendar.VARIANT_UMALQURA)
 *       .with(Attributes.PIVOT_YEAR, 1500); // mapped to range 1400-1499
 *     HijriCalendar hijri = formatter.parse(&quot;Thu, 29. Ramadan 36&quot;);
 *     PlainDate date = hijri.transform(PlainDate.class);
 *     System.out.println(date); // 2015-07-16
 * </pre>
 *
 * @author  <NAME>
 * @since   3.5/4.3
 * @doctags.concurrency {immutable}
 */
/*[deutsch]
 * <p>Repr&auml;sentiert den Hijri-Kalender, der in vielen islamischen L&auml;ndern vorwiegend f&uuml;r
 * religi&ouml;se Zwecke benutzt wird. </p>
 *
 * <p>Es handelt sich um einen lunaren Kalender, der in verschiedenen Varianten existiert. Die Variante
 * in Saudi-Arabien hei&szlig;t &quot;islamic-umalqura&quot; und basiert teilweise auf Daten gewonnen
 * durch die Sichtung des Neumonds, teilweise auf astronomischen Berechnungen und Voraussagen. Zu beachten:
 * Die religi&ouml;sen Autorit&auml;ten in den meisten L&auml;ndern folgen nicht streng den offiziellen
 * Kalendervarianten, sondern ver&ouml;ffentlichen oft ein Datum, das 1 oder 2 Tage abweichen kann. </p>
 *
 * <p>Das Kalendarjahr wird in 12 islamische Monate geteilt. Jeder Monat hat gew&ouml;hnlich entweder 29 oder
 * 30 Tage. Die L&auml;nge des Monats in Tagen soll den Zeitpunkt reflektieren, wann der Neumond gesichtet wird.
 * Aber jede Variante kennt verschiedenen Daten oder Regeln, um zu bestimmen, ob ein Monat 29 oder 30 Tage hat.
 * Der islamische Kalendertag startet am Abend. Neue Varianten k&ouml;nnen mit Hilfe einer Datei konfiguriert
 * werden, die den Namen &quot;{variant-name}.data&quot; hat und im data-Unterordner des Ressourcen-Klassenpfads
 * liegt (wobei Bindestriche durch Unterstriche ersetzt werden). Formatdetails siehe die vorhandene Datei
 * &quot;islamic_umalqura.data&quot;. </p>
 *
 * <p>Registriert sind folgende als Konstanten deklarierte Elemente: </p>
 *
 * <ul>
 *  <li>{@link #DAY_OF_WEEK}</li>
 *  <li>{@link #DAY_OF_MONTH}</li>
 *  <li>{@link #DAY_OF_YEAR}</li>
 *  <li>{@link #MONTH_OF_YEAR}</li>
 *  <li>{@link #YEAR_OF_ERA}</li>
 *  <li>{@link #ERA}</li>
 * </ul>
 *
 * <p>Au&slig;erdem werden alle Elemente von {@code EpochDays} und {@link CommonElements} unterst&uuml;tzt. </p>
 *
 * <p>Anwendungsbeispiel: </p>
 *
 * <pre>
 *     ChronoFormatter&lt;HijriCalendar&gt; formatter =
 *       ChronoFormatter.setUp(HijriCalendar.class, Locale.ENGLISH)
 *       .addPattern(&quot;EEE, d. MMMM yy&quot;, PatternType.NON_ISO_DATE).build()
 *       .withCalendarVariant(HijriCalendar.VARIANT_UMALQURA)
 *       .with(Attributes.PIVOT_YEAR, 1500); // mapped to range 1400-1499
 *     HijriCalendar hijri = formatter.parse(&quot;Thu, 29. Ramadan 36&quot;);
 *     PlainDate date = hijri.transform(PlainDate.class);
 *     System.out.println(date); // 2015-07-16
 * </pre>
 *
 * @author  <NAME><commit_msg>improved javadoc of HijriCalendar<commit_after>/*
 * -----------------------------------------------------------------------
 * Copyright © 2013-2016 <NAME>, <http://www.menodata.de/>
 * -----------------------------------------------------------------------
 * This file (HijriCalendar.java) is part of project Time4J.
 *
 * Time4J is free software: You can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * Time4J is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Time4J. If not, see <http://www.gnu.org/licenses/>.
 * -----------------------------------------------------------------------
 */

package net.time4j.calendar;

import net.time4j.GeneralTimestamp;
import net.time4j.Moment;
import net.time4j.PlainTime;
import net.time4j.Weekday;
import net.time4j.Weekmodel;
import net.time4j.base.MathUtils;
import net.time4j.base.TimeSource;
import net.time4j.calendar.service.GenericDatePatterns;
import net.time4j.calendar.service.StdEnumDateElement;
import net.time4j.calendar.service.StdIntegerDateElement;
import net.time4j.calendar.service.StdWeekdayElement;
import net.time4j.engine.AttributeQuery;
import net.time4j.engine.CalendarDays;
import net.time4j.engine.CalendarFamily;
import net.time4j.engine.CalendarVariant;
import net.time4j.engine.ChronoElement;
import net.time4j.engine.ChronoEntity;
import net.time4j.engine.ChronoException;
import net.time4j.engine.ChronoMerger;
import net.time4j.engine.ChronoUnit;
import net.time4j.engine.DisplayStyle;
import net.time4j.engine.ElementRule;
import net.time4j.engine.FormattableElement;
import net.time4j.engine.StartOfDay;
import net.time4j.engine.ValidationElement;
import net.time4j.engine.VariantSource;
import net.time4j.format.Attributes;
import net.time4j.format.CalendarType;
import net.time4j.format.Leniency;
import net.time4j.format.LocalizedPatternSupport;
import net.time4j.tz.TZID;
import net.time4j.tz.Timezone;

import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.time.chrono.Chronology;
import java.time.chrono.HijrahDate;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQueries;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * <p>Represents the Hijri calendar used in many islamic countries. </p>
 *
 * <p>It is a lunar calendar which exists in several variants and is mainly for religious purposes.
 * The variant used in Saudi-Arabia is named &quot;islamic-umalqura&quot; and is based on data partially
 * observed by sighting the new moon, partially by astronomical calculations/predictions. Note that the
 * religious authorities in most countries often publish dates which deviate from such official calendars
 * by one or two days. </p>
 *
 * <p>The calendar year is divided into 12 islamic months. Every month usually has either 29 or 30 days. The length
 * of the month in days shall reflect the date when the new moon appears. However, for every variant there
 * are different data or rules how to determine if a month has 29 or 30 days. The Hijri calendar day starts
 * in the evening. New variants can be configured by a file named &quot;{variant-name}.data&quot; in the
 * data-subdirectory of resource class path (where hyphens are replaced by underscores). Format details see
 * the file &quot;islamic_umalqura.data&quot;. </p>
 *
 * <p>Following elements which are declared as constants are registered by
 * this class: </p>
 *
 * <ul>
 *  <li>{@link #DAY_OF_WEEK}</li>
 *  <li>{@link #DAY_OF_MONTH}</li>
 *  <li>{@link #DAY_OF_YEAR}</li>
 *  <li>{@link #MONTH_OF_YEAR}</li>
 *  <li>{@link #YEAR_OF_ERA}</li>
 *  <li>{@link #ERA}</li>
 * </ul>
 *
 * <p>Furthermore, all elements defined in {@code EpochDays} and {@link CommonElements} are supported. </p>
 *
 * <p>Examples of usage: </p>
 *
 * <pre>
 *     // parse a Hijri-string and convert to a gregorian date
 *     ChronoFormatter&lt;HijriCalendar&gt; formatter =
 *       ChronoFormatter.setUp(HijriCalendar.class, Locale.ENGLISH)
 *       .addPattern(&quot;EEE, d. MMMM yy&quot;, PatternType.NON_ISO_DATE).build()
 *       .withCalendarVariant(HijriCalendar.VARIANT_UMALQURA)
 *       .with(Attributes.PIVOT_YEAR, 1500); // mapped to range 1400-1499
 *     HijriCalendar hijri = formatter.parse(&quot;Thu, 29. Ramadan 36&quot;);
 *     PlainDate date = hijri.transform(PlainDate.class);
 *     System.out.println(date); // 2015-07-16
 *
 *     // determine actual Hijri date (two methods)
 *     HijriCalendar today = // conversion valid at noon (not in the evening when next islamic day starts)
 *       SystemClock.inLocalView().today().transform(HijriCalendar.class, HijriCalendar.VARIANT_UMALQURA);
 *     HijriCalendar todayExact = // taking into account the specific start of day for Hijri calendar
 *       SystemClock.inLocalView().now(
 *         HijriCalendar.family(),
 *         HijriCalendar.VARIANT_UMALQURA,
 *         StartOfDay.EVENING // simple approximation =&gt; 18:00
 *       ).toDate();
 * </pre>
 *
 * <p>Note that the supported range of this class is limited compared with the gregorian counter-example. Users
 * can apply following code to determine the exact variant-dependent range: </p>
 *
 * <pre>
 *     CalendarSystem<HijriCalendar> calsys =
 *       HijriCalendar.family().getCalendarSystem(HijriCalendar.VARIANT_UMALQURA);
 *     long min = calsys.getMinimumSinceUTC(); // -32556
 *     long max = calsys.getMaximumSinceUTC(); // 38671
 *
 *     // same minimum and maximum displayed as Hijri calendar dates
 *     HijriCalendar minHijri = calsys.transform(min); // AH-1300-01-01[islamic-umalqura]
 *     HijriCalendar maxHijri = calsys.transform(max); // AH-1500-12-30[islamic-umalqura]
 *
 *     // same minimum and maximum displayed as gregorian dates
 *     PlainDate minGregorian = PlainDate.of(min, EpochDays.UTC); // 1882-11-12
 *     PlainDate maxGregorian = PlainDate.of(max, EpochDays.UTC); // 2077-11-16
 * </pre>
 *
 * @author  <NAME>
 * @since   3.5/4.3
 * @doctags.concurrency {immutable}
 */
/*[deutsch]
 * <p>Repr&auml;sentiert den Hijri-Kalender, der in vielen islamischen L&auml;ndern vorwiegend f&uuml;r
 * religi&ouml;se Zwecke benutzt wird. </p>
 *
 * <p>Es handelt sich um einen lunaren Kalender, der in verschiedenen Varianten existiert. Die Variante
 * in Saudi-Arabien hei&szlig;t &quot;islamic-umalqura&quot; und basiert teilweise auf Daten gewonnen
 * durch die Sichtung des Neumonds, teilweise auf astronomischen Berechnungen und Voraussagen. Zu beachten:
 * Die religi&ouml;sen Autorit&auml;ten in den meisten L&auml;ndern folgen nicht streng den offiziellen
 * Kalendervarianten, sondern ver&ouml;ffentlichen oft ein Datum, das 1 oder 2 Tage abweichen kann. </p>
 *
 * <p>Das Kalendarjahr wird in 12 islamische Monate geteilt. Jeder Monat hat gew&ouml;hnlich entweder 29 oder
 * 30 Tage. Die L&auml;nge des Monats in Tagen soll den Zeitpunkt reflektieren, wann der Neumond gesichtet wird.
 * Aber jede Variante kennt verschiedenen Daten oder Regeln, um zu bestimmen, ob ein Monat 29 oder 30 Tage hat.
 * Der islamische Kalendertag startet am Abend. Neue Varianten k&ouml;nnen mit Hilfe einer Datei konfiguriert
 * werden, die den Namen &quot;{variant-name}.data&quot; hat und im data-Unterordner des Ressourcen-Klassenpfads
 * liegt (wobei Bindestriche durch Unterstriche ersetzt werden). Formatdetails siehe die vorhandene Datei
 * &quot;islamic_umalqura.data&quot;. </p>
 *
 * <p>Registriert sind folgende als Konstanten deklarierte Elemente: </p>
 *
 * <ul>
 *  <li>{@link #DAY_OF_WEEK}</li>
 *  <li>{@link #DAY_OF_MONTH}</li>
 *  <li>{@link #DAY_OF_YEAR}</li>
 *  <li>{@link #MONTH_OF_YEAR}</li>
 *  <li>{@link #YEAR_OF_ERA}</li>
 *  <li>{@link #ERA}</li>
 * </ul>
 *
 * <p>Au&slig;erdem werden alle Elemente von {@code EpochDays} und {@link CommonElements} unterst&uuml;tzt. </p>
 *
 * <p>Anwendungsbeispiele: </p>
 *
 * <pre>
 *     // Hijri-Text interpretieren und in ein gregorianisches Datum umwandeln
 *     ChronoFormatter&lt;HijriCalendar&gt; formatter =
 *       ChronoFormatter.setUp(HijriCalendar.class, Locale.ENGLISH)
 *       .addPattern(&quot;EEE, d. MMMM yy&quot;, PatternType.NON_ISO_DATE).build()
 *       .withCalendarVariant(HijriCalendar.VARIANT_UMALQURA)
 *       .with(Attributes.PIVOT_YEAR, 1500); // abgebildet auf den Bereich 1400-1499
 *     HijriCalendar hijri = formatter.parse(&quot;Thu, 29. Ramadan 36&quot;);
 *     PlainDate date = hijri.transform(PlainDate.class);
 *     System.out.println(date); // 2015-07-16
 *
 *     // aktuelles Hijri-Datum bestimmen (zwei Methoden)
 *     HijriCalendar today = // Konversion mittags g&uuml;ltig (nicht abends, wenn der n&auml;chste Tag beginnt)
 *       SystemClock.inLocalView().today().transform(HijriCalendar.class, HijriCalendar.VARIANT_UMALQURA);
 *     HijriCalendar todayExact = // ber&uuml;cksichtigt den spezifischen Start des islamischen Tags
 *       SystemClock.inLocalView().now(
 *         HijriCalendar.family(),
 *         HijriCalendar.VARIANT_UMALQURA,
 *         StartOfDay.EVENING // einfache N&auml;herung =&gt; 18:00
 *       ).toDate();
 * </pre>
 *
 * <p>Hinweis: Der unterst&uuml;tze variantenabh&auml;ngige Wertbereich dieser Klasse ist verglichen mit
 * dem gregorianischen Standardfall begrenzt. Anwender k&ouml;nnen folgenden Code nutzen, um den genauen
 * Wertbereich zu bestimmen: </p>
 *
 * <pre>
 *     CalendarSystem<HijriCalendar> calsys =
 *       HijriCalendar.family().getCalendarSystem(HijriCalendar.VARIANT_UMALQURA);
 *     long min = calsys.getMinimumSinceUTC(); // -32556
 *     long max = calsys.getMaximumSinceUTC(); // 38671
 *
 *     // gleiches Minimum und Maximum als islamisches Kalendardatum
 *     HijriCalendar minHijri = calsys.transform(min); // AH-1300-01-01[islamic-umalqura]
 *     HijriCalendar maxHijri = calsys.transform(max); // AH-1500-12-30[islamic-umalqura]
 *
 *     // gleiches Minimum und Maximum als gregorianisches Kalenderdatum
 *     PlainDate minGregorian = PlainDate.of(min, EpochDays.UTC); // 1882-11-12
 *     PlainDate maxGregorian = PlainDate.of(max, EpochDays.UTC); // 2077-11-16
 * </pre>
 *
 * @author  <NAME>
{'fraction_non_alphanumeric': 0.13183082915971062, 'fraction_numerical': 0.01858653311074012, 'mean_word_length': 3.8063653383257554, 'pattern_counts': {'":': 0, '<': 135, '<?xml version=': 0, '>': 135, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5010613', 'n_tokens_mistral': 6186, 'n_tokens_neox': 5985, 'n_words': 1612}