从周数计算date

任何人都知道一个简单的方法来获得一周的第一天的date(星期一在这里在欧洲)。 我知道年份和周数? 我打算用C#来做这件事。

提前致谢。

即使通过@RobinAndersson修复,我也遇到了@HenkHolterman解决scheme的问题。

阅读ISO 8601标准很好地解决了这个问题。 使用第一个星期四作为目标,而不是星期一。 下面的代码也适用于2009年第53周。

public static DateTime FirstDateOfWeekISO8601(int year, int weekOfYear) { DateTime jan1 = new DateTime(year, 1, 1); int daysOffset = DayOfWeek.Thursday - jan1.DayOfWeek; DateTime firstThursday = jan1.AddDays(daysOffset); var cal = CultureInfo.CurrentCulture.Calendar; int firstWeek = cal.GetWeekOfYear(firstThursday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); var weekNum = weekOfYear; if (firstWeek <= 1) { weekNum -= 1; } var result = firstThursday.AddDays(weekNum * 7); return result.AddDays(-3); } 

注意

下面的答案使用.NET日历规则。 它不承诺ISO8601一致性。 当你需要的时候,看一些其他的答案。 周编号是一团糟,总是试图找出你需要先遵循什么规则。


下面的代码正确地把2009年第一周的开始在29-12-2008。 CalendarWeekRule可能应该是一个参数。

请注意,weekNum应该是> = 1

 static DateTime FirstDateOfWeek(int year, int weekNum, CalendarWeekRule rule) { Debug.Assert(weekNum >= 1); DateTime jan1 = new DateTime(year, 1, 1); int daysOffset = DayOfWeek.Monday - jan1.DayOfWeek; DateTime firstMonday = jan1.AddDays(daysOffset); Debug.Assert(firstMonday.DayOfWeek == DayOfWeek.Monday); var cal = CultureInfo.CurrentCulture.Calendar; int firstWeek = cal.GetWeekOfYear(firstMonday, rule, DayOfWeek.Monday); if (firstWeek <= 1) { weekNum -= 1; } DateTime result = firstMonday.AddDays(weekNum * 7); return result; } 

我喜欢Henk Holterman提供的解决scheme。 但要多一点文化独立,你必须得到当前文化的一周的第一天(这不总是星期一):

 using System.Globalization; static DateTime FirstDateOfWeek(int year, int weekOfYear) { DateTime jan1 = new DateTime(year, 1, 1); int daysOffset = (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek - (int)jan1.DayOfWeek; DateTime firstMonday = jan1.AddDays(daysOffset); int firstWeek = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(jan1, CultureInfo.CurrentCulture.DateTimeFormat.CalendarWeekRule, CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek); if (firstWeek <= 1) { weekOfYear -= 1; } return firstMonday.AddDays(weekOfYear * 7); } 

最简单的方法可能是find一年中的第一个星期一,然后添加相关的周数。 这是一些示例代码。 它假定一个星期从1开始,顺便说一下:

 using System; class Test { static void Main() { // Show the third Tuesday in 2009. Should be January 20th Console.WriteLine(YearWeekDayToDateTime(2009, DayOfWeek.Tuesday, 3)); } static DateTime YearWeekDayToDateTime(int year, DayOfWeek day, int week) { DateTime startOfYear = new DateTime (year, 1, 1); // The +7 and %7 stuff is to avoid negative numbers etc. int daysToFirstCorrectDay = (((int)day - (int)startOfYear.DayOfWeek) + 7) % 7; return startOfYear.AddDays(7 * (week-1) + daysToFirstCorrectDay); } } 

就我个人而言,我会利用文化信息来获得一周中的第一天,然后回到文化的第一天。 我不知道我是否正确地解释它,这里是一个例子:

  public DateTime GetFirstDayOfWeek(int year, int weekNumber) { return GetFirstDayOfWeek(year, weekNumber, Application.CurrentCulture); } public DateTime GetFirstDayOfWeek(int year, int weekNumber, System.Globalization.CultureInfo culture) { System.Globalization.Calendar calendar = culture.Calendar; DateTime firstOfYear = new DateTime(year, 1, 1, calendar); DateTime targetDay = calendar.AddWeeks(firstOfYear, weekNumber); DayOfWeek firstDayOfWeek = culture.DateTimeFormat.FirstDayOfWeek; while (targetDay.DayOfWeek != firstDayOfWeek) { targetDay = targetDay.AddDays(-1); } return targetDay; } 

根据瑞典使用的 ISO 8601:1988 今年的第一周是新年之内至less四天的第一周。

所以,如果你的星期在星期一开始,那么每年的第一个星期四在第一个星期内。 你可以从这个DateAdd或DateDiff。

使用Fluent DateTime http://fluentdatetime.codeplex.com/

  var year = 2009; var firstDayOfYear = new DateTime(year, 1, 1); var firstMonday = firstDayOfYear.Next(DayOfWeek.Monday); var weeksDateTime = 12.Weeks().Since(firstMonday); 

以下是一种与Google Analytics(分析)的星期编号兼容的方法,也是我们在英特尔内部使用的相同编号scheme,而且我确定这种方法也可用于其他许多情况。

 // Google Analytics does not follow ISO standards for date. // It numbers week 1 starting on Jan. 1, regardless what day of week it starts on. // It treats Sunday as the first day of the week. // The first and last weeks of a year are usually not complete weeks. public static DateTime GetStartDateTimeFromWeekNumberInYear(int year, uint weekOfYear) { if (weekOfYear == 0 || weekOfYear > 54) throw new ArgumentException("Week number must be between 1 and 54! (Yes, 54... Year 2000 had Jan. 1 on a Saturday plus 53 Sundays.)"); // January 1 -- first week. DateTime firstDayInWeek = new DateTime(year, 1, 1); if (weekOfYear == 1) return firstDayInWeek; // Get second week, starting on the following Sunday. do { firstDayInWeek = firstDayInWeek.AddDays(1); } while (firstDayInWeek.DayOfWeek != DayOfWeek.Sunday); if (weekOfYear == 2) return firstDayInWeek; // Now get the Sunday of whichever week we're looking for. return firstDayInWeek.AddDays((weekOfYear - 2)*7); } 

假设周数从1开始

 DateTime dt = new DateTime(YearNumber, 1, 1).AddDays((WeekNumber - 1) * 7 - (WeekNumber == 1 ? 0 : 1)); return dt.AddDays(-(int)dt.DayOfWeek); 

这应该给你在任何一个星期的第一天。 我没有做过很多的testing,但看起来像是有效的。 它比我在网上find的其他大多数的解决scheme都小,所以想要分享。

.NET的免费时间库包括ISO 8601符合类

 // ---------------------------------------------------------------------- public static DateTime GetFirstDayOfWeek( int year, int weekOfYear ) { return new Week( year, weekOfYear ).FirstDayStart; } // GetFirstDayOfWeek 

这一个为我工作,它也有期待一个文化信息作为参数来testing不同文化的公式的优势。 如果为空,则获得当前的文化信息…有效值如“it”,“en-us”,“fr”,… ando等。 诀窍是减去一年中第一天的周数,也就是1表示第一天在第一周内。 希望这可以帮助。

 Public Shared Function FirstDayOfWeek(ByVal year As Integer, ByVal weekNumber As Integer, ByVal culture As String) As Date Dim cInfo As System.Globalization.CultureInfo If culture = "" Then cInfo = System.Globalization.CultureInfo.CurrentCulture Else cInfo = System.Globalization.CultureInfo.CreateSpecificCulture(culture) End If Dim calendar As System.Globalization.Calendar = cInfo.Calendar Dim firstOfYear As DateTime = New DateTime(year, 1, 1, calendar) Dim firstDayWeek As Integer = calendar.GetWeekOfYear(firstOfYear, cInfo.DateTimeFormat.CalendarWeekRule, cInfo.DateTimeFormat.FirstDayOfWeek) weekNumber -= firstDayWeek Dim targetDay As DateTime = calendar.AddWeeks(firstOfYear, weekNumber) Dim fDayOfWeek As DayOfWeek = cInfo.DateTimeFormat.FirstDayOfWeek While (targetDay.DayOfWeek <> fDayOfWeek) targetDay = targetDay.AddDays(-1) End While Return targetDay End Function 

轻轻改变了Mikael Svenson的代码。 我find了第一个星期一的星期,并适当地改变了星期的数字。

  DateTime GetFirstWeekDay(int year, int weekNum) { Calendar calendar = CultureInfo.CurrentCulture.Calendar; DateTime jan1 = new DateTime(year, 1, 1); int daysOffset = DayOfWeek.Monday - jan1.DayOfWeek; DateTime firstMonday = jan1.AddDays(daysOffset); int firstMondayWeekNum = calendar.GetWeekOfYear(firstMonday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); DateTime firstWeekDay = firstMonday.AddDays((weekNum-firstMondayWeekNum) * 7); return firstWeekDay; } 

我尝试了一些上面的代码,一些有一些小错误,当你尝试不同的年份,在不同的开始几天你会看到他们,我拿了乔恩Skeet的代码,修复它,它的工作,非常简单的代码。

 Public Function YearWeekDayToDateTime(ByVal year As Integer, ByVal weekDay As Integer, ByVal week As Integer) As DateTime ' weekDay, day you want Dim startOfYear As New DateTime(year, 1, 1) Dim startOfYearFixDay As Integer If startOfYear.DayOfWeek <> DayOfWeek.Sunday Then startOfYearFixDay = startOfYear.DayOfWeek Else startOfYearFixDay = 7 End If Return startOfYear.AddDays((7 * (week)) - startOfYearFixDay + weekDay) End Function 

第1周定义为星期一开始的星期,包含一年中的第一个星期四。

要在两个方向转换,请参阅此处: 关于ISO周date的维基百科文章

我用一个覆盖改进了一下托马斯的解决scheme:

  public static DateTime FirstDateOfWeek(int year, int weekOfYear) { return Timer.FirstDateOfWeekOfMonth(year, 1, weekOfYear); } public static DateTime FirstDateOfWeekOfMonth(int year, int month, int weekOfYear) { DateTime dtFirstDayOfMonth = new DateTime(year, month, 1); //I also commented out this part: /* if (firstWeek <= 1) { weekOfYear -= 1; } */ 

否则,date前一周。

谢谢托马斯,很有帮助。

我使用了其中的一个解决scheme,但它给了我错误的结果,仅仅是因为它将星期天定为一周中的第一天。

我变了:

 var firstDay = new DateTime(DateTime.Now.Year, 1, 1).AddDays((weekNumber - 1) * 7); var lastDay = firstDay.AddDays(6); 

至:

 var lastDay = new DateTime(DateTime.Now.Year, 1, 1).AddDays((weekNumber) * 7); var firstDay = lastDay.AddDays(-6); 

现在它正在成为一种魅力。

build议的解决scheme不完整 – 它只适用于CalendarWeekRule.FirstFullWeek。 其他types的周规则不起作用。 使用这个testing用例可以看出这一点:

 foreach (CalendarWeekRule rule in Enum.GetValues(typeof(CalendarWeekRule))) { for (int year = 1900; year < 2000; year++) { DateTime date = FirstDateOfWeek(year, 1, rule); Assert(CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(date, rule, DayOfWeek.Monday) == 1); Assert(CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(date.AddDays(-1), rule, DayOfWeek.Monday) != 1); } } 

我已经提出了一个更简单的参数化的build议解决scheme的精炼版本,并将参数化为firstDayOfWeek:

 public static DateTime GetFirstDayOfWeek(int year, int week, DayOfWeek firstDayOfWeek) { return GetWeek1Day1(year, firstDayOfWeek).AddDays(7 * (week - 1)); } public static DateTime GetWeek1Day1(int year, DayOfWeek firstDayOfWeek) { DateTime date = new DateTime(year, 1, 1); // Move towards firstDayOfWeek date = date.AddDays(firstDayOfWeek - date.DayOfWeek); // Either 1 or 52 or 53 int weekOfYear = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFullWeek, firstDayOfWeek); // Move forwards 1 week if week is 52 or 53 date = date.AddDays(7 * System.Math.Sign(weekOfYear - 1)); return date; } 

这是我的解决scheme,当我们要计算一个给定的年份,周数和星期几的date。

 int Year = 2014; int Week = 48; int DayOfWeek = 4; DateTime FecIni = new DateTime(Year, 1, 1); FecIni = FecIni.AddDays(7 * (Week - 1)); if ((int)FecIni.DayOfWeek > DayOfWeek) { while ((int)FecIni.DayOfWeek != DayOfWeek) FecIni = FecIni.AddDays(-1); } else { while ((int)FecIni.DayOfWeek != DayOfWeek) FecIni = FecIni.AddDays(1); } 

我简化了Mikael Svensson提供的欧洲许多国家正确的代码。

 public static DateTime FirstDateOfWeekIso8601(int year, int week) { var firstThursdayOfYear = new DateTime(year, 1, 1); while (firstThursdayOfYear.DayOfWeek != DayOfWeek.Thursday) { firstThursdayOfYear = firstThursdayOfYear.AddDays(1); } var startDateOfWeekOne = firstThursdayOfYear.AddDays(-(DayOfWeek.Thursday - DayOfWeek.Monday)); return startDateOfWeekOne.AddDays(7 * (week - 1)); } 

我已经编写和testing了下面的代码,对我来说工作得很好。 请让我知道如果有人遇到麻烦,我也发布了一个问题,以获得最佳答案。 有人可能会觉得它有用。

 public static DateTime GetFirstDateOfWeekByWeekNumber(int year, int weekNumber) { var date = new DateTime(year, 01, 01); var firstDayOfYear = date.DayOfWeek; var result = date.AddDays(weekNumber * 7); if (firstDayOfYear == DayOfWeek.Monday) return result.Date; if (firstDayOfYear == DayOfWeek.Tuesday) return result.AddDays(-1).Date; if (firstDayOfYear == DayOfWeek.Wednesday) return result.AddDays(-2).Date; if (firstDayOfYear == DayOfWeek.Thursday) return result.AddDays(-3).Date; if (firstDayOfYear == DayOfWeek.Friday) return result.AddDays(-4).Date; if (firstDayOfYear == DayOfWeek.Saturday) return result.AddDays(-5).Date; return result.AddDays(-6).Date; } 

目前,没有正确处理ISO 8601周编号的C#类。 即使你可以实例化一个文化,寻找最接近的东西,并纠正这一点,我认为最好自己做一个完整的计算:

  /// <summary> /// Converts a date to a week number. /// ISO 8601 week 1 is the week that contains the first Thursday that year. /// </summary> public static int ToIso8601Weeknumber(this DateTime date) { var thursday = date.AddDays(3 - date.DayOfWeek.DayOffset()); return (thursday.DayOfYear - 1) / 7 + 1; } /// <summary> /// Converts a week number to a date. /// Note: Week 1 of a year may start in the previous year. /// ISO 8601 week 1 is the week that contains the first Thursday that year, so /// if December 28 is a Monday, December 31 is a Thursday, /// and week 1 starts January 4. /// If December 28 is a later day in the week, week 1 starts earlier. /// If December 28 is a Sunday, it is in the same week as Thursday January 1. /// </summary> public static DateTime FromIso8601Weeknumber(int weekNumber, int? year = null, DayOfWeek day = DayOfWeek.Monday) { var dec28 = new DateTime((year ?? DateTime.Today.Year) - 1, 12, 28); var monday = dec28.AddDays(7 * weekNumber - dec28.DayOfWeek.DayOffset()); return monday.AddDays(day.DayOffset()); } /// <summary> /// Iso8601 weeks start on Monday. This returns 0 for Monday. /// </summary> private static int DayOffset(this DayOfWeek weekDay) { return ((int)weekDay + 6) % 7; }