怎么做我将从Calendar.GetWeekOfYear返回的一周反转回DateTime?

时间:2013-05-14 22:27:45

标签: c# datetime

问题在于,似乎没有一种内置方法可以从之前计算的“周数”中获取DateTime。

我想要做的是基本上所有时间和所有文化日历都有这项工作。

  DateTime dt1 = new DateTime.Now;
  int week = cal.GetWeekOfYear(dt);
  DateTime dt2 = GetDateTimeFromYearAndWeek(dt.Year, week);

  if (dt1 < dt2 || dt2 > dt2.AddDays(7.0))
  {
    throw new Exception("new datetime limits do not span existing datetime;
  }

我认为其中一个问题是,对于某些文化,cal.GetWeekOfYear(dt)调用将从dt.Year返回不同年的正确周数。这意味着你不能在我的虚拟GetDateTimeFromYearAndWeek电话的调用中使用它。

1 个答案:

答案 0 :(得分:0)

我自己的答案是三倍的。首先,我想出了一个返回本周“年”的Calendar.GetWeekOfYear包装器,因为今年可能与DateTime对象的年份不同。

    public static void GetWeek(DateTime dt, CultureInfo ci, out int week, out int year)
    {
        year = dt.Year;
        week = ci.Calendar.GetWeekOfYear(dt, ci.DateTimeFormat.CalendarWeekRule, ci.DateTimeFormat.FirstDayOfWeek);

        int prevweek = ci.Calendar.GetWeekOfYear(dt.AddDays(-7.0), ci.DateTimeFormat.CalendarWeekRule, ci.DateTimeFormat.FirstDayOfWeek);

        if (prevweek + 1 == week) {
            // year of prevweek should be correct
            year = dt.AddDays(-7.0).Year;
        } else {
            // stay here
            year = dt.Year;
        }
    }

接下来,这是答案的答案。这会将yearweekOfYear反转为DateTime对象。请注意,我在今年年中使用过,因为这似乎可以避免新一年的奇点出现问题(52或53可能会或者不会回到1)。我还通过查找确实是一周中第一天的日期来同步日期,避免了比较两个DayOfWeek值的负偏移问题。

    public static DateTime FirstDateOfWeek(int year, int weekOfYear, CultureInfo ci)
    {
        DateTime jul1 = new DateTime(year, 7, 1);
        while (jul1.DayOfWeek != ci.DateTimeFormat.FirstDayOfWeek)
        {
            jul1 = jul1.AddDays(1.0);
        }
        int refWeek = ci.Calendar.GetWeekOfYear(jul1, ci.DateTimeFormat.CalendarWeekRule, ci.DateTimeFormat.FirstDayOfWeek);

        int weekOffset = weekOfYear - refWeek;

        return jul1.AddDays(7 * weekOffset );
    }

最后,对所有怀疑它的人来说,这是我的单元测试,它循环了很多日期和文化,以确保它适用于所有这些。

    public static void TestDates()
    {
        foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures).Where((x)=>!x.IsNeutralCulture && x.Calendar.AlgorithmType == CalendarAlgorithmType.SolarCalendar))
        {

            for (int year = 2010; year < 2040; year++)
            {
                // first try a bunch of hours in this year
                // convert from date -> week -> date

                for (int hour = 0; hour < 356 * 24; hour+= 6)
                {
                    DateTime dt = new DateTime(year, 1, 1).AddHours(hour);
                    int ww;
                    int wyear;
                    Gener8.SerialNumber.GetWeek(dt, ci, out ww, out wyear);
                    if (wyear != year)
                    {
                        //Console.WriteLine("{0} warning: {1} {2} {3}", ci.Name, dt, year, wyear);
                    }
                    DateTime dt1 = Gener8.SerialNumber.FirstDateOfWeek(wyear, ww, ci);
                    DateTime dt2 = Gener8.SerialNumber.FirstDateOfWeek(wyear, ww, ci).AddDays(7.0);
                    if (dt < dt1 || dt > dt2)
                    {
                        Console.WriteLine("{3} Bad date {0} not between {1} and {2}", dt, dt1, dt2, ci.Name);
                    }
                }

                // next try a bunch of weeks in this year
                // convert from week -> date -> week

                for (int week = 1; week < 54; week++)
                {
                    DateTime dt0 = FirstDateOfWeek(year, week, ci);
                    int ww0;
                    int wyear0;
                    GetWeek(dt0, ci, out ww0, out wyear0);
                    DateTime dt1 = dt0.AddDays(6.9);
                    int ww1;
                    int wyear1;
                    GetWeek(dt1, ci, out ww1, out wyear1);
                    if ((dt0.Year == year && ww0 != week) ||
                        (dt1.Year == year && ww1 != week))
                    {
                        Console.WriteLine("{4} Bad date {0} ww0={1} ww1={2}, week={3}", dt0, ww0, ww1, week, ci.Name);
                    }
                }
            }
        }
    }