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