Рассчитать дату по номеру недели - PullRequest
122 голосов
/ 19 марта 2009

Каждый знает простой способ получить дату первого дня недели (понедельник здесь, в Европе). Я знаю год и номер недели? Я собираюсь сделать это в C #.

Ответы [ 23 ]

219 голосов
/ 30 января 2012

У меня были проблемы с решением @HenkHolterman даже с исправлением @ RobinAndersson.

Чтение по стандарту ISO 8601 хорошо решает проблему. Используйте первый четверг как цель, а не понедельник. Код ниже будет работать и для 53 недели 2009 года.

public static DateTime FirstDateOfWeekISO8601(int year, int weekOfYear)
{
    DateTime jan1 = new DateTime(year, 1, 1);
    int daysOffset = DayOfWeek.Thursday - jan1.DayOfWeek;

    // Use first Thursday in January to get first week of the year as
    // it will never be in Week 52/53
    DateTime firstThursday = jan1.AddDays(daysOffset);
    var cal = CultureInfo.CurrentCulture.Calendar;
    int firstWeek = cal.GetWeekOfYear(firstThursday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);

    var weekNum = weekOfYear;
    // As we're adding days to a date in Week 1,
    // we need to subtract 1 in order to get the right date for week #1
    if (firstWeek == 1)
    {
        weekNum -= 1;
    }

    // Using the first Thursday as starting week ensures that we are starting in the right year
    // then we add number of weeks multiplied with days
    var result = firstThursday.AddDays(weekNum * 7);

    // Subtract 3 days from Thursday to get Monday, which is the first weekday in ISO8601
    return result.AddDays(-3);
}       
36 голосов
/ 27 мая 2009

Мне нравится решение, предоставленное Хенком Холтерманом. Но чтобы быть немного более независимым от культуры, вы должны получить первый день недели для текущей культуры (это не всегда понедельник):

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);
}
9 голосов
/ 19 марта 2009

Самый простой способ - это найти первый понедельник года, а затем добавить соответствующее количество недель. Вот пример кода. Предполагается, что номер недели начинается с 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);
    }
}
4 голосов
/ 19 июня 2018

Хорошие новости! запрос на получение , добавляющий System.Globalization.ISOWeek в .NET Core, был только что объединен и в настоящее время запланирован на выпуск 3.0. Надеемся, что он распространится на другие платформы .NET в недалеком будущем.

Вы должны быть в состоянии использовать метод ISOWeek.ToDateTime(int year, int week, DayOfWeek dayOfWeek) для вычисления этого.

Вы можете найти исходный код здесь .

3 голосов
/ 19 марта 2009

Лично я бы использовал информацию о культуре, чтобы узнать день недели и перейти к первому дню культуры. Я не уверен, что правильно объясняю, вот пример:

    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;
    }
2 голосов
/ 04 сентября 2009

с использованием 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);
2 голосов
/ 19 марта 2009

Согласно ISO 8601: 1988 , который используется в Швеции , первая неделя года - это первая неделя, на которую в новом году приходится как минимум четыре дня.

Так что, если ваша неделя начинается в понедельник, первый четверг, то любой год находится в пределах первой недели. Вы можете DateAdd или DateDiff из этого.

2 голосов
/ 26 февраля 2014

Вот метод, который совместим с номерами недель, которые использует Google Analytics, а также с той же схемой нумерации, которую мы использовали внутри Intel, и которая, я уверен, также используется во многих других контекстах.

// 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);
}
2 голосов
/ 26 августа 2011

Я пробовал некоторые коды выше, и у некоторых есть небольшие ошибки, когда вы пробуете разные годы с разными начальными днями недели, вы увидите их, я взял код Джона Скита, исправил его, и он работает, очень простой код.

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
2 голосов
/ 29 марта 2013

Это сработало для меня, у него также есть преимущество в том, что в качестве параметра для проверки формулы с различными культурами нужно ожидать информацию о культурах. Если он пуст, он получает информацию о текущей культуре ... допустимые значения такие: "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
...