Merge pull request #726 from pruiz/xamarin-bug-13708
[mono.git] / mcs / class / corlib / System.Globalization / JapaneseCalendar.cs
1 // System.Globalization.JapaneseCalendar.cs
2 //
3 // (C) Ulrich Kunitz 2002
4 //
5
6 //
7 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 namespace System.Globalization {
30
31 using System;
32 using System.Runtime.InteropServices;
33
34 /// <summary>
35 /// This is the Japanese calendar. It differs from the Gregorian calendar
36 /// only in the years.
37 /// </summary>
38 /// <remarks>
39 /// <para>The Japanese calendar support four eras.</para>
40 /// <list type="table">
41 /// <listheader>
42 /// <term>era number</term>
43 /// <term>Gregorian start date</term>
44 /// <term>Gregorian end date</term>
45 /// </listheader>
46 /// <item>
47 /// <term>1</term>
48 /// <term>September 8, 1868</term>
49 /// <term>July 29, 1912</term>
50 /// </item>
51 /// <item>
52 /// <term>2</term>
53 /// <term>July 30, 1912</term>
54 /// <term>December 24, 1926</term>
55 /// </item>
56 /// <item>
57 /// <term>3</term>
58 /// <term>December 25, 1926</term>
59 /// <term>January 7, 1989</term>
60 /// </item>
61 /// <item>
62 /// <term>4</term>
63 /// <term>January 8, 1989</term>
64 /// <term>present</term>
65 /// </item>
66 /// </list>
67 /// <para>The implementation uses the
68 /// <see cref="N:CalendricalCalculations"/> namespace.
69 /// </para>
70 /// </remarks>
71 [Serializable]
72 [ComVisible (true)]
73 [MonoLimitation ("Serialization format not compatible with .NET")]
74 public class JapaneseCalendar : Calendar {
75         /// <summary>
76         /// Static protected field storing the
77         /// <see cref="T:CalendricalCalculations.GregorianEraHandler"/>.
78         /// </summary>
79         internal static readonly CCGregorianEraHandler M_EraHandler;
80
81         /// <summary>
82         /// Static constructor, who creates and initializes
83         /// <see cref="F:M_EraHandler"/>.
84         /// </summary>
85         static JapaneseCalendar() {
86                 M_EraHandler = new CCGregorianEraHandler();
87                 M_EraHandler.appendEra(1,
88                         CCGregorianCalendar.fixed_from_dmy(8, 9, 1868),
89                         CCGregorianCalendar.fixed_from_dmy(29, 7, 1912));
90                 M_EraHandler.appendEra(2,
91                         CCGregorianCalendar.fixed_from_dmy(30, 7, 1912),
92                         CCGregorianCalendar.fixed_from_dmy(24, 12, 1926));
93                 M_EraHandler.appendEra(3,
94                         CCGregorianCalendar.fixed_from_dmy(25, 12, 1926),
95                         CCGregorianCalendar.fixed_from_dmy(7, 1, 1989));
96                 M_EraHandler.appendEra(4,
97                         CCGregorianCalendar.fixed_from_dmy(8, 1, 1989));
98         }
99
100         /// <summary>
101         /// Default constructor.
102         /// </summary>
103         public JapaneseCalendar() {
104                 M_AbbrEraNames = new string[] { "M", "T", "S", "H" };
105                 M_EraNames = new string[] { "Meiji", "Taisho", "Showa",
106                         "Heisei" };
107         }
108                 
109
110         /// <value>Overridden. Gives the eras supported by the
111         /// calendar as an array of integers.
112         /// </value>
113         public override int[] Eras {
114                 get {
115                         return (int[])M_EraHandler.Eras.Clone();
116                 }
117         }
118
119         public override int TwoDigitYearMax 
120         {
121                 get {
122                         return twoDigitYearMax;
123                 }
124                 set {
125                         CheckReadOnly ();
126                         M_ArgumentInRange ("value", value, 100, M_MaxYear);
127
128                         twoDigitYearMax = value;
129                 }
130         }
131         
132         /// <summary>
133         /// A protected member checking a
134         /// <see cref="T:System.DateTime"/> value.
135         /// </summary>
136         /// <param name="time">The
137         /// <see cref="T:System.DateTime"/>
138         /// to check.
139         /// </param>
140         /// <exception cref="T:System.ArgumentOutOfRangeException">
141         /// The exception is thrown if the
142         /// <see cref="T:System.DateTime"/> parameter is outside all
143         /// supported eras.
144         /// </exception>
145         internal void M_CheckDateTime(DateTime time) {
146                 M_EraHandler.CheckDateTime(time);
147         }
148
149         /// <summary>
150         /// A protected method checking the era number.
151         /// </summary>
152         /// <param name="era">The era number as reference. It is set
153         /// to <see cref="F:CurrentEra"/>, if the input value is 0.</param>
154         /// <exception name="T:System.ArgumentException">
155         /// The exception is thrown if the era is not supported by the class.
156         /// </exception>
157         internal void M_CheckEra(ref int era) {
158                 if (era == CurrentEra)
159                         era = 4;
160                 if (!M_EraHandler.ValidEra(era))
161                         throw new ArgumentException("Era value was not valid.");
162         }
163
164         /// <summary>
165         /// A protected method checking calendar year and the era number.
166         /// </summary>
167         /// <param name="year">An integer representing the calendar year.
168         /// </param>
169         /// <param name="era">The era number as reference.</param>
170         /// <exception name="T:System.ArgumentException">
171         /// The exception is thrown if the era is not supported by the class.
172         /// </exception>
173         /// <exception cref="T:System.ArgumentOutOfRangeException">
174         /// The exception is thrown if the calendar year is outside of
175         /// the supported range.
176         /// </exception>
177         internal int M_CheckYEG(int year, ref int era) {
178                 M_CheckEra(ref era);
179                 return M_EraHandler.GregorianYear(year, era);
180         }
181
182         /// <summary>
183         /// Checks whether the year is the era is valid, if era = CurrentEra
184         /// the right value is set.
185         /// </summary>
186         /// <param name="year">The year to check.</param>
187         /// <param name="era">The era to check.</Param>
188         /// <exception cref="T:ArgumentOutOfRangeException">
189         /// The exception will be thrown, if the year is not valid.
190         /// </exception>
191         internal override void M_CheckYE(int year, ref int era) {
192                 M_CheckYEG(year, ref era);
193         }
194
195         /// <summary>
196         /// A protected method checking the calendar year, month, and
197         /// era number.
198         /// </summary>
199         /// <param name="year">An integer representing the calendar year.
200         /// </param>
201         /// <param name="month">An integer giving the calendar month.
202         /// </param>
203         /// <param name="era">The era number as reference.</param>
204         /// <exception name="T:System.ArgumentException">
205         /// The exception is thrown if the era is not supported by the class.
206         /// </exception>
207         /// <exception cref="T:System.ArgumentOutOfRangeException">
208         /// The exception is thrown if the calendar year or month is
209         /// outside of the supported range.
210         /// </exception>
211         internal int M_CheckYMEG(int year, int month, ref int era) {
212                 int gregorianYear = M_CheckYEG(year, ref era);
213                 if (month < 1 || month > 12)
214                         throw new ArgumentOutOfRangeException("month",
215                                 "Month must be between one and twelve.");
216                 return gregorianYear;
217         }
218
219         /// <summary>
220         /// A protected method checking the calendar day, month, and year
221         /// and the era number.
222         /// </summary>
223         /// <param name="year">An integer representing the calendar year.
224         /// </param>
225         /// <param name="month">An integer giving the calendar month.
226         /// </param>
227         /// <param name="day">An integer giving the calendar day.
228         /// </param>
229         /// <param name="era">The era number as reference.</param>
230         /// <exception name="T:System.ArgumentException">
231         /// The exception is thrown if the era is not supported by the class.
232         /// </exception>
233         /// <exception cref="T:System.ArgumentOutOfRangeException">
234         /// The exception is thrown if the calendar year, month, or day is
235         /// outside of the supported range.
236         /// </exception>
237         internal int M_CheckYMDEG(int year, int month, int day, ref int era)
238         {
239                 int gregorianYear = M_CheckYMEG(year, month, ref era);
240                 M_ArgumentInRange("day", day, 1, GetDaysInMonth(year, month, era));
241                 return gregorianYear;
242         }
243         
244         /// <summary>
245         /// Overrideden. Adds months to a given date.
246         /// </summary>
247         /// <param name="time">The
248         /// <see cref="T:System.DateTime"/> to which to add
249         /// months.
250         /// </param>
251         /// <param name="months">The number of months to add.</param>
252         /// <returns>A new <see cref="T:System.DateTime"/> value, that
253         /// results from adding <paramref name="months"/> to the specified
254         /// DateTime.</returns>
255         /// <exception cref="T:System.ArgumentOutOfRangeException">
256         /// The exception is thrown if
257         /// <see cref="T:System.DateTime"/> return value is outside all
258         /// supported eras.
259         /// </exception>
260         public override DateTime AddMonths(DateTime time, int months) {
261                 DateTime t = CCGregorianCalendar.AddMonths(time, months);
262                 M_CheckDateTime(t);
263                 return t;
264         }
265
266         /// <summary>
267         /// Overridden. Adds years to a given date.
268         /// </summary>
269         /// <param name="time">The
270         /// <see cref="T:System.DateTime"/> to which to add
271         /// years.
272         /// </param>
273         /// <param name="years">The number of years to add.</param>
274         /// <returns>A new <see cref="T:System.DateTime"/> value, that
275         /// results from adding <paramref name="years"/> to the specified
276         /// DateTime.</returns>
277         /// <exception cref="T:System.ArgumentOutOfRangeException">
278         /// The exception is thrown if
279         /// <see cref="T:System.DateTime"/> return value is outside all
280         /// supported eras.
281         /// </exception>
282         public override DateTime AddYears(DateTime time, int years) {
283                 DateTime t = CCGregorianCalendar.AddYears(time, years);
284                 M_CheckDateTime(t);
285                 return t;
286         }
287                 
288         /// <summary>
289         /// Overriden. Gets the day of the month from
290         /// <paramref name="time"/>.
291         /// </summary>
292         /// <param name="time">The
293         /// <see cref="T:System.DateTime"/> that specifies a
294         /// date.
295         /// </param>
296         /// <returns>An integer giving the day of months, starting with 1.
297         /// </returns>
298         /// <exception cref="T:System.ArgumentOutOfRangeException">
299         /// The exception is thrown if the
300         /// <see cref="T:System.DateTime"/> parameter is outside all
301         /// supported eras.
302         /// </exception>
303         public override int GetDayOfMonth(DateTime time) {
304                 M_CheckDateTime(time);
305                 return CCGregorianCalendar.GetDayOfMonth(time);
306         }
307
308         /// <summary>
309         /// Overriden. Gets the day of the week from the specified date.
310         /// </summary>
311         /// <param name="time">The
312         /// <see cref="T:System.DateTime"/> that specifies a
313         /// date.
314         /// </param>
315         /// <returns>An integer giving the day of months, starting with 1.
316         /// </returns>
317         /// <exception cref="T:System.ArgumentOutOfRangeException">
318         /// The exception is thrown if the
319         /// <see cref="T:System.DateTime"/> parameter is outside all
320         /// supported eras.
321         /// </exception>
322         public override DayOfWeek GetDayOfWeek(DateTime time) {
323                 M_CheckDateTime(time);
324                 int rd = CCFixed.FromDateTime(time);
325                 return (DayOfWeek)CCFixed.day_of_week(rd);
326         }
327
328         /// <summary>
329         /// Overridden. Gives the number of the day in the year.
330         /// </summary>
331         /// <param name="time">The
332         /// <see cref="T:System.DateTime"/> that specifies a
333         /// date.
334         /// </param>
335         /// <returns>An integer representing the day of the year,
336         /// starting with 1.</returns>
337         /// <exception cref="T:System.ArgumentOutOfRangeException">
338         /// The exception is thrown if the
339         /// <see cref="T:System.DateTime"/> parameter is outside all
340         /// supported eras.
341         /// </exception>
342         public override int GetDayOfYear(DateTime time) {
343                 M_CheckDateTime(time);
344                 return CCGregorianCalendar.GetDayOfYear(time);
345         }
346
347         /// <summary>
348         /// Overridden. Gives the number of days in the specified month
349         /// of the given year and era.
350         /// </summary>
351         /// <param name="year">An integer that gives the year.
352         /// </param>
353         /// <param name="month">An integer that gives the month, starting
354         /// with 1.</param>
355         /// <param name="era">An integer that gives the era of the specified
356         /// year.</param>
357         /// <returns>An integer that gives the number of days of the
358         /// specified month.</returns>
359         /// <exception cref="T:System.ArgumentOutOfRangeException">
360         /// The exception is thrown, if <paramref name="month"/>,
361         /// <paramref name="year"/> ,or <paramref name="era"/> is outside
362         /// the allowed range.
363         /// </exception>
364         public override int GetDaysInMonth(int year, int month, int era) {
365                 int gregorianYear = M_CheckYMEG(year, month, ref era);
366                 return CCGregorianCalendar.GetDaysInMonth(gregorianYear, month);
367         }
368
369         /// <summary>
370         /// Overridden. Gives the number of days of the specified
371         /// year of the given era. 
372         /// </summary>
373         /// <param name="year">An integer that specifies the year. 
374         /// </param>
375         /// <param name="era">An ineger that specifies the era.
376         /// </param>
377         /// <returns>An integer that gives the number of days of the
378         /// specified year.</returns>
379         /// <exception cref="T:System.ArgumentOutOfRangeExceiption">
380         /// The exception is thrown, if
381         /// <paramref name="year"/> or <paramref name="era"/> are outside the
382         /// allowed range.
383         /// </exception>
384         public override int GetDaysInYear(int year, int era) {
385                 int gregorianYear = M_CheckYEG(year, ref era);
386                 return CCGregorianCalendar.GetDaysInYear(gregorianYear);
387         }
388                 
389
390         /// <summary>
391         /// Overridden. Gives the era of the specified date.
392         /// </summary>
393         /// <param name="time">The
394         /// <see cref="T:System.DateTime"/> that specifies a
395         /// date.
396         /// </param>
397         /// <returns>An integer representing the era of the calendar.
398         /// </returns>
399         /// <exception cref="T:System.ArgumentOutOfRangeException">
400         /// The exception is thrown if the
401         /// <see cref="T:System.DateTime"/> parameter is outside all
402         /// supported eras.
403         /// </exception>
404         public override int GetEra(DateTime time) {
405                 // M_CheckDateTime not needed, because EraYear does the
406                 // right thing.
407                 int rd = CCFixed.FromDateTime(time);
408                 int era;
409                 M_EraHandler.EraYear(out era, rd);
410                 return era;
411         }
412
413         [ComVisible (false)]
414         public override int GetLeapMonth (int year, int era)
415         {
416                 return 0;
417         }
418
419         /// <summary>
420         /// Overridden. Gives the number of the month of the specified
421         /// date.
422         /// </summary>
423         /// <param name="time">The
424         /// <see cref="T:System.DateTime"/> that specifies a
425         /// date.
426         /// </param>
427         /// <returns>An integer representing the month, 
428         /// starting with 1.</returns>
429         /// <exception cref="T:System.ArgumentOutOfRangeException">
430         /// The exception is thrown if the
431         /// <see cref="T:System.DateTime"/> parameter is outside all
432         /// supported eras.
433         /// </exception>
434         public override int GetMonth(DateTime time) {
435                 M_CheckDateTime(time);
436                 return CCGregorianCalendar.GetMonth(time);
437         }
438
439         /// <summary>
440         /// Overridden. Gives the number of months in the specified year 
441         /// and era.
442         /// </summary>
443         /// <param name="year">An integer that specifies the year.
444         /// </param>
445         /// <param name="era">An integer that specifies the era.
446         /// </param>
447         /// <returns>An integer that gives the number of the months in the
448         /// specified year.</returns>
449         /// <exception cref="T:System.ArgumentOutOfRangeException">
450         /// The exception is thrown, if the year or the era are not valid.
451         /// </exception>
452         public override int GetMonthsInYear(int year, int era) {
453                 M_CheckYE(year, ref era);
454                 return 12;
455         }
456
457         [ComVisible (false)]
458         public override int GetWeekOfYear (DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
459         {
460                 return base.GetWeekOfYear (time, rule, firstDayOfWeek);
461         }
462
463         /// <summary>
464         /// Overridden. Gives the number of the year of the specified
465         /// date.
466         /// </summary>
467         /// <param name="time">The
468         /// <see cref="T:System.DateTime"/> that specifies a
469         /// date.
470         /// </param>
471         /// <returns>An integer representing the year, 
472         /// starting with 1.</returns>
473         /// <exception cref="T:System.ArgumentOutOfRangeException">
474         /// The exception is thrown if the
475         /// <see cref="T:System.DateTime"/> parameter is outside all
476         /// supported eras.
477         /// </exception>
478         public override int GetYear(DateTime time) {
479                 // M_CheckDateTime not needed, because EraYeat does the
480                 // right thing.
481                 int rd = CCFixed.FromDateTime(time);
482                 int era;
483                 return M_EraHandler.EraYear(out era, rd);
484         }
485
486         /// <summary>
487         /// Overridden. Tells whether the given day 
488         /// is a leap day.
489         /// </summary>
490         /// <param name="year">An integer that specifies the year in the
491         /// given era.
492         /// </param>
493         /// <param name="month">An integer that specifies the month.
494         /// </param>
495         /// <param name="day">An integer that specifies the day.
496         /// </param>
497         /// <param name="era">An integer that specifies the era.
498         /// </param>
499         /// <returns>A boolean that tells whether the given day is a leap
500         /// day.
501         /// </returns>
502         /// <exception cref="T:System.ArgumentOutOfRangeException">
503         /// The exception is thrown, if the year, month, day, or era is not
504         /// valid.
505         /// </exception>
506         public override bool IsLeapDay(int year, int month, int day, int era)
507         {
508                 int gregorianYear = M_CheckYMDEG(year, month, day, ref era);
509                 return CCGregorianCalendar.IsLeapDay(gregorianYear, month, day);
510         }
511
512         /// <summary>
513         /// Overridden. Tells whether the given month 
514         /// is a leap month.
515         /// </summary>
516         /// <param name="year">An integer that specifies the year in the
517         /// given era.
518         /// </param>
519         /// <param name="month">An integer that specifies the month.
520         /// </param>
521         /// <param name="era">An integer that specifies the era.
522         /// </param>
523         /// <returns>A boolean that tells whether the given month is a leap
524         /// month.
525         /// </returns>
526         /// <exception cref="T:System.ArgumentOutOfRangeException">
527         /// The exception is thrown, if the year, month, or era is not
528         /// valid.
529         /// </exception>
530         public override bool IsLeapMonth(int year, int month, int era) {
531                 M_CheckYMEG(year, month, ref era);
532                 return false;
533         }
534
535         /// <summary>
536         /// Overridden. Tells whether the given year
537         /// is a leap year.
538         /// </summary>
539         /// <param name="year">An integer that specifies the year in the
540         /// given era.
541         /// </param>
542         /// <param name="era">An integer that specifies the era.
543         /// </param>
544         /// <returns>A boolean that tells whether the given year is a leap
545         /// year.
546         /// </returns>
547         /// <exception cref="T:System.ArgumentOutOfRangeException">
548         /// The exception is thrown, if the year or era is not
549         /// valid.
550         /// </exception>
551         public override bool IsLeapYear(int year, int era) {
552                 int gregorianYear = M_CheckYEG(year, ref era);
553                 return CCGregorianCalendar.is_leap_year(gregorianYear);
554         }
555
556         /// <summary>
557         /// Overridden. Creates the
558         /// <see cref="T:System.DateTime"/> from the parameters.
559         /// </summary>
560         /// <param name="year">An integer that gives the year in the
561         /// <paramref name="era"/>.
562         /// </param>
563         /// <param name="month">An integer that specifies the month.
564         /// </param>
565         /// <param name="day">An integer that specifies the day.
566         /// </param>
567         /// <param name="hour">An integer that specifies the hour.
568         /// </param>
569         /// <param name="minute">An integer that specifies the minute.
570         /// </param>
571         /// <param name="second">An integer that gives the second.
572         /// </param>
573         /// <param name="milliseconds">An integer that gives the
574         /// milliseconds.
575         /// </param>
576         /// <param name="era">An integer that specifies the era.
577         /// </param>
578         /// <returns>A
579         /// <see cref="T:system.DateTime"/> representig the date and time.
580         /// </returns>
581         /// <exception cref="T:System.ArgumentOutOfRangeException">
582         /// The exception is thrown, if at least one of the parameters
583         /// is out of range.
584         /// </exception>
585         public override DateTime ToDateTime(int year, int month, int day,
586                 int hour, int minute, int second, int millisecond,
587                 int era)
588         {
589                 int gregorianYear = M_CheckYMDEG(year, month, day, ref era);
590                 M_CheckHMSM(hour, minute, second, millisecond);
591                 return CCGregorianCalendar.ToDateTime(
592                         gregorianYear, month, day,
593                         hour, minute, second, millisecond);
594         }
595
596
597         /// <summary>
598         /// This functions returns simply the year for the Japanese calendar.
599         /// </summary>
600         /// <param name="year">An integer that gives the year.
601         /// </param>
602         /// <returns>The same argument as the year.
603         /// </returns>
604         /// <exception cref="T:System.ArgumentOutOfRangeException">
605         /// The exception is thrown if the year is negative or the resulting 
606         /// year is invalid.
607         /// </exception>
608         public override int ToFourDigitYear(int year) {
609                 if (year < 0)
610                         throw new ArgumentOutOfRangeException(
611                                 "year", "Non-negative number required.");
612                 int era = CurrentEra;
613                 M_CheckYE(year, ref era);
614                 return year;
615         }
616
617 #if !NET_2_1
618         [ComVisible (false)]
619         public override CalendarAlgorithmType AlgorithmType {
620                 get {
621                         return CalendarAlgorithmType.SolarCalendar;
622                 }
623         }
624 #endif
625
626         static DateTime JapanMin = new DateTime (1868, 9, 8, 0, 0, 0);
627         static DateTime JapanMax = new DateTime (9999, 12, 31, 11, 59, 59);
628                 
629         [ComVisible (false)]
630         public override DateTime MinSupportedDateTime {
631                 get {
632                         return JapanMin;
633                 }
634         }
635
636         [ComVisible (false)]
637         public override DateTime MaxSupportedDateTime {
638                 get {
639                         return JapanMax;
640                 }
641         }
642
643 } // class JapaneseCalendar
644         
645 } // namespace System.Globalization