< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 37
Coverable lines: 37
Total lines: 192
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 34
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
GetWeekOfYear(...)0%660%
GetWeekOfYear(...)100%110%
GetYear(...)0%660%
GetYear(...)100%110%
GetYearStart(...)100%110%
GetYearEnd(...)100%110%
GetWeeksInYear(...)0%880%
P(System.UInt32)100%110%
ToDateTime(...)0%12120%
ToDateOnly(...)100%110%
GetWeekNumber(...)100%110%
GetWeekday(...)0%220%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Private.CoreLib/src/System/Globalization/ISOWeek.cs

#LineLine coverage
 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
 4using System.Runtime.CompilerServices;
 5using static System.Globalization.GregorianCalendar;
 6
 7namespace System.Globalization
 8{
 9    public static class ISOWeek
 10    {
 11        private const int WeeksInLongYear = 53;
 12        private const int WeeksInShortYear = 52;
 13
 14        private const int MinWeek = 1;
 15        private const int MaxWeek = WeeksInLongYear;
 16
 17        public static int GetWeekOfYear(DateTime date)
 18        {
 019            int week = GetWeekNumber(date);
 20
 021            if (week < MinWeek)
 22            {
 23                // If the week number obtained equals 0, it means that the
 24                // given date belongs to the preceding (week-based) year.
 025                return GetWeeksInYear(date.Year - 1);
 26            }
 27
 028            if (week > WeeksInShortYear && GetWeeksInYear(date.Year) == WeeksInShortYear)
 29            {
 30                // If a week number of 53 is obtained, one must check that
 31                // the date is not actually in week 1 of the following year.
 032                return MinWeek;
 33            }
 34
 035            return week;
 36        }
 37
 38        /// <summary>
 39        /// Calculates the ISO week number of a given Gregorian date.
 40        /// </summary>
 41        /// <param name="date">A date in the Gregorian calendar.</param>
 42        /// <returns>A number between 1 and 53 representing the ISO week number of the given Gregorian date.</returns>
 043        public static int GetWeekOfYear(DateOnly date) => GetWeekOfYear(date.GetEquivalentDateTime());
 44
 45        public static int GetYear(DateTime date)
 46        {
 047            int week = GetWeekNumber(date);
 048            int year = date.Year;
 49
 050            if (week < MinWeek)
 51            {
 52                // If the week number obtained equals 0, it means that the
 53                // given date belongs to the preceding (week-based) year.
 054                year--;
 55            }
 056            else if (week > WeeksInShortYear && GetWeeksInYear(year) == WeeksInShortYear)
 57            {
 58                // If a week number of 53 is obtained, one must check that
 59                // the date is not actually in week 1 of the following year.
 060                year++;
 61            }
 62
 063            return year;
 64        }
 65
 66        /// <summary>
 67        /// Calculates the ISO week-numbering year (also called ISO year informally) mapped to the input Gregorian date.
 68        /// </summary>
 69        /// <param name="date">A date in the Gregorian calendar.</param>
 70        /// <returns>The ISO week-numbering year, between 1 and 9999</returns>
 071        public static int GetYear(DateOnly date) => GetYear(date.GetEquivalentDateTime());
 72
 73        // The year parameter represents an ISO week-numbering year (also called ISO year informally).
 74        // Each week's year is the Gregorian year in which the Thursday falls.
 75        // The first week of the year, hence, always contains 4 January.
 76        // ISO week year numbering therefore slightly deviates from the Gregorian for some days close to 1 January.
 77        public static DateTime GetYearStart(int year)
 78        {
 079            return ToDateTime(year, MinWeek, DayOfWeek.Monday);
 80        }
 81
 82        // The year parameter represents an ISO week-numbering year (also called ISO year informally).
 83        // Each week's year is the Gregorian year in which the Thursday falls.
 84        // The first week of the year, hence, always contains 4 January.
 85        // ISO week year numbering therefore slightly deviates from the Gregorian for some days close to 1 January.
 86        public static DateTime GetYearEnd(int year)
 87        {
 088            return ToDateTime(year, GetWeeksInYear(year), DayOfWeek.Sunday);
 89        }
 90
 91        // From https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year:
 92        //
 93        // The long years, with 53 weeks in them, can be described by any of the following equivalent definitions:
 94        //
 95        // - Any year starting on Thursday and any leap year starting on Wednesday.
 96        // - Any year ending on Thursday and any leap year ending on Friday.
 97        // - Years in which 1 January and 31 December (in common years) or either (in leap years) are Thursdays.
 98        //
 99        // All other week-numbering years are short years and have 52 weeks.
 100        public static int GetWeeksInYear(int year)
 101        {
 0102            if (year < MinYear || year > MaxYear)
 103            {
 0104                ThrowHelper.ThrowArgumentOutOfRange_Year();
 105            }
 106
 107            [MethodImpl(MethodImplOptions.AggressiveInlining)]
 108            static uint P(uint y)
 109            {
 0110                uint cent = y / 100;
 0111                return (y + (y / 4) - cent + cent / 4) % 7;
 112            }
 113
 0114            if (P((uint)year) == 4 || P((uint)year - 1) == 3)
 115            {
 0116                return WeeksInLongYear;
 117            }
 118
 0119            return WeeksInShortYear;
 120        }
 121
 122        // From https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year,_week_number_and_weekday:
 123        //
 124        // This method requires that one know the weekday of 4 January of the year in question.
 125        // Add 3 to the number of this weekday, giving a correction to be used for dates within this year.
 126        //
 127        // Multiply the week number by 7, then add the weekday. From this sum subtract the correction for the year.
 128        // The result is the ordinal date, which can be converted into a calendar date.
 129        //
 130        // If the ordinal date thus obtained is zero or negative, the date belongs to the previous calendar year.
 131        // If greater than the number of days in the year, to the following year.
 132        public static DateTime ToDateTime(int year, int week, DayOfWeek dayOfWeek)
 133        {
 0134            if (year < MinYear || year > MaxYear)
 135            {
 0136                ThrowHelper.ThrowArgumentOutOfRange_Year();
 137            }
 138
 0139            if (week < MinWeek || week > MaxWeek)
 140            {
 0141                throw new ArgumentOutOfRangeException(nameof(week), SR.ArgumentOutOfRange_Week_ISO);
 142            }
 143
 144            // We allow 7 for convenience in cases where a user already has a valid ISO
 145            // day of week value for Sunday. This means that both 0 and 7 will map to Sunday.
 146            // The GetWeekday method will normalize this into the 1-7 range required by ISO.
 0147            if ((int)dayOfWeek < 0 || (int)dayOfWeek > 7)
 148            {
 0149                throw new ArgumentOutOfRangeException(nameof(dayOfWeek), SR.ArgumentOutOfRange_DayOfWeek);
 150            }
 151
 0152            var jan4 = new DateTime(year, month: 1, day: 4);
 153
 0154            int correction = GetWeekday(jan4.DayOfWeek) + 3;
 155
 0156            int ordinal = (week * 7) + GetWeekday(dayOfWeek) - correction;
 157
 0158            return jan4.AddTicks((ordinal - 4) * TimeSpan.TicksPerDay);
 159        }
 160
 161
 162        /// <summary>
 163        /// Maps the ISO week date represented by a specified ISO year, week number, and day of week to the equivalent G
 164        /// </summary>
 165        /// <param name="year">An ISO week-numbering year (also called an ISO year informally).</param>
 166        /// <param name="week">The ISO week number in the given ISO week-numbering year.</param>
 167        /// <param name="dayOfWeek">The day of week inside the given ISO week.</param>
 168        /// <returns>The Gregorian date equivalent to the input ISO week date.</returns>
 0169        public static DateOnly ToDateOnly(int year, int week, DayOfWeek dayOfWeek) => DateOnly.FromDateTime(ToDateTime(y
 170
 171        // From https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_of_a_given_date:
 172        //
 173        // Using ISO weekday numbers (running from 1 for Monday to 7 for Sunday),
 174        // subtract the weekday from the ordinal date, then add 10. Divide the result by 7.
 175        // Ignore the remainder; the quotient equals the week number.
 176        //
 177        // If the week number thus obtained equals 0, it means that the given date belongs to the preceding (week-based)
 178        // If a week number of 53 is obtained, one must check that the date is not actually in week 1 of the following y
 179        private static int GetWeekNumber(DateTime date)
 180        {
 0181            return (int)((uint)(date.DayOfYear - GetWeekday(date.DayOfWeek) + 10) / 7);
 182        }
 183
 184        // Day of week in ISO is represented by an integer from 1 through 7, beginning with Monday and ending with Sunda
 185        // This matches the underlying values of the DayOfWeek enum, except for Sunday, which needs to be converted.
 186        private static int GetWeekday(DayOfWeek dayOfWeek)
 187        {
 0188            return dayOfWeek == DayOfWeek.Sunday ? 7 : (int)dayOfWeek;
 189        }
 190    }
 191}
 192