001/* 002 * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos 003 * 004 * All rights reserved. 005 * 006 * Redistribution and use in source and binary forms, with or without 007 * modification, are permitted provided that the following conditions are met: 008 * 009 * * Redistributions of source code must retain the above copyright notice, 010 * this list of conditions and the following disclaimer. 011 * 012 * * Redistributions in binary form must reproduce the above copyright notice, 013 * this list of conditions and the following disclaimer in the documentation 014 * and/or other materials provided with the distribution. 015 * 016 * * Neither the name of JSR-310 nor the names of its contributors 017 * may be used to endorse or promote products derived from this software 018 * without specific prior written permission. 019 * 020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 021 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 022 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 023 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 024 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 026 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 027 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 028 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 029 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 030 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 031 */ 032 033package org.threeten.bp.calendar; 034 035import static org.threeten.bp.temporal.ChronoField.EPOCH_DAY; 036 037import java.io.Serializable; 038import java.util.Arrays; 039import java.util.HashMap; 040import java.util.List; 041import java.util.Locale; 042 043import org.threeten.bp.DateTimeException; 044import org.threeten.bp.temporal.Chrono; 045import org.threeten.bp.temporal.ChronoField; 046import org.threeten.bp.temporal.ChronoLocalDate; 047import org.threeten.bp.temporal.Era; 048import org.threeten.bp.temporal.TemporalAccessor; 049import org.threeten.bp.temporal.ValueRange; 050 051/** 052 * The Hijrah calendar system. 053 * <p> 054 * This chronology defines the rules of the Hijrah calendar system. 055 * <p> 056 * The implementation follows the Freeman-Grenville algorithm (*1) and has following features. 057 * <p><ul> 058 * <li>A year has 12 months.</li> 059 * <li>Over a cycle of 30 years there are 11 leap years.</li> 060 * <li>There are 30 days in month number 1, 3, 5, 7, 9, and 11, 061 * and 29 days in month number 2, 4, 6, 8, 10, and 12.</li> 062 * <li>In a leap year month 12 has 30 days.</li> 063 * <li>In a 30 year cycle, year 2, 5, 7, 10, 13, 16, 18, 21, 24, 064 * 26, and 29 are leap years.</li> 065 * <li>Total of 10631 days in a 30 years cycle.</li> 066 * </ul><p> 067 * <P> 068 * The table shows the features described above. 069 * <blockquote> 070 * <table border="1"> 071 * <tbody> 072 * <tr> 073 * <th># of month</th> 074 * <th>Name of month</th> 075 * <th>Number of days</th> 076 * </tr> 077 * <tr> 078 * <td>1</td> 079 * <td>Muharram</td> 080 * <td>30</td> 081 * </tr> 082 * <tr> 083 * <td>2</td> 084 * <td>Safar</td> 085 * <td>29</td> 086 * </tr> 087 * <tr> 088 * <td>3</td> 089 * <td>Rabi'al-Awwal</td> 090 * <td>30</td> 091 * </tr> 092 * <tr> 093 * <td>4</td> 094 * <td>Rabi'ath-Thani</td> 095 * <td>29</td> 096 * </tr> 097 * <tr> 098 * <td>5</td> 099 * <td>Jumada l-Ula</td> 100 * <td>30</td> 101 * </tr> 102 * <tr> 103 * <td>6</td> 104 * <td>Jumada t-Tania</td> 105 * <td>29</td> 106 * </tr> 107 * <tr> 108 * <td>7</td> 109 * <td>Rajab</td> 110 * <td>30</td> 111 * </tr> 112 * <tr> 113 * <td>8</td> 114 * <td>Sha`ban</td> 115 * <td>29</td> 116 * </tr> 117 * <tr> 118 * <td>9</td> 119 * <td>Ramadan</td> 120 * <td>30</td> 121 * </tr> 122 * <tr> 123 * <td>10</td> 124 * <td>Shawwal</td> 125 * <td>29</td> 126 * </tr> 127 * <tr> 128 * <td>11</td> 129 * <td>Dhu 'l-Qa`da</td> 130 * <td>30</td> 131 * </tr> 132 * <tr> 133 * <td>12</td> 134 * <td>Dhu 'l-Hijja</td> 135 * <td>29, but 30 days in years 2, 5, 7, 10,<br> 136 * 13, 16, 18, 21, 24, 26, and 29</td> 137 * </tr> 138 * </tbody> 139 * </table> 140 * </blockquote> 141 * <p> 142 * (*1) The algorithm is taken from the book, 143 * The Muslim and Christian Calendars by G.S.P. Freeman-Grenville. 144 * <p> 145 * 146 * <h3>Specification for implementors</h3> 147 * This class is immutable and thread-safe. 148 */ 149public final class HijrahChrono extends Chrono<HijrahChrono> implements Serializable { 150 151 /** 152 * Singleton instance of the Hijrah chronology. 153 */ 154 public static final HijrahChrono INSTANCE = new HijrahChrono(); 155 156 /** 157 * The singleton instance for the era before the current one - Before Hijrah - 158 * which has the value 0. 159 */ 160 public static final Era<HijrahChrono> ERA_BEFORE_AH = HijrahEra.BEFORE_AH; 161 /** 162 * The singleton instance for the current era - Hijrah - which has the value 1. 163 */ 164 public static final Era<HijrahChrono> ERA_AH = HijrahEra.AH; 165 /** 166 * Serialization version. 167 */ 168 private static final long serialVersionUID = 3127340209035924785L; 169 /** 170 * Narrow names for eras. 171 */ 172 private static final HashMap<String, String[]> ERA_NARROW_NAMES = new HashMap<>(); 173 /** 174 * Short names for eras. 175 */ 176 private static final HashMap<String, String[]> ERA_SHORT_NAMES = new HashMap<>(); 177 /** 178 * Full names for eras. 179 */ 180 private static final HashMap<String, String[]> ERA_FULL_NAMES = new HashMap<>(); 181 /** 182 * Fallback language for the era names. 183 */ 184 private static final String FALLBACK_LANGUAGE = "en"; 185 186 /** 187 * Language that has the era names. 188 */ 189 //private static final String TARGET_LANGUAGE = "ar"; 190 /** 191 * Name data. 192 */ 193 static { 194 ERA_NARROW_NAMES.put(FALLBACK_LANGUAGE, new String[]{"BH", "HE"}); 195 ERA_SHORT_NAMES.put(FALLBACK_LANGUAGE, new String[]{"B.H.", "H.E."}); 196 ERA_FULL_NAMES.put(FALLBACK_LANGUAGE, new String[]{"Before Hijrah", "Hijrah Era"}); 197 } 198 199 /** 200 * Restrictive constructor. 201 */ 202 private HijrahChrono() { 203 } 204 205 /** 206 * Resolve singleton. 207 * 208 * @return the singleton instance, not null 209 */ 210 private Object readResolve() { 211 return INSTANCE; 212 } 213 214 //----------------------------------------------------------------------- 215 /** 216 * Gets the ID of the chronology - 'Hijrah'. 217 * <p> 218 * The ID uniquely identifies the {@code Chrono}. 219 * It can be used to lookup the {@code Chrono} using {@link #of(String)}. 220 * 221 * @return the chronology ID - 'Hijrah' 222 * @see #getCalendarType() 223 */ 224 @Override 225 public String getId() { 226 return "Hijrah"; 227 } 228 229 /** 230 * Gets the calendar type of the underlying calendar system - 'islamicc'. 231 * <p> 232 * The calendar type is an identifier defined by the 233 * <em>Unicode Locale Data Markup Language (LDML)</em> specification. 234 * It can be used to lookup the {@code Chrono} using {@link #of(String)}. 235 * It can also be used as part of a locale, accessible via 236 * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. 237 * 238 * @return the calendar system type - 'islamicc' 239 * @see #getId() 240 */ 241 @Override 242 public String getCalendarType() { 243 return "islamicc"; 244 } 245 246 //----------------------------------------------------------------------- 247 @Override 248 public ChronoLocalDate<HijrahChrono> date(int prolepticYear, int month, int dayOfMonth) { 249 return HijrahDate.of(prolepticYear, month, dayOfMonth); 250 } 251 252 @Override 253 public ChronoLocalDate<HijrahChrono> dateYearDay(int prolepticYear, int dayOfYear) { 254 return HijrahDate.of(prolepticYear, 1, 1).plusDays(dayOfYear - 1); // TODO better 255 } 256 257 @Override 258 public ChronoLocalDate<HijrahChrono> date(TemporalAccessor temporal) { 259 if (temporal instanceof HijrahDate) { 260 return (HijrahDate) temporal; 261 } 262 return HijrahDate.ofEpochDay(temporal.getLong(EPOCH_DAY)); 263 } 264 265 //----------------------------------------------------------------------- 266 @Override 267 public boolean isLeapYear(long prolepticYear) { 268 return HijrahDate.isLeapYear(prolepticYear); 269 } 270 271 @Override 272 public int prolepticYear(Era<HijrahChrono> era, int yearOfEra) { 273 if (era instanceof HijrahEra == false) { 274 throw new DateTimeException("Era must be HijrahEra"); 275 } 276 return (era == HijrahEra.AH ? yearOfEra : 1 - yearOfEra); 277 } 278 279 @Override 280 public Era<HijrahChrono> eraOf(int eraValue) { 281 switch (eraValue) { 282 case 0: 283 return HijrahEra.BEFORE_AH; 284 case 1: 285 return HijrahEra.AH; 286 default: 287 throw new DateTimeException("invalid Hijrah era"); 288 } 289 } 290 291 @Override 292 public List<Era<HijrahChrono>> eras() { 293 return Arrays.<Era<HijrahChrono>>asList(HijrahEra.values()); 294 } 295 296 //----------------------------------------------------------------------- 297 @Override 298 public ValueRange range(ChronoField field) { 299 return field.range(); 300 } 301 302}