Merge pull request #1388 from schani/fix-23401
[mono.git] / mcs / class / corlib / System.Globalization / JulianCalendar.cs
1 // System.Globalization.JulianCalendar.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 Julian calendar.
36 /// </summary>
37 /// <remarks>
38 /// <para>The Julian calendar supports only the Common Era from
39 /// January 1, 1 (Gregorian) to December 31, 9999 (Gregorian).
40 /// </para>
41 /// <para>The implementation uses the
42 /// <see cref="N:CalendricalCalculations"/> namespace.
43 /// </para>
44 /// </remarks>
45 [Serializable]
46 [ComVisible (true)]
47 [MonoLimitation ("Serialization format not compatible with .NET")]
48 public class JulianCalendar : Calendar {
49         /// <summary>
50         /// Default constructor.
51         /// </summary>
52         public JulianCalendar() {
53                 M_AbbrEraNames = new string[] {"C.E."};
54                 M_EraNames = new string[] {"Common Era"};
55                 if (twoDigitYearMax == 99)
56                         twoDigitYearMax = 2029;
57         }
58                 
59         /// <summary>
60         /// The era number for the Common Era (C.E.) or Anno Domini (A.D.)
61         /// respective.
62         /// </summary>
63         public static readonly int JulianEra = 1;
64
65         /// <value>Overridden. Gives the eras supported by the Julian
66         /// calendar as an array of integers.
67         /// </value>
68         public override int[] Eras {
69                 get {
70                         return new int[] { JulianEra }; 
71                 }
72         }
73
74         public override int TwoDigitYearMax 
75         {
76                 get {
77                         return twoDigitYearMax;
78                 }
79                 set {
80                         CheckReadOnly ();
81                         M_ArgumentInRange ("value", value, 100, M_MaxYear);
82
83                         twoDigitYearMax = value;
84                 }
85         }
86
87         /// <summary>
88         /// A protected method checking the era number.
89         /// </summary>
90         /// <param name="era">The era number.</param>
91         /// <exception name="T:System.ArgumentException">
92         /// The exception is thrown if the era is not equal
93         /// <see cref="M:JulianEra"/>.
94         /// </exception>
95         internal void M_CheckEra(ref int era) {
96                 if (era == CurrentEra)
97                         era = JulianEra;
98                 if (era != JulianEra)
99                         throw new ArgumentException("Era value was not valid.");
100         }
101
102         /// <summary>
103         /// A protected method checking calendar year and the era number.
104         /// </summary>
105         /// <param name="year">An integer representing the calendar year.
106         /// </param>
107         /// <param name="era">The era number.</param>
108         /// <exception cref="T:System.ArgumentException">
109         /// The exception is thrown if the era is not equal
110         /// <see cref="M:JulianEra"/>.
111         /// </exception>
112         /// <exception cref="T:System.ArgumentOutOfRangeException">
113         /// The exception is thrown if the calendar year is outside of
114         /// the allowed range.
115         /// </exception>
116         internal override void M_CheckYE(int year, ref int era) {
117                 M_CheckEra(ref era);
118                 M_ArgumentInRange("year", year, 1, 9999);
119         }
120
121         /// <summary>
122         /// A protected method checking the calendar year, month, and
123         /// era number.
124         /// </summary>
125         /// <param name="year">An integer representing the calendar year.
126         /// </param>
127         /// <param name="month">An integer giving the calendar month.
128         /// </param>
129         /// <param name="era">The era number.</param>
130         /// <exception cref="T:System.ArgumentException">
131         /// The exception is thrown if the era is not equal
132         /// <see cref="M:JulianEra"/>.
133         /// </exception>
134         /// <exception cref="T:System.ArgumentOutOfRangeException">
135         /// The exception is thrown if the calendar year or month is
136         /// outside of the allowed range.
137         /// </exception>
138         internal void M_CheckYME(int year, int month, ref int era) {
139                 M_CheckYE(year, ref era);
140                 if (month < 1 || month > 12)
141                         throw new ArgumentOutOfRangeException("month",
142                                 "Month must be between one and twelve.");
143         }
144
145         /// <summary>
146         /// A protected method checking the calendar day, month, and year
147         /// and the era number.
148         /// </summary>
149         /// <param name="year">An integer representing the calendar year.
150         /// </param>
151         /// <param name="month">An integer giving the calendar month.
152         /// </param>
153         /// <param name="day">An integer giving the calendar day.
154         /// </param>
155         /// <param name="era">The era number.</param>
156         /// <exception cref="T:System.ArgumentException">
157         /// The exception is thrown if the era is not equal
158         /// <see cref="M:JulianEra"/>.
159         /// </exception>
160         /// <exception cref="T:System.ArgumentOutOfRangeException">
161         /// The exception is thrown if the calendar year, month, or day is
162         /// outside of the allowed range.
163         /// </exception>
164         internal void M_CheckYMDE(int year, int month, int day, ref int era)
165         {
166                 M_CheckYME(year, month, ref era);
167                 M_ArgumentInRange("day", day, 1,
168                         GetDaysInMonth(year, month, era));
169                 if (year == 9999 && ((month == 10 && day > 19) || month > 10))
170                         throw new ArgumentOutOfRangeException(
171                                 "The maximum Julian date is 19. 10. 9999.");
172         }
173
174         /// <summary>
175         /// Overridden. Adds months to a given date.
176         /// </summary>
177         /// <param name="time">The
178         /// <see cref="T:System.DateTime"/> to which to add
179         /// months.
180         /// </param>
181         /// <param name="months">The number of months to add.</param>
182         /// <returns>A new <see cref="T:System.DateTime"/> value, that
183         /// results from adding <paramref name="months"/> to the specified
184         /// DateTime.</returns>
185         public override DateTime AddMonths(DateTime time, int months) {
186                 int rd = CCFixed.FromDateTime(time);
187                 int day, month, year;
188                 CCJulianCalendar.dmy_from_fixed(
189                         out day, out month, out year, rd);
190                 month += months;
191                 year += CCMath.div_mod(out month, month, 12);
192                 rd = CCJulianCalendar.fixed_from_dmy(day, month, year);
193                 DateTime t = CCFixed.ToDateTime(rd);
194                 return t.Add(time.TimeOfDay);
195         }
196
197         /// <summary>
198         /// Overridden. Adds years to a given date.
199         /// </summary>
200         /// <param name="time">The
201         /// <see cref="T:System.DateTime"/> to which to add
202         /// years.
203         /// </param>
204         /// <param name="years">The number of years to add.</param>
205         /// <returns>A new <see cref="T:System.DateTime"/> value, that
206         /// results from adding <paramref name="years"/> to the specified
207         /// DateTime.</returns>
208         public override DateTime AddYears(DateTime time, int years) {
209                 int rd = CCFixed.FromDateTime(time);
210                 int day, month, year;
211                 CCJulianCalendar.dmy_from_fixed(
212                         out day, out month, out year, rd);
213                 year += years;
214                 rd = CCJulianCalendar.fixed_from_dmy(day, month, year);
215                 DateTime t = CCFixed.ToDateTime(rd);
216                 return t.Add(time.TimeOfDay);
217         }
218                 
219         /// <summary>
220         /// Overridden. Gets the day of the month from
221         /// <paramref name="time"/>.
222         /// </summary>
223         /// <param name="time">The
224         /// <see cref="T:System.DateTime"/> that specifies a
225         /// date.
226         /// </param>
227         /// <returns>An integer giving the day of months, starting with 1.
228         /// </returns>
229         public override int GetDayOfMonth(DateTime time) {
230                 int rd = CCFixed.FromDateTime(time);
231                 return CCJulianCalendar.day_from_fixed(rd);
232         }
233
234         /// <summary>
235         /// Overridden. Gets the day of the week from the specified date.
236         /// </summary>
237         /// <param name="time">The
238         /// <see cref="T:System.DateTime"/> that specifies a
239         /// date.
240         /// </param>
241         /// <returns>An integer giving the day of months, starting with 1.
242         /// </returns>
243         public override DayOfWeek GetDayOfWeek(DateTime time) {
244                 int rd = CCFixed.FromDateTime(time);
245                 return (DayOfWeek)CCFixed.day_of_week(rd);
246         }
247
248         /// <summary>
249         /// Overridden. Gives the number of the day in the year.
250         /// </summary>
251         /// <param name="time">The
252         /// <see cref="T:System.DateTime"/> that specifies a
253         /// date.
254         /// </param>
255         /// <returns>An integer representing the day of the year,
256         /// starting with 1.</returns>
257         public override int GetDayOfYear(DateTime time) {
258                 int rd = CCFixed.FromDateTime(time);
259                 int year = CCJulianCalendar.year_from_fixed(rd);
260                 int rd1_1 = CCJulianCalendar.fixed_from_dmy(1, 1, year);
261                 return rd - rd1_1 + 1;
262         }
263
264         /// <summary>
265         /// Overridden. Gives the number of days in the specified month
266         /// of the given year and era.
267         /// </summary>
268         /// <param name="year">An integer that gives the year.
269         /// </param>
270         /// <param name="month">An integer that gives the month, starting
271         /// with 1.</param>
272         /// <param name="era">An intger that gives the era of the specified
273         /// year.</param>
274         /// <returns>An integer that gives the number of days of the
275         /// specified month.</returns>
276         /// <exception cref="T:System.ArgumentOutOfRangeException">
277         /// The exception is thrown, if <paramref name="month"/>,
278         /// <paramref name="year"/> ,or <paramref name="era"/> is outside
279         /// the allowed range.
280         /// </exception>
281         public override int GetDaysInMonth(int year, int month, int era) {
282                 M_CheckYME(year, month, ref era);
283                 int rd1 = CCJulianCalendar.fixed_from_dmy(1, month, year);
284                 int rd2 = CCJulianCalendar.fixed_from_dmy(1, month+1, year);
285                 return rd2 - rd1;
286         }
287
288         /// <summary>
289         /// Overridden. Gives the number of days of the specified
290         /// year of the given era. 
291         /// </summary>
292         /// <param name="year">An integer that specifies the year. 
293         /// </param>
294         /// <param name="era">An ineger that specifies the era.
295         /// </param>
296         /// <returns>An integer that gives the number of days of the
297         /// specified year.</returns>
298         /// <exception cref="T:System.ArgumentOutOfRangeExceiption">
299         /// The exception is thrown, if
300         /// <paramref name="year"/> is outside the allowed range.
301         /// </exception>
302         public override int GetDaysInYear(int year, int era) {
303                 M_CheckYE(year, ref era);
304                 int rd1 = CCJulianCalendar.fixed_from_dmy(1, 1, year);
305                 int rd2 = CCJulianCalendar.fixed_from_dmy(1, 1, year+1);
306                 return rd2 - rd1;
307         }
308                 
309
310         /// <summary>
311         /// Overridden. Gives the era of the specified date.
312         /// </summary>
313         /// <param name="time">The
314         /// <see cref="T:System.DateTime"/> that specifies a
315         /// date.
316         /// </param>
317         /// <returns>An integer representing the era of the calendar.
318         /// </returns>
319         public override int GetEra(DateTime time) {
320                 // should change, if more than one era is supported
321                 return JulianEra;
322         }
323
324         [ComVisible (false)]
325         public override int GetLeapMonth (int year, int era)
326         {
327                 return 0;
328         }
329
330         /// <summary>
331         /// Overridden. Gives the number of the month of the specified
332         /// date.
333         /// </summary>
334         /// <param name="time">The
335         /// <see cref="T:System.DateTime"/> that specifies a
336         /// date.
337         /// </param>
338         /// <returns>An integer representing the month, 
339         /// starting with 1.</returns>
340         public override int GetMonth(DateTime time) {
341                 int rd = CCFixed.FromDateTime(time);
342                 return CCJulianCalendar.month_from_fixed(rd);
343         }
344
345         /// <summary>
346         /// Overridden. Gives the number of months in the specified year 
347         /// and era.
348         /// </summary>
349         /// <param name="year">An integer that specifies the year.
350         /// </param>
351         /// <param name="era">An integer that specifies the era.
352         /// </param>
353         /// <returns>An integer that gives the number of the months in the
354         /// specified year.</returns>
355         /// <exception cref="T:System.ArgumentOutOfRangeException">
356         /// The exception is thrown, if the year or the era are not valid.
357         /// </exception>
358         public override int GetMonthsInYear(int year, int era) {
359                 M_CheckYE(year, ref era);
360                 return 12;
361         }
362
363         /// <summary>
364         /// Overridden. Gives the number of the year of the specified
365         /// date.
366         /// </summary>
367         /// <param name="time">The
368         /// <see cref="T:System.DateTime"/> that specifies a
369         /// date.
370         /// </param>
371         /// <returns>An integer representing the year, 
372         /// starting with 1.</returns>
373         public override int GetYear(DateTime time) {
374                 int rd = CCFixed.FromDateTime(time);
375                 return CCJulianCalendar.year_from_fixed(rd);
376         }
377
378         /// <summary>
379         /// Overridden. Tells whether the given day 
380         /// is a leap day.
381         /// </summary>
382         /// <param name="year">An integer that specifies the year in the
383         /// given era.
384         /// </param>
385         /// <param name="month">An integer that specifies the month.
386         /// </param>
387         /// <param name="day">An integer that specifies the day.
388         /// </param>
389         /// <param name="era">An integer that specifies the era.
390         /// </param>
391         /// <returns>A boolean that tells whether the given day is a leap
392         /// day.
393         /// </returns>
394         /// <exception cref="T:System.ArgumentOutOfRangeException">
395         /// The exception is thrown, if the year, month, day, or era is not
396         /// valid.
397         /// </exception>
398         public override bool IsLeapDay(int year, int month, int day, int era)
399         {
400                 M_CheckYMDE(year, month, day, ref era);
401                 return IsLeapYear(year) && month == 2 && day == 29;
402         }
403
404         /// <summary>
405         /// Overridden. Tells whether the given month 
406         /// is a leap month.
407         /// </summary>
408         /// <param name="year">An integer that specifies the year in the
409         /// given era.
410         /// </param>
411         /// <param name="month">An integer that specifies the month.
412         /// </param>
413         /// <param name="era">An integer that specifies the era.
414         /// </param>
415         /// <returns>A boolean that tells whether the given month is a leap
416         /// month.
417         /// </returns>
418         /// <exception cref="T:System.ArgumentOutOfRangeException">
419         /// The exception is thrown, if the year, month, or era is not
420         /// valid.
421         /// </exception>
422         public override bool IsLeapMonth(int year, int month, int era) {
423                 M_CheckYME(year, month, ref era);
424                 return false;
425         }
426
427         /// <summary>
428         /// Overridden. Tells whether the given year
429         /// is a leap year.
430         /// </summary>
431         /// <param name="year">An integer that specifies the year in the
432         /// given era.
433         /// </param>
434         /// <param name="era">An integer that specifies the era.
435         /// </param>
436         /// <returns>A boolean that tells whether the given year is a leap
437         /// year.
438         /// </returns>
439         /// <exception cref="T:System.ArgumentOutOfRangeException">
440         /// The exception is thrown, if the year or era is not
441         /// valid.
442         /// </exception>
443         public override bool IsLeapYear(int year, int era) {
444                 M_CheckYE(year, ref era);
445                 return CCJulianCalendar.is_leap_year(year);
446         }
447
448         /// <summary>
449         /// Overridden. Creates the
450         /// <see cref="T:System.DateTime"/> from the parameters.
451         /// </summary>
452         /// <param name="year">An integer that gives the year in the
453         /// <paramref name="era"/>.
454         /// </param>
455         /// <param name="month">An integer that specifies the month.
456         /// </param>
457         /// <param name="day">An integer that specifies the day.
458         /// </param>
459         /// <param name="hour">An integer that specifies the hour.
460         /// </param>
461         /// <param name="minute">An integer that specifies the minute.
462         /// </param>
463         /// <param name="second">An integer that gives the second.
464         /// </param>
465         /// <param name="milliseconds">An integer that gives the
466         /// milliseconds.
467         /// </param>
468         /// <param name="era">An integer that specifies the era.
469         /// </param>
470         /// <returns>
471         /// <see cref="T:system.DateTime"/> representig the date and time.
472         /// </returns>
473         /// <exception cref="T:System.ArgumentOutOfRangeException">
474         /// The exception is thrown, if at least one of the parameters
475         /// is out of range.
476         /// </exception>
477         public override DateTime ToDateTime(int year, int month, int day,
478                 int hour, int minute, int second, int millisecond,
479                 int era)
480         {
481                 M_CheckYMDE(year, month, day, ref era);
482                 M_CheckHMSM(hour, minute, second, millisecond);
483                 int rd = CCJulianCalendar.fixed_from_dmy(day, month, year);
484                 return CCFixed.ToDateTime(rd,
485                         hour, minute, second, millisecond);
486         }
487
488         public override int ToFourDigitYear(int year)
489         {
490                 return base.ToFourDigitYear (year);
491         }
492
493         [ComVisible (false)]
494         public override CalendarAlgorithmType AlgorithmType {
495                 get {
496                         return CalendarAlgorithmType.SolarCalendar;
497                 }
498         }
499
500         static DateTime JulianMin = new DateTime (1, 1, 1, 0, 0, 0);
501         static DateTime JulianMax = new DateTime (9999, 12, 31, 11, 59, 59);
502                 
503         [ComVisible (false)]
504         public override DateTime MinSupportedDateTime {
505                 get {
506                         return JulianMin;
507                 }
508         }
509
510         [ComVisible (false)]
511         public override DateTime MaxSupportedDateTime {
512                 get {
513                         return JulianMax;
514                 }
515         }
516         
517 } // class JulianCalendar
518         
519 } // namespace System.Globalization