问题在于,似乎没有一种内置方法可以从之前计算的“周数”中获取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
电话的调用中使用它。
答案 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;
}
}
接下来,这是答案的答案。这会将year
和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);
}
}
}
}
}