JapaneseCalendar.cs 14 KB

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