最後一年年週,53週和52週

C#知識系列

最近筆者在寫測試的時候,發現到非常特別狀況,讓我少了這個測試案例…我一直以為年底都是53週,原來有52週

    public interface IDateTimeHelper
    {
        /// <summary>
        /// 取時間-避免相依DataTime方便寫單元測試
        /// </summary>
        /// <returns></returns>
        DateTime GetDateTimeNow();
        /// <summary>
        /// 抓當年度本週
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        int GetCurrentYearWeekNo(DateTime today);
        /// <summary>
        /// 抓本年度當週的上一週
        /// </summary>
        /// <param name="today"></param>
        /// <returns></returns>
        int GetYearLastWeekNo(DateTime today);
        /// <summary>
        /// 抓本年度當週的前兩週
        /// </summary>
        /// <param name="today"></param>
        /// <returns></returns>
        int GetYearTwoAgoWeekNo(DateTime today);


    }
    public class DateTimeHelper : IDateTimeHelper
    {
        public DateTime GetDateTimeNow()
        {
            return DateTime.Now;
        }

        public int GetYearLastWeekNo(DateTime today)
        {
            int yearWeekNo = GetCurrentYearWeekNo(today);
            return (yearWeekNo % 100 == 1) ? GetYearFinallyWeekNo(today.Year)
                                                        : yearWeekNo - 1;
        }

        public int GetYearTwoAgoWeekNo(DateTime today)
        {
            int yearWeekNo = GetCurrentYearWeekNo(today);
            int weekNo = (yearWeekNo % 100);

            if (weekNo == 1)
                return GetYearFinallyWeekNo(today.Year) - 1;
            else if (weekNo == 2)
                return GetYearFinallyWeekNo(today.Year);
            else
                return yearWeekNo - 2;
        }

        /// <summary>
        /// 抓當年度本週
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public int GetCurrentYearWeekNo(DateTime today)
        {
            //var firstSaturday = today.AddDays(6 - (int)today.DayOfWeek);
            //int week = (firstSaturday.DayOfYear - 1) / 7 + 1;
            //string yeeaNo = firstSaturday.ToString("yyyy") + week.ToString("D2");
            //return Convert.ToInt32(yeeaNo);
            GregorianCalendar gc = new GregorianCalendar();
            return Convert.ToInt32(today.Year.ToString() + gc.GetWeekOfYear(today,
                    CalendarWeekRule.FirstDay, DayOfWeek.Monday).ToString().PadLeft(2, '0'));
        }

        /// <summary>
        ///  去年的十二月底最後一週
        /// </summary>
        /// <param name="year"></param>
        /// <param name="reduceNum"></param>
        /// <returns></returns>
        private int GetYearFinallyWeekNo(int year)
        {
            //int lastYear = year - 1;
            //string yearWeekNo = string.Empty;
            //DateTime firstSaturday = new DateTime();
            //int week = 0;
            //int i = 0;
            //do
            //{
            //    DateTime end = new DateTime(lastYear, 12, 31 - i);  //該年最後一天/因為
            //    firstSaturday = end.AddDays(6 - (int)end.DayOfWeek);
            //    week = (firstSaturday.DayOfYear - 1) / 7 + 1;
            //    i++;
            //} while ((week == 1));
            //yearWeekNo = firstSaturday.ToString("yyyy") + week.ToString("D2");

            //return Convert.ToInt32(yearWeekNo);
            int lastYear = year - 1;
            DateTime end = new DateTime(lastYear, 12, 31);  //該年最後一天
            GregorianCalendar gc = new GregorianCalendar();
            return Convert.ToInt32(lastYear.ToString() + (gc.GetWeekOfYear(end,
                   CalendarWeekRule.FirstDay, DayOfWeek.Monday)).ToString().PadLeft(2, '0'));  //該年的週數
        }
        
    }

 

 

    /// <summary>
    /// 日期測試
    ///  <para> 測試命名:Should_預期行為(ExpectedBehavior)_When_執行測試案例的狀態</para>
    /// </summary>
    [TestFixture]
    public class DateTimeHelper_Ut
    {
        public IDateTimeHelper _dateTimeHelper;

        [SetUp]
        public void Setup()
        {
            _dateTimeHelper = new DateTimeHelper();
        }
        /// <summary>
        /// 當取現在日期,應該得到年週
        /// 當2020/1/1,應該202001
        /// 當2020/2/1,應該202005
        /// 當2020/12/31,應該202053
        /// 當2021/1/1,應該202101
        /// 當2021/12/31,應該202153
        /// 當2022/1/1,應該202201
        /// 當2022/12/31,應該202253
        /// </summary>
        /// <param name="expected"></param>
        /// <param name="year"></param>
        /// <param name="month"></param>
        /// <param name="day"></param>

        [Test]
        [TestCase(202001, 2020, 1, 1)]
        [TestCase(202005, 2020, 2, 1)]
        [TestCase(202053, 2020, 12, 31)]
        [TestCase(202101, 2021, 1, 1)]
        [TestCase(202153, 2021, 12, 31)]
        [TestCase(202201, 2022, 1, 1)]
        [TestCase(202253, 2022, 12, 31)]
        public void Should_YearWeekNo_When_GetNowDate(int expected, int year, int month, int day)
        {
            ShouldBeCurrentYearWeekNo(expected, year, month, day);
        }

        private void ShouldBeCurrentYearWeekNo(int expected, int year, int month, int day)
        {
            Assert.AreEqual(expected, _dateTimeHelper.GetCurrentYearWeekNo(new DateTime(year, month, day)));
        }

        /// <summary>
        /// 當取現在日期,應該取得年度前一週
        /// 當2020/1/1,應該201953
        /// 當2020/1/6,應該202001
        /// 當2021/1/1,應該202053(DBA那邊只認禮拜一、不認後面)
        /// 當2021/1/4,應該202101
        /// 當2022/1/1,應該202153
        /// </summary>
        [Test]
        [TestCase(201953, 2020, 1, 1)]
        [TestCase(202001, 2020, 1, 6)]
        [TestCase(202053, 2021, 1, 1)]
        [TestCase(202101, 2021, 1, 4)]
        [TestCase(202153, 2022, 1, 1)]

        public void Should_YearLastWeekNo_When_GetNowDate(int expected, int year, int month, int day)
        {
            ShouldBeYearLastWeekNo(expected, year, month, day);
        }

        /// <summary>
        /// 當取現在日期,應該取得年度前兩週
        /// 當2020/1/1,應該201952
        /// 當2020/1/6,應該201953
        /// 當2020/1/13,應該202001
        /// 當2021/1/1,應該202052
        /// 當2021/1/4,應該202053
        /// 當2021/1/11,應該202101
        /// </summary>
        [Test]
        [TestCase(201952, 2020, 1, 1)]
        [TestCase(201953, 2020, 1, 6)]
        [TestCase(202001, 2020, 1, 13)]
        [TestCase(202052, 2021, 1, 1)]
        [TestCase(202053, 2021, 1, 4)]
        [TestCase(202101, 2021, 1, 11)]
        public void Should_YearTwoAgoWeekNo_When_GetNowDate(int expected, int year, int month, int day)
        {
            ShouldBeYearTwoAgoWeekNo(expected, year, month, day);
        }

        private void ShouldBeYearLastWeekNo(int expected, int year, int month, int day)
        {
            Assert.AreEqual(expected, _dateTimeHelper.GetYearLastWeekNo(new DateTime(year, month, day)));
        }

        private void ShouldBeYearTwoAgoWeekNo(int expected, int year, int month, int day)
        {
            Assert.AreEqual(expected, _dateTimeHelper.GetYearTwoAgoWeekNo(new DateTime(year, month, day)));
        }
    }

老E隨手寫