/// <summary>
        /// Constructs a <see cref="FiscalYear"/> from year number.
        /// </summary>
        /// <param name="year">The year.</param>
        /// <returns>
        /// The <see cref="FiscalYear"/>.
        /// </returns>
        public static FiscalYear ToFiscal(
            this int year)
        {
            var result = new FiscalYear(year);

            return(result);
        }
        private static FiscalYear Plus(
            this FiscalYear unitOfTime,
            int unitsToAdd)
        {
            var genericYear = unitOfTime.ToGenericYear().Plus(unitsToAdd);
            var result      = new FiscalYear(genericYear.Year);

            return(result);
        }
        public override ReportingPeriod <CalendarDay> GetReportingPeriodForFiscalYear(
            FiscalYear fiscalYear)
        {
            if (fiscalYear == null)
            {
                throw new ArgumentNullException(nameof(fiscalYear));
            }

            var firstDayInYear = this.GetAccountingYearEndDate(fiscalYear.Year - 1).AddDays(1).ToCalendarDay();
            var lastDayInYear  = this.GetAccountingYearEndDate(fiscalYear.Year).ToCalendarDay();
            var result         = new ReportingPeriod <CalendarDay>(firstDayInYear, lastDayInYear);

            return(result);
        }
        /// <inheritdoc />
        /// <exception cref="ArgumentNullException"><paramref name="fiscalYear"/> is null.</exception>
        public override ReportingPeriod <CalendarDay> GetReportingPeriodForFiscalYear(
            FiscalYear fiscalYear)
        {
            if (fiscalYear == null)
            {
                throw new ArgumentNullException(nameof(fiscalYear));
            }

            var januaryFirst        = new CalendarDay(fiscalYear.Year, MonthOfYear.January, DayOfMonth.One);
            var decemberThirtyFirst = new CalendarDay(fiscalYear.Year, MonthOfYear.December, DayOfMonth.ThirtyOne);
            var result = new ReportingPeriod <CalendarDay>(januaryFirst, decemberThirtyFirst);

            return(result);
        }
        /// <inheritdoc />
        /// <exception cref="ArgumentNullException"><paramref name="fiscalYear"/> is null.</exception>
        public override ReportingPeriod <CalendarDay> GetReportingPeriodForFiscalYear(
            FiscalYear fiscalYear)
        {
            if (fiscalYear == null)
            {
                throw new ArgumentNullException(nameof(fiscalYear));
            }

            var lastDayInEndingMonth = DateTime.DaysInMonth(fiscalYear.Year, (int)this.LastMonthInFiscalYear);
            var lastDayInFiscalYear  = new DateTime(fiscalYear.Year, (int)this.LastMonthInFiscalYear, lastDayInEndingMonth);
            var firstDayInFiscalYear = lastDayInFiscalYear.AddDays(1).AddYears(-1);
            var result = new ReportingPeriod <CalendarDay>(firstDayInFiscalYear.ToCalendarDay(), lastDayInFiscalYear.ToCalendarDay());

            return(result);
        }
 /// <summary>
 /// Gets the reporting period, in calendar days, for the specified fiscal year.
 /// </summary>
 /// <param name="fiscalYear">The fiscal year.</param>
 /// <returns>
 /// Returns the reporting period, in calendar days, for the specified fiscal year.
 /// </returns>
 /// <exception cref="ArgumentNullException"><paramref name="fiscalYear"/> is null.</exception>
 public abstract ReportingPeriod GetReportingPeriodForFiscalYear(
     FiscalYear fiscalYear);
Exemple #7
0
        public static UnitOfTime DeserializeFromSortableString(
            this string unitOfTime,
            Type type)
        {
            if (!type.IsUnitOfTimeType())
            {
                throw new NotSupportedException(Invariant($"Unsupported type {type?.FullName ?? "<NULL TYPE>"}, expected an implmenter {nameof(UnitOfTime)}"));
            }

            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            if (unitOfTime == null)
            {
                throw new ArgumentNullException(nameof(unitOfTime));
            }

            if (string.IsNullOrWhiteSpace(unitOfTime))
            {
                throw new ArgumentException(Invariant($"'{nameof(unitOfTime)}' is white space"));
            }

            var serializationFormatMatch = SerializationFormatByType.Select(_ => new { Match = _.Regex.Match(unitOfTime), SerializationFormat = _ }).SingleOrDefault(_ => _.Match.Success);

            if (serializationFormatMatch == null)
            {
                throw new InvalidOperationException("Cannot deserialize string; it is not valid unit-of-time.");
            }

            var serializedType = serializationFormatMatch.SerializationFormat.Type;

            if (!type.IsAssignableFrom(serializedType))
            {
                throw new InvalidOperationException(Invariant($"The unit-of-time appears to be a {serializedType.Name} which cannot be casted to a {type.Name}."));
            }

            string errorMessage = Invariant($"Cannot deserialize string;  it appears to be a {serializedType.Name} but it is malformed.");
            var    tokens       = serializationFormatMatch.SerializationFormat.Regex.GetGroupNames().Skip(1).Select(_ => serializationFormatMatch.Match.Groups[_].Value).ToArray();

            if (serializedType == typeof(CalendarDay))
            {
                var year  = ParseIntOrThrow(tokens[0], errorMessage);
                var month = ParseEnumOrThrow <MonthOfYear>(tokens[1], errorMessage);
                var day   = ParseEnumOrThrow <DayOfMonth>(tokens[2], errorMessage);

                try
                {
                    var result = new CalendarDay(year, month, day);

                    return(result);
                }
                catch (ArgumentException)
                {
                    throw new InvalidOperationException(errorMessage);
                }
            }

            if (serializedType == typeof(CalendarMonth))
            {
                var year  = ParseIntOrThrow(tokens[0], errorMessage);
                var month = ParseEnumOrThrow <MonthOfYear>(tokens[1], errorMessage);

                try
                {
                    var result = new CalendarMonth(year, month);

                    return(result);
                }
                catch (ArgumentException)
                {
                    throw new InvalidOperationException(errorMessage);
                }
            }

            if (serializedType == typeof(CalendarQuarter))
            {
                var year    = ParseIntOrThrow(tokens[0], errorMessage);
                var quarter = ParseEnumOrThrow <QuarterNumber>(tokens[1], errorMessage);

                try
                {
                    var result = new CalendarQuarter(year, quarter);

                    return(result);
                }
                catch (ArgumentException)
                {
                    throw new InvalidOperationException(errorMessage);
                }
            }

            if (serializedType == typeof(CalendarYear))
            {
                var year = ParseIntOrThrow(tokens[0], errorMessage);

                try
                {
                    var result = new CalendarYear(year);

                    return(result);
                }
                catch (ArgumentException)
                {
                    throw new InvalidOperationException(errorMessage);
                }
            }

            if (serializedType == typeof(CalendarUnbounded))
            {
                var result = new CalendarUnbounded();

                return(result);
            }

            if (serializedType == typeof(FiscalMonth))
            {
                var year  = ParseIntOrThrow(tokens[0], errorMessage);
                var month = ParseEnumOrThrow <MonthNumber>(tokens[1], errorMessage);

                try
                {
                    var result = new FiscalMonth(year, month);

                    return(result);
                }
                catch (ArgumentException)
                {
                    throw new InvalidOperationException(errorMessage);
                }
            }

            if (serializedType == typeof(FiscalQuarter))
            {
                var year    = ParseIntOrThrow(tokens[0], errorMessage);
                var quarter = ParseEnumOrThrow <QuarterNumber>(tokens[1], errorMessage);

                try
                {
                    var result = new FiscalQuarter(year, quarter);

                    return(result);
                }
                catch (ArgumentException)
                {
                    throw new InvalidOperationException(errorMessage);
                }
            }

            if (serializedType == typeof(FiscalYear))
            {
                var year = ParseIntOrThrow(tokens[0], errorMessage);

                try
                {
                    var result = new FiscalYear(year);

                    return(result);
                }
                catch (ArgumentException)
                {
                    throw new InvalidOperationException(errorMessage);
                }
            }

            if (serializedType == typeof(FiscalUnbounded))
            {
                var result = new FiscalUnbounded();

                return(result);
            }

            if (serializedType == typeof(GenericMonth))
            {
                var year  = ParseIntOrThrow(tokens[0], errorMessage);
                var month = ParseEnumOrThrow <MonthNumber>(tokens[1], errorMessage);

                try
                {
                    var result = new GenericMonth(year, month);

                    return(result);
                }
                catch (ArgumentException)
                {
                    throw new InvalidOperationException(errorMessage);
                }
            }

            if (serializedType == typeof(GenericQuarter))
            {
                var year    = ParseIntOrThrow(tokens[0], errorMessage);
                var quarter = ParseEnumOrThrow <QuarterNumber>(tokens[1], errorMessage);

                try
                {
                    var result = new GenericQuarter(year, quarter);

                    return(result);
                }
                catch (ArgumentException)
                {
                    throw new InvalidOperationException(errorMessage);
                }
            }

            if (serializedType == typeof(GenericYear))
            {
                var year = ParseIntOrThrow(tokens[0], errorMessage);

                try
                {
                    var result = new GenericYear(year);

                    return(result);
                }
                catch (ArgumentException)
                {
                    throw new InvalidOperationException(errorMessage);
                }
            }

            if (serializedType == typeof(GenericUnbounded))
            {
                var result = new GenericUnbounded();

                return(result);
            }

            throw new NotSupportedException("this type of unit-of-time is not supported: " + serializedType);
        }
Exemple #8
0
        private static IReportingPeriod <UnitOfTime> MakeLessGranular(
            this IReportingPeriod <UnitOfTime> reportingPeriod,
            UnitOfTimeGranularity granularity)
        {
            if (reportingPeriod == null)
            {
                throw new ArgumentNullException(nameof(reportingPeriod));
            }

            if (reportingPeriod.HasComponentWithUnboundedGranularity())
            {
                throw new ArgumentException(Invariant($"{nameof(reportingPeriod)} has an {nameof(UnitOfTimeGranularity.Unbounded)} component"));
            }

            if (granularity == UnitOfTimeGranularity.Invalid)
            {
                throw new ArgumentException(Invariant($"{nameof(granularity)} is {nameof(UnitOfTimeGranularity.Invalid)}"));
            }

            if (granularity == UnitOfTimeGranularity.Unbounded)
            {
                throw new ArgumentException(Invariant($"{nameof(granularity)} is {nameof(UnitOfTimeGranularity.Unbounded)}"));
            }

            var reportingPeriodGranularity = reportingPeriod.GetUnitOfTimeGranularity();

            if (reportingPeriodGranularity.IsAsGranularOrLessGranularThan(granularity))
            {
                throw new ArgumentException(Invariant($"{nameof(reportingPeriod)} is as granular or less granular than {nameof(granularity)}"));
            }

            IReportingPeriod <UnitOfTime> lessGranularReportingPeriod;
            var unitOfTimeKind = reportingPeriod.GetUnitOfTimeKind();

            if (reportingPeriodGranularity == UnitOfTimeGranularity.Day)
            {
                if (unitOfTimeKind == UnitOfTimeKind.Calendar)
                {
                    var startAsCalendarDay = reportingPeriod.Start as CalendarDay;

                    // ReSharper disable once PossibleNullReferenceException
                    var startMonth = new CalendarMonth(startAsCalendarDay.Year, startAsCalendarDay.MonthOfYear);
                    if (startMonth.GetFirstCalendarDay() != startAsCalendarDay)
                    {
                        throw new InvalidOperationException("Cannot convert a calendar day reporting period to a calendar month reporting period when the reporting period start time is not the first day of a month.");
                    }

                    var endAsCalendarDay = reportingPeriod.End as CalendarDay;

                    // ReSharper disable once PossibleNullReferenceException
                    var endMonth = new CalendarMonth(endAsCalendarDay.Year, endAsCalendarDay.MonthOfYear);
                    if (endMonth.GetLastCalendarDay() != endAsCalendarDay)
                    {
                        throw new InvalidOperationException("Cannot convert a calendar day reporting period to a calendar month reporting period when the reporting period end time is not the last day of a month.");
                    }

                    lessGranularReportingPeriod = new ReportingPeriod <CalendarMonth>(startMonth, endMonth);
                }
                else
                {
                    throw new NotSupportedException("This kind of unit-of-time is not supported: " + unitOfTimeKind);
                }
            }
            else if (reportingPeriodGranularity == UnitOfTimeGranularity.Month)
            {
                var startAsMonth = reportingPeriod.Start as IHaveAMonth;
                var endAsMonth   = reportingPeriod.End as IHaveAMonth;

                var quarterByStartMonth = new Dictionary <int, QuarterNumber>
                {
                    { 1, QuarterNumber.Q1 },
                    { 4, QuarterNumber.Q2 },
                    { 7, QuarterNumber.Q3 },
                    { 10, QuarterNumber.Q4 },
                };

                var quarterByEndMonth = new Dictionary <int, QuarterNumber>
                {
                    { 3, QuarterNumber.Q1 },
                    { 6, QuarterNumber.Q2 },
                    { 9, QuarterNumber.Q3 },
                    { 12, QuarterNumber.Q4 },
                };

                // ReSharper disable once PossibleNullReferenceException
                if (!quarterByStartMonth.ContainsKey((int)startAsMonth.MonthNumber))
                {
                    throw new InvalidOperationException("Cannot convert a monthly reporting period to a quarterly reporting period when the reporting period start time is not the first month of a recognized quarter.");
                }

                // ReSharper disable once PossibleNullReferenceException
                if (!quarterByEndMonth.ContainsKey((int)endAsMonth.MonthNumber))
                {
                    throw new InvalidOperationException("Cannot convert a monthly reporting period to a quarterly reporting period when the reporting period end time is not the last month of a recognized quarter.");
                }

                if (unitOfTimeKind == UnitOfTimeKind.Calendar)
                {
                    var startQuarter = new CalendarQuarter(startAsMonth.Year, quarterByStartMonth[(int)startAsMonth.MonthNumber]);
                    var endQuarter   = new CalendarQuarter(endAsMonth.Year, quarterByEndMonth[(int)endAsMonth.MonthNumber]);
                    lessGranularReportingPeriod = new ReportingPeriod <CalendarQuarter>(startQuarter, endQuarter);
                }
                else if (unitOfTimeKind == UnitOfTimeKind.Fiscal)
                {
                    var startQuarter = new FiscalQuarter(startAsMonth.Year, quarterByStartMonth[(int)startAsMonth.MonthNumber]);
                    var endQuarter   = new FiscalQuarter(endAsMonth.Year, quarterByEndMonth[(int)endAsMonth.MonthNumber]);
                    lessGranularReportingPeriod = new ReportingPeriod <FiscalQuarter>(startQuarter, endQuarter);
                }
                else if (unitOfTimeKind == UnitOfTimeKind.Generic)
                {
                    var startQuarter = new GenericQuarter(startAsMonth.Year, quarterByStartMonth[(int)startAsMonth.MonthNumber]);
                    var endQuarter   = new GenericQuarter(endAsMonth.Year, quarterByEndMonth[(int)endAsMonth.MonthNumber]);
                    lessGranularReportingPeriod = new ReportingPeriod <GenericQuarter>(startQuarter, endQuarter);
                }
                else
                {
                    throw new NotSupportedException("This kind of unit-of-time is not supported: " + unitOfTimeKind);
                }
            }
            else if (reportingPeriodGranularity == UnitOfTimeGranularity.Quarter)
            {
                var startAsQuarter = reportingPeriod.Start as IHaveAQuarter;
                var endAsQuarter   = reportingPeriod.End as IHaveAQuarter;

                // ReSharper disable once PossibleNullReferenceException
                if (startAsQuarter.QuarterNumber != QuarterNumber.Q1)
                {
                    throw new InvalidOperationException(
                              "Cannot convert a quarterly reporting period to a yearly reporting period when the reporting period start time is not Q1.");
                }

                // ReSharper disable once PossibleNullReferenceException
                if (endAsQuarter.QuarterNumber != QuarterNumber.Q4)
                {
                    throw new InvalidOperationException(
                              "Cannot convert a quarterly reporting period to a yearly reporting period when the reporting period end is not Q4.");
                }

                if (unitOfTimeKind == UnitOfTimeKind.Calendar)
                {
                    var startYear = new CalendarYear(startAsQuarter.Year);
                    var endYear   = new CalendarYear(endAsQuarter.Year);
                    lessGranularReportingPeriod = new ReportingPeriod <CalendarYear>(startYear, endYear);
                }
                else if (unitOfTimeKind == UnitOfTimeKind.Fiscal)
                {
                    var startYear = new FiscalYear(startAsQuarter.Year);
                    var endYear   = new FiscalYear(endAsQuarter.Year);
                    lessGranularReportingPeriod = new ReportingPeriod <FiscalYear>(startYear, endYear);
                }
                else if (unitOfTimeKind == UnitOfTimeKind.Generic)
                {
                    var startYear = new GenericYear(startAsQuarter.Year);
                    var endYear   = new GenericYear(endAsQuarter.Year);
                    lessGranularReportingPeriod = new ReportingPeriod <GenericYear>(startYear, endYear);
                }
                else
                {
                    throw new NotSupportedException("This kind of unit-of-time is not supported: " + unitOfTimeKind);
                }
            }
            else
            {
                throw new NotSupportedException("This granularity is not supported: " + reportingPeriodGranularity);
            }

            if (lessGranularReportingPeriod.GetUnitOfTimeGranularity() == granularity)
            {
                return(lessGranularReportingPeriod);
            }

            var result = MakeLessGranular(lessGranularReportingPeriod, granularity);

            return(result);
        }
Exemple #9
0
 /// <summary>
 /// Gets the reporting period, in calendar days, for the specified fiscal year.
 /// </summary>
 /// <param name="fiscalYear">The fiscal year.</param>
 /// <returns>
 /// Returns the reporting period, in calendar days, for the specified fiscal year.
 /// </returns>
 /// <exception cref="ArgumentNullException"><paramref name="fiscalYear"/> is null.</exception>
 public abstract ReportingPeriod <CalendarDay> GetReportingPeriodForFiscalYear(
     FiscalYear fiscalYear);
        private static ReportingPeriod MakeLessGranular(
            this ReportingPeriod reportingPeriod,
            UnitOfTimeGranularity granularity,
            bool throwOnMisalignment = true)
        {
            if (reportingPeriod == null)
            {
                throw new ArgumentNullException(nameof(reportingPeriod));
            }

            if (reportingPeriod.HasComponentWithUnboundedGranularity())
            {
                throw new ArgumentException(Invariant($"{nameof(reportingPeriod)} has an {nameof(UnitOfTimeGranularity.Unbounded)} component."));
            }

            if (granularity == UnitOfTimeGranularity.Invalid)
            {
                throw new ArgumentOutOfRangeException(Invariant($"'{nameof(granularity)}' == '{UnitOfTimeGranularity.Invalid}'"), (Exception)null);
            }

            if (granularity == UnitOfTimeGranularity.Unbounded)
            {
                throw new ArgumentOutOfRangeException(Invariant($"'{nameof(granularity)}' == '{UnitOfTimeGranularity.Unbounded}'"), (Exception)null);
            }

            var reportingPeriodGranularity = reportingPeriod.GetUnitOfTimeGranularity();

            if (reportingPeriodGranularity.IsAsGranularOrLessGranularThan(granularity))
            {
                throw new ArgumentException(Invariant($"{nameof(reportingPeriod)} is as granular or less granular than {nameof(granularity)}."));
            }

            ReportingPeriod lessGranularReportingPeriod;
            var             unitOfTimeKind = reportingPeriod.GetUnitOfTimeKind();

            if (reportingPeriodGranularity == UnitOfTimeGranularity.Day)
            {
                if (unitOfTimeKind == UnitOfTimeKind.Calendar)
                {
                    var startAsCalendarDay = reportingPeriod.Start as CalendarDay;

                    // ReSharper disable once PossibleNullReferenceException
                    var startMonth = new CalendarMonth(startAsCalendarDay.Year, startAsCalendarDay.MonthOfYear);
                    if ((startMonth.GetFirstCalendarDay() != startAsCalendarDay) && throwOnMisalignment)
                    {
                        throw new InvalidOperationException("Cannot convert a calendar day reporting period to a calendar month reporting period when the reporting period start time is not the first day of a month.");
                    }

                    var endAsCalendarDay = reportingPeriod.End as CalendarDay;

                    // ReSharper disable once PossibleNullReferenceException
                    var endMonth = new CalendarMonth(endAsCalendarDay.Year, endAsCalendarDay.MonthOfYear);
                    if ((endMonth.GetLastCalendarDay() != endAsCalendarDay) && throwOnMisalignment)
                    {
                        throw new InvalidOperationException("Cannot convert a calendar day reporting period to a calendar month reporting period when the reporting period end time is not the last day of a month.");
                    }

                    lessGranularReportingPeriod = new ReportingPeriod(startMonth, endMonth);
                }
                else
                {
                    throw new NotSupportedException("This kind of unit-of-time is not supported: " + unitOfTimeKind);
                }
            }
            else if (reportingPeriodGranularity == UnitOfTimeGranularity.Month)
            {
                var startAsMonth = reportingPeriod.Start as IHaveAMonth;
                var endAsMonth   = reportingPeriod.End as IHaveAMonth;

                var validStartMonths = new HashSet <int> {
                    1, 4, 7, 10
                };

                // ReSharper disable once PossibleNullReferenceException
                if ((!validStartMonths.Contains((int)startAsMonth.MonthNumber)) && throwOnMisalignment)
                {
                    throw new InvalidOperationException("Cannot convert a monthly reporting period to a quarterly reporting period when the reporting period start time is not the first month of a recognized quarter.");
                }

                var validEndMonths = new HashSet <int> {
                    3, 6, 9, 12
                };

                // ReSharper disable once PossibleNullReferenceException
                if ((!validEndMonths.Contains((int)endAsMonth.MonthNumber)) && throwOnMisalignment)
                {
                    throw new InvalidOperationException("Cannot convert a monthly reporting period to a quarterly reporting period when the reporting period end time is not the last month of a recognized quarter.");
                }

                var monthNumberToQuarterMap = new Dictionary <int, QuarterNumber>
                {
                    { 1, QuarterNumber.Q1 },
                    { 2, QuarterNumber.Q1 },
                    { 3, QuarterNumber.Q1 },
                    { 4, QuarterNumber.Q2 },
                    { 5, QuarterNumber.Q2 },
                    { 6, QuarterNumber.Q2 },
                    { 7, QuarterNumber.Q3 },
                    { 8, QuarterNumber.Q3 },
                    { 9, QuarterNumber.Q3 },
                    { 10, QuarterNumber.Q4 },
                    { 11, QuarterNumber.Q4 },
                    { 12, QuarterNumber.Q4 },
                };

                if (unitOfTimeKind == UnitOfTimeKind.Calendar)
                {
                    var startQuarter = new CalendarQuarter(startAsMonth.Year, monthNumberToQuarterMap[(int)startAsMonth.MonthNumber]);

                    var endQuarter = new CalendarQuarter(endAsMonth.Year, monthNumberToQuarterMap[(int)endAsMonth.MonthNumber]);

                    lessGranularReportingPeriod = new ReportingPeriod(startQuarter, endQuarter);
                }
                else if (unitOfTimeKind == UnitOfTimeKind.Fiscal)
                {
                    var startQuarter = new FiscalQuarter(startAsMonth.Year, monthNumberToQuarterMap[(int)startAsMonth.MonthNumber]);

                    var endQuarter = new FiscalQuarter(endAsMonth.Year, monthNumberToQuarterMap[(int)endAsMonth.MonthNumber]);

                    lessGranularReportingPeriod = new ReportingPeriod(startQuarter, endQuarter);
                }
                else if (unitOfTimeKind == UnitOfTimeKind.Generic)
                {
                    var startQuarter = new GenericQuarter(startAsMonth.Year, monthNumberToQuarterMap[(int)startAsMonth.MonthNumber]);

                    var endQuarter = new GenericQuarter(endAsMonth.Year, monthNumberToQuarterMap[(int)endAsMonth.MonthNumber]);

                    lessGranularReportingPeriod = new ReportingPeriod(startQuarter, endQuarter);
                }
                else
                {
                    throw new NotSupportedException("This kind of unit-of-time is not supported: " + unitOfTimeKind);
                }
            }
            else if (reportingPeriodGranularity == UnitOfTimeGranularity.Quarter)
            {
                var startAsQuarter = reportingPeriod.Start as IHaveAQuarter;
                var endAsQuarter   = reportingPeriod.End as IHaveAQuarter;

                // ReSharper disable once PossibleNullReferenceException
                if ((startAsQuarter.QuarterNumber != QuarterNumber.Q1) && throwOnMisalignment)
                {
                    throw new InvalidOperationException("Cannot convert a quarterly reporting period to a yearly reporting period when the reporting period start time is not Q1.");
                }

                // ReSharper disable once PossibleNullReferenceException
                if ((endAsQuarter.QuarterNumber != QuarterNumber.Q4) && throwOnMisalignment)
                {
                    throw new InvalidOperationException("Cannot convert a quarterly reporting period to a yearly reporting period when the reporting period end is not Q4.");
                }

                if (unitOfTimeKind == UnitOfTimeKind.Calendar)
                {
                    var startYear = new CalendarYear(startAsQuarter.Year);

                    var endYear = new CalendarYear(endAsQuarter.Year);

                    lessGranularReportingPeriod = new ReportingPeriod(startYear, endYear);
                }
                else if (unitOfTimeKind == UnitOfTimeKind.Fiscal)
                {
                    var startYear = new FiscalYear(startAsQuarter.Year);

                    var endYear = new FiscalYear(endAsQuarter.Year);

                    lessGranularReportingPeriod = new ReportingPeriod(startYear, endYear);
                }
                else if (unitOfTimeKind == UnitOfTimeKind.Generic)
                {
                    var startYear = new GenericYear(startAsQuarter.Year);

                    var endYear = new GenericYear(endAsQuarter.Year);

                    lessGranularReportingPeriod = new ReportingPeriod(startYear, endYear);
                }
                else
                {
                    throw new NotSupportedException("This kind of unit-of-time is not supported: " + unitOfTimeKind);
                }
            }
            else
            {
                throw new NotSupportedException("This granularity is not supported: " + reportingPeriodGranularity);
            }

            if (lessGranularReportingPeriod.GetUnitOfTimeGranularity() == granularity)
            {
                return(lessGranularReportingPeriod);
            }

            var result = MakeLessGranular(lessGranularReportingPeriod, granularity, throwOnMisalignment);

            return(result);
        }