static UmAlQuraYearMonthDayCalculator()
{
// Try to initialize. If anything fails, YearLengths will still be null, so IsSupported will return false.
Calendar bclCalendar;
#if PCL
// Can't refer to the BCL calendar by name, but it *might* be available anyway. Let's try to instantiate
// it with reflection. If we can't, that's fair enough.
try
{
var type = typeof(Calendar).Assembly.GetType("System.Globalization.UmAlQuraCalendar");
if (type == null)
{
return;
}
bclCalendar = (Calendar) Activator.CreateInstance(type);
}
catch
{
// Don't really care what went wrong here. We'll assume it's not supported.
return;
}
#else
bclCalendar = new UmAlQuraCalendar();
#endif
DateTime minDateTime = bclCalendar.MinSupportedDateTime;
// Check if this looks like a sensible implementation, with a limited time range.
// (The .NET implementation only runs from 1900-2077, for example.)
// Mono is unfortunately broken - it advertises a large range, but then is inconsistent:
// Year 2 (for example) either has 354 or 355 days depending on how you ask.
if (minDateTime.Year < 1800 || minDateTime.Year > 3000)
{
YearLengths = null;
MonthLengths = null;
YearStartDays = null;
return;
}
// Work out the min and max supported years, ensuring that we support complete years.
ComputedMinYear = bclCalendar.GetYear(minDateTime);
if (bclCalendar.GetMonth(minDateTime) != 1 || bclCalendar.GetDayOfMonth(minDateTime) != 1)
{
ComputedMinYear++;
}
DateTime maxDateTime = bclCalendar.MaxSupportedDateTime;
ComputedMaxYear = bclCalendar.GetYear(maxDateTime);
if (bclCalendar.GetMonth(maxDateTime) != 12 || bclCalendar.GetDayOfMonth(maxDateTime) != bclCalendar.GetDaysInMonth(ComputedMaxYear, 12))
{
ComputedMaxYear--;
}
// For year lengths, we need to handle 1 year beyond the boundaries, too.
// We don't need MonthLengths to be quite as long, but it's simpler to be consistent.
YearLengths = new int[ComputedMaxYear - ComputedMinYear + 3];
YearStartDays = new int[ComputedMaxYear - ComputedMinYear + 3];
MonthLengths = new int[ComputedMaxYear - ComputedMinYear + 3];
int totalDays = 0;
for (int year = ComputedMinYear; year <= ComputedMaxYear; year++)
{
int yearIndex = year - ComputedMinYear + 1;
YearLengths[yearIndex] = bclCalendar.GetDaysInYear(year);
YearStartDays[yearIndex] = totalDays;
totalDays += YearLengths[yearIndex];
int monthBits = 0;
for (int month = 1; month <= 12; month++)
{
if (bclCalendar.GetDaysInMonth(year, month) == 30)
{
monthBits |= 1 << month;
}
}
MonthLengths[yearIndex] = monthBits;
}
// Fill in the cache with dummy data for before/after the min/max year, pretending
// that both of the "extra" years were 354 days long.
YearStartDays[0] = -354;
YearStartDays[YearStartDays.Length - 1] = totalDays;
YearLengths[0] = 354;
YearLengths[YearStartDays.Length - 1] = 354;
// Assume every 10 years before minDateTime has exactly 3544 days... it doesn't matter whether or not that's
// correct, but it gets roughly the right estimate. It doesn't matter that startOfMinYear isn't in UTC; we're only
// taking the Ticks property, which doesn't take account of the Kind.
DateTime startOfMinYear = bclCalendar.ToDateTime(ComputedMinYear, 1, 1, 0, 0, 0, 0);
ComputedDaysAtStartOfMinYear = (int) ((startOfMinYear.Ticks - NodaConstants.BclTicksAtUnixEpoch) / NodaConstants.TicksPerDay);
ComputedDaysAtStartOfYear1 = ComputedDaysAtStartOfMinYear + (int) (((1 - ComputedMinYear) / 10.0) * AverageDaysPer10Years);
}