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

问题是似乎没有内置的方法从先前计算的“周数”获得DateTime。

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

DateTime dt1 = new DateTime.Now; int week = cal.GetWeekOfYear(dt); DateTime dt2 = GetDateTimeFromYearAndWeek(dt.Year, week); if (dt1  dt2.AddDays(7.0)) { throw new Exception("new datetime limits do not span existing datetime; } 

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

我自己的答案是三方面的。 首先,我想出了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 ); } 

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

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