0

问题是似乎没有一种内置方法可以从先前计算的“周数”中获取 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;
  }

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

4

1 回答 1

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;
        }
    }

接下来,这是答案的核心。这将yearand反转weekOfYear为一个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);
                    }
                }
            }
        }
    }
于 2013-05-14T22:27:44.927 回答