주 번호에서 날짜 계산


135

누구나 주중 첫날 (유럽의 월요일)을 쉽게 얻을 수있는 방법을 알고 있습니다. 연도와 주 번호를 알고 있습니까? 나는 C #에서 이것을 할 것입니다.


강력하게 관련, 아마도 중복 : stackoverflow.com/questions/659183/…
John Rasch

답변:


251

@RobinAndersson의 수정으로도 @HenkHolterman의 솔루션에 문제가있었습니다.

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;

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

3
나는 여기에 주어진 거의 모든 솔루션을 시도했지만, 이것은 지금 나에게 올바르게 작동하는 유일한 솔루션입니다. 현재는 2012 년 2 월 7 일입니다. 주 nr은 # 6입니다. 이 코드는 2 월 6 일을 주 시작 날짜로 올바르게 지정합니다. 다른 솔루션은 모두 2 월 13 일을 줬는데, 이는 실제로 # 7의 시작일입니다.
HaukurHaf

1
매력처럼 작동합니다. 몇 가지 데이터를 테스트했습니다. pastebin.com/mfx8s1vq 모든 것이 완벽하게 작동합니다! 미카엘 감사합니다!
Mittchel

1
@ RobinWassén-Andersson이 질문을 다음에 다시 검토 한 것이 좋습니다 : D 6 더 많은 투표와 나는 "not"정답 hehe와 묶을 것입니다.
미카엘 스벤슨

2
제안 : 보편적 인 '올바른'답변이 없기 때문에 "ISO8601"을 분석법 이름에 맞게 만드십시오.
Henk Holterman

1
@Muflix 나는 SQL과 날짜 / 달력에 대해 충분히 알지 못하지만 CLR을 수행하면 효과가 있습니다.
Mikael Svenson

36

나는 Henk Holterman이 제공하는 솔루션을 좋아합니다. 그러나 좀 더 독립적 인 문화를 유지하려면 현재 문화에 대한 첫 번째 요일을 가져와야합니다 (항상 월요일은 아닙니다).

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

Calendar와 DateTimeFormatInfo의 확장 방법으로 Mannex에 이것을 추가했습니다. 또한 신용에 대한이 답변을 상호 참조했습니다.
Atif Aziz

1
컴퓨터에서 제대로 작동하지 않습니다. 2010 년 대신 0010 날짜가 표시됩니다. .net 프레임 워크 또는이 기능에 문제가 있는지 모르겠습니다. 어쨌든 좋은 시도 ...
에두아르도 사비에르

6
firstMonday월요일이 아닐 수도있는 잘못된 변수 이름입니다. =)
mflodin

11

업데이트 : .NET Core 3.0 및 .NET Standard 2.1은이 유형과 함께 제공됩니다.

좋은 소식! .NET Core에 추가 되는 풀 요청System.Globalization.ISOWeek 이 병합되었으며 현재 3.0 릴리스로 예정되어 있습니다. 바라지 않는 미래에 다른 .NET 플랫폼으로 전파되기를 바랍니다.

ISOWeek.ToDateTime(int year, int week, DayOfWeek dayOfWeek)방법을 사용하여 이를 계산할 수 있어야합니다 .

소스 코드는 여기에서 찾을 수 있습니다 .


9

가장 쉬운 방법은 해당 연도의 첫 번째 월요일을 찾은 다음 관련 주 수를 추가하는 것입니다. 샘플 코드는 다음과 같습니다. 그것은 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
그러나 올해의 첫 번째 월요일은 전년도의 52 주 53 주에 속할 수 있습니다.
Henk Holterman 2014 년

1
사물을 어떻게 정의하고 싶은가에 달려 있습니다. 불행히도 우리는 여기에 갈 정보가 많지 않습니다 ...하지만 이것이 유용하기를 바랍니다.
Jon Skeet

3

개인적으로 나는 문화 정보를 이용하여 요일을 얻고 문화의 첫 요일로 넘어갑니다. 올바르게 설명하고 있는지 잘 모르겠습니다. 예를 들어 보겠습니다.

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

3

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

스웨덴 에서 사용되는 ISO 8601 : 1988에 따르면 , 첫 번째주는 새해에 최소 4 일이 지난 주입니다.

따라서 주가 월요일에 시작되면 첫 번째 목요일은 첫 주 안에 있습니다. 그로부터 DateAdd 또는 DateDiff를 사용할 수 있습니다.


2

주 번호가 1에서 시작한다고 가정

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

이것은 매주 첫날을 알려줄 것입니다. 나는 그것에 대해 많은 테스트를하지 않았지만 작동하는 것처럼 보입니다. 웹에서 찾은 대부분의 다른 솔루션보다 작은 솔루션이므로 공유하고 싶었습니다.


나쁜 대답. DateTime에는 연도, 월 및 일이 필요한 생성자가 있으므로 DateTime.Parse를 사용할 필요가 없습니다. new DateTime(1,1,YearNumber)
Jamiec

구문 분석을 사용하는 대신 새 DateTime을 작성하도록 코드를 업데이트했습니다. 늦었다. ;)
QuinnG

2

.NET 용 무료 기간 라이브러리 에는 ISO 8601 준수 클래스 Week가 포함됩니다 .

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

2

이것은 나를 위해 일했으며 다른 culture로 수식을 테스트하기 위해 cultureinfo를 매개 변수로 기대할 수 있다는 이점이 있습니다. 비어 있으면 현재 문화권 정보를 가져옵니다. 유효한 값은 "it", "en-us", "fr", ... 등입니다. 트릭은 첫 번째 요일의 주 번호를 빼는 것입니다. 첫 번째 요일이 첫 주 내에 있음을 나타내려면 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

2

다음은 Google 웹 로그 분석의 주 번호와 호환되며 인텔에서 내부적으로 사용한 것과 동일한 번호 체계이며 다른 많은 상황에서도 사용됩니다.

// 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

위의 코드 중 일부를 시도했지만 약간의 실수가 있습니다. 다른 시작 요일로 다른 해를 시도하면 코드를 볼 수 있습니다 .Jon 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

Mikael Svenson 코드가 약간 변경되었습니다. 첫 번째 월요일의 주를 찾았고 주 번호를 적절히 변경했습니다.

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

0

1 주차는 월요일에 시작하여 연중 첫 번째 목요일을 포함하는 주로 정의됩니다.


1
그것은 하나의 정의입니다. 다른 것들도 있습니다.
Henk Holterman

1
ISO 표준은 1 주를 연도의 첫 목요일이있는 주로 정의합니다.
RickardN


0

재정의로 Thomas의 솔루션을 약간 개선했습니다.

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

그렇지 않으면 날짜가 일주일 전이었습니다.

토마스 감사합니다.


0

나는 해결책 중 하나를 사용했지만 일요일을 요일의 첫 번째 날로 간주하기 때문에 잘못된 결과를 얻었습니다.

나는 바꿨다 :

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

그리고 지금 그것은 매력으로 일하고 있습니다.


1
그러나 이것은 OP의 질문에 대답합니까? 1/1 + 고정 일수입니다. 주의 첫날 개념은 없습니다.
Gert Arnold

0

제안 된 솔루션은 완전하지 않습니다-CalendarWeekRule.FirstFullWeek에서만 작동합니다. 다른 유형의 주 규칙은 작동하지 않습니다. 이 테스트 사례를 사용하여 볼 수 있습니다.

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

0

나는 제안 된 솔루션의 정제 된 버전을 만들었고 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;
}

0

이것은 우리가 주어진 연도, 주 번호 및 요일을 계산할 때 내 솔루션입니다.

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

0

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

0

다음 코드를 작성하고 테스트했으며 완벽하게 작동합니다. 누구 든지이 문제에 직면하면 알려주십시오. 나는 최선의 답변을 얻기 위해 질문을 게시했습니다. 누군가 유용하다고 생각할 수도 있습니다.

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

이것은 적어도 많은 유럽 국가들에게는 잘못된 것입니다. GetFirstDateOfWeekByWeekNumber(2020, 29)2020 년 29 주 동안이 결과가 반환 07/20/2020됩니다. 그러나 29 주째 첫날은07/13/2020
Matthias Burger

0

현재 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;
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.