1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Diagnostics.CodeAnalysis; 6 7 namespace System.Globalization 8 { 9 /*=================================JapaneseCalendar========================== 10 ** 11 ** JapaneseCalendar is based on Gregorian calendar. The month and day values are the same as 12 ** Gregorian calendar. However, the year value is an offset to the Gregorian 13 ** year based on the era. 14 ** 15 ** This system is adopted by Emperor Meiji in 1868. The year value is counted based on the reign of an emperor, 16 ** and the era begins on the day an emperor ascends the throne and continues until his death. 17 ** The era changes at 12:00AM. 18 ** 19 ** For example, the current era is Heisei. It started on 1989/1/8 A.D. Therefore, Gregorian year 1989 is also Heisei 1st. 20 ** 1989/1/8 A.D. is also Heisei 1st 1/8. 21 ** 22 ** Any date in the year during which era is changed can be reckoned in either era. For example, 23 ** 1989/1/1 can be 1/1 Heisei 1st year or 1/1 Showa 64th year. 24 ** 25 ** Note: 26 ** The DateTime can be represented by the JapaneseCalendar are limited to two factors: 27 ** 1. The min value and max value of DateTime class. 28 ** 2. The available era information. 29 ** 30 ** Calendar support range: 31 ** Calendar Minimum Maximum 32 ** ========== ========== ========== 33 ** Gregorian 1868/09/08 9999/12/31 34 ** Japanese Meiji 01/01 Heisei 8011/12/31 35 ============================================================================*/ 36 37 38 public partial class JapaneseCalendar : Calendar 39 { 40 internal static readonly DateTime calendarMinValue = new DateTime(1868, 9, 8); 41 42 43 public override DateTime MinSupportedDateTime 44 { 45 get 46 { 47 return (calendarMinValue); 48 } 49 } 50 51 public override DateTime MaxSupportedDateTime 52 { 53 get 54 { 55 return (DateTime.MaxValue); 56 } 57 } 58 59 public override CalendarAlgorithmType AlgorithmType 60 { 61 get 62 { 63 return CalendarAlgorithmType.SolarCalendar; 64 } 65 } 66 67 // 68 // Using a field initializer rather than a static constructor so that the whole class can be lazy 69 // init. 70 internal static volatile EraInfo[] japaneseEraInfo; 71 72 // 73 // Read our era info 74 // 75 // m_EraInfo must be listed in reverse chronological order. The most recent era 76 // should be the first element. 77 // That is, m_EraInfo[0] contains the most recent era. 78 // 79 // We know about 4 built-in eras, however users may add additional era(s) from the 80 // registry, by adding values to HKLM\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras 81 // we don't read the registry and instead we call WinRT to get the needed informatio 82 // 83 // Registry values look like: 84 // yyyy.mm.dd=era_abbrev_english_englishabbrev 85 // 86 // Where yyyy.mm.dd is the registry value name, and also the date of the era start. 87 // yyyy, mm, and dd are the year, month & day the era begins (4, 2 & 2 digits long) 88 // era is the Japanese Era name 89 // abbrev is the Abbreviated Japanese Era Name 90 // english is the English name for the Era (unused) 91 // englishabbrev is the Abbreviated English name for the era. 92 // . is a delimiter, but the value of . doesn't matter. 93 // '_' marks the space between the japanese era name, japanese abbreviated era name 94 // english name, and abbreviated english names. 95 // GetEraInfo()96 internal static EraInfo[] GetEraInfo() 97 { 98 // See if we need to build it 99 if (japaneseEraInfo == null) 100 { 101 japaneseEraInfo = GetJapaneseEras(); 102 // See if we have to use the built-in eras 103 if (japaneseEraInfo == null) 104 { 105 // We know about some built-in ranges 106 EraInfo[] defaultEraRanges = new EraInfo[4]; 107 defaultEraRanges[0] = new EraInfo(4, 1989, 1, 8, 1988, 1, GregorianCalendar.MaxYear - 1988, 108 "\x5e73\x6210", "\x5e73", "H"); // era #4 start year/month/day, yearOffset, minEraYear 109 defaultEraRanges[1] = new EraInfo(3, 1926, 12, 25, 1925, 1, 1989 - 1925, 110 "\x662d\x548c", "\x662d", "S"); // era #3,start year/month/day, yearOffset, minEraYear 111 defaultEraRanges[2] = new EraInfo(2, 1912, 7, 30, 1911, 1, 1926 - 1911, 112 "\x5927\x6b63", "\x5927", "T"); // era #2,start year/month/day, yearOffset, minEraYear 113 defaultEraRanges[3] = new EraInfo(1, 1868, 1, 1, 1867, 1, 1912 - 1867, 114 "\x660e\x6cbb", "\x660e", "M"); // era #1,start year/month/day, yearOffset, minEraYear 115 116 // Remember the ranges we built 117 japaneseEraInfo = defaultEraRanges; 118 } 119 } 120 121 // return the era we found/made 122 return japaneseEraInfo; 123 } 124 125 internal static volatile Calendar s_defaultInstance; 126 internal GregorianCalendarHelper helper; 127 128 /*=================================GetDefaultInstance========================== 129 **Action: Internal method to provide a default intance of JapaneseCalendar. Used by NLS+ implementation 130 ** and other calendars. 131 **Returns: 132 **Arguments: 133 **Exceptions: 134 ============================================================================*/ 135 GetDefaultInstance()136 internal static Calendar GetDefaultInstance() 137 { 138 if (s_defaultInstance == null) 139 { 140 s_defaultInstance = new JapaneseCalendar(); 141 } 142 return (s_defaultInstance); 143 } 144 145 JapaneseCalendar()146 public JapaneseCalendar() 147 { 148 try 149 { 150 new CultureInfo("ja-JP"); 151 } 152 catch (ArgumentException e) 153 { 154 throw new TypeInitializationException(this.GetType().ToString(), e); 155 } 156 helper = new GregorianCalendarHelper(this, GetEraInfo()); 157 } 158 159 internal override CalendarId ID 160 { 161 get 162 { 163 return CalendarId.JAPAN; 164 } 165 } 166 167 AddMonths(DateTime time, int months)168 public override DateTime AddMonths(DateTime time, int months) 169 { 170 return (helper.AddMonths(time, months)); 171 } 172 173 AddYears(DateTime time, int years)174 public override DateTime AddYears(DateTime time, int years) 175 { 176 return (helper.AddYears(time, years)); 177 } 178 179 /*=================================GetDaysInMonth========================== 180 **Action: Returns the number of days in the month given by the year and month arguments. 181 **Returns: The number of days in the given month. 182 **Arguments: 183 ** year The year in Japanese calendar. 184 ** month The month 185 ** era The Japanese era value. 186 **Exceptions 187 ** ArgumentException If month is less than 1 or greater * than 12. 188 ============================================================================*/ 189 190 GetDaysInMonth(int year, int month, int era)191 public override int GetDaysInMonth(int year, int month, int era) 192 { 193 return (helper.GetDaysInMonth(year, month, era)); 194 } 195 196 GetDaysInYear(int year, int era)197 public override int GetDaysInYear(int year, int era) 198 { 199 return (helper.GetDaysInYear(year, era)); 200 } 201 202 GetDayOfMonth(DateTime time)203 public override int GetDayOfMonth(DateTime time) 204 { 205 return (helper.GetDayOfMonth(time)); 206 } 207 208 GetDayOfWeek(DateTime time)209 public override DayOfWeek GetDayOfWeek(DateTime time) 210 { 211 return (helper.GetDayOfWeek(time)); 212 } 213 214 GetDayOfYear(DateTime time)215 public override int GetDayOfYear(DateTime time) 216 { 217 return (helper.GetDayOfYear(time)); 218 } 219 220 GetMonthsInYear(int year, int era)221 public override int GetMonthsInYear(int year, int era) 222 { 223 return (helper.GetMonthsInYear(year, era)); 224 } 225 226 GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)227 public override int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek) 228 { 229 return (helper.GetWeekOfYear(time, rule, firstDayOfWeek)); 230 } 231 232 /*=================================GetEra========================== 233 **Action: Get the era value of the specified time. 234 **Returns: The era value for the specified time. 235 **Arguments: 236 ** time the specified date time. 237 **Exceptions: ArgumentOutOfRangeException if time is out of the valid era ranges. 238 ============================================================================*/ 239 240 GetEra(DateTime time)241 public override int GetEra(DateTime time) 242 { 243 return (helper.GetEra(time)); 244 } 245 246 GetMonth(DateTime time)247 public override int GetMonth(DateTime time) 248 { 249 return (helper.GetMonth(time)); 250 } 251 252 GetYear(DateTime time)253 public override int GetYear(DateTime time) 254 { 255 return (helper.GetYear(time)); 256 } 257 258 IsLeapDay(int year, int month, int day, int era)259 public override bool IsLeapDay(int year, int month, int day, int era) 260 { 261 return (helper.IsLeapDay(year, month, day, era)); 262 } 263 264 IsLeapYear(int year, int era)265 public override bool IsLeapYear(int year, int era) 266 { 267 return (helper.IsLeapYear(year, era)); 268 } 269 270 // Returns the leap month in a calendar year of the specified era. This method returns 0 271 // if this calendar does not have leap month, or this year is not a leap year. 272 // 273 GetLeapMonth(int year, int era)274 public override int GetLeapMonth(int year, int era) 275 { 276 return (helper.GetLeapMonth(year, era)); 277 } 278 279 IsLeapMonth(int year, int month, int era)280 public override bool IsLeapMonth(int year, int month, int era) 281 { 282 return (helper.IsLeapMonth(year, month, era)); 283 } 284 285 ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)286 public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) 287 { 288 return (helper.ToDateTime(year, month, day, hour, minute, second, millisecond, era)); 289 } 290 291 // For Japanese calendar, four digit year is not used. Few emperors will live for more than one hundred years. 292 // Therefore, for any two digit number, we just return the original number. 293 ToFourDigitYear(int year)294 public override int ToFourDigitYear(int year) 295 { 296 if (year <= 0) 297 { 298 throw new ArgumentOutOfRangeException(nameof(year), 299 SR.ArgumentOutOfRange_NeedPosNum); 300 } 301 302 if (year > helper.MaxYear) 303 { 304 throw new ArgumentOutOfRangeException( 305 nameof(year), 306 String.Format( 307 CultureInfo.CurrentCulture, 308 SR.ArgumentOutOfRange_Range, 309 1, 310 helper.MaxYear)); 311 } 312 return (year); 313 } 314 315 316 public override int[] Eras 317 { 318 get 319 { 320 return (helper.Eras); 321 } 322 } 323 324 // 325 // Return the various era strings 326 // Note: The arrays are backwards of the eras 327 // EraNames()328 internal static String[] EraNames() 329 { 330 EraInfo[] eras = GetEraInfo(); 331 String[] eraNames = new String[eras.Length]; 332 333 for (int i = 0; i < eras.Length; i++) 334 { 335 // Strings are in chronological order, eras are backwards order. 336 eraNames[i] = eras[eras.Length - i - 1].eraName; 337 } 338 339 return eraNames; 340 } 341 AbbrevEraNames()342 internal static String[] AbbrevEraNames() 343 { 344 EraInfo[] eras = GetEraInfo(); 345 String[] erasAbbrev = new String[eras.Length]; 346 347 for (int i = 0; i < eras.Length; i++) 348 { 349 // Strings are in chronological order, eras are backwards order. 350 erasAbbrev[i] = eras[eras.Length - i - 1].abbrevEraName; 351 } 352 353 return erasAbbrev; 354 } 355 EnglishEraNames()356 internal static String[] EnglishEraNames() 357 { 358 EraInfo[] eras = GetEraInfo(); 359 String[] erasEnglish = new String[eras.Length]; 360 361 for (int i = 0; i < eras.Length; i++) 362 { 363 // Strings are in chronological order, eras are backwards order. 364 erasEnglish[i] = eras[eras.Length - i - 1].englishEraName; 365 } 366 367 return erasEnglish; 368 } 369 370 private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 99; 371 IsValidYear(int year, int era)372 internal override bool IsValidYear(int year, int era) 373 { 374 return helper.IsValidYear(year, era); 375 } 376 377 public override int TwoDigitYearMax 378 { 379 get 380 { 381 if (twoDigitYearMax == -1) 382 { 383 twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DEFAULT_TWO_DIGIT_YEAR_MAX); 384 } 385 return (twoDigitYearMax); 386 } 387 388 set 389 { 390 VerifyWritable(); 391 if (value < 99 || value > helper.MaxYear) 392 { 393 throw new ArgumentOutOfRangeException( 394 "year", 395 String.Format( 396 CultureInfo.CurrentCulture, 397 SR.ArgumentOutOfRange_Range, 398 99, 399 helper.MaxYear)); 400 } 401 twoDigitYearMax = value; 402 } 403 } 404 } 405 } 406