programing

지정된 날짜의 올바른 주 번호 가져오기

showcode 2023. 5. 20. 11:01
반응형

지정된 날짜의 올바른 주 번호 가져오기

저는 많은 구글 검색을 했고 많은 해결책을 찾았지만, 그 중 어느 것도 2012-12-31에 대한 정확한 주 번호를 알려주지 않았습니다.MSDN(링크)의 예제도 실패합니다.

2012-12-31은 월요일이므로 1주차가 되어야 하지만 제가 시도한 모든 방법은 저에게 53을 줍니다.제가 시도한 몇 가지 방법은 다음과 같습니다.

MDSN 라이브러리에서:

DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
Calendar cal = dfi.Calendar;

return cal.GetWeekOfYear(date, dfi.CalendarWeekRule, dfi.FirstDayOfWeek);

솔루션 2:

return new GregorianCalendar(GregorianCalendarTypes.Localized).GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);

솔루션 3:

CultureInfo ciCurr = CultureInfo.CurrentCulture;
int weekNum = ciCurr.Calendar.GetWeekOfYear(dtPassed, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return weekNum;

갱신하다

다음 방법은 실제로 날짜가 2012-12-31인 경우 1을 반환합니다.다시 말해서, 제 문제는 제 방법이 ISO-8601 표준을 따르지 않는다는 것이었습니다.

// This presumes that weeks start with Monday.
// Week 1 is the 1st week of the year with a Thursday in it.
public static int GetIso8601WeekOfYear(DateTime time)
{
    // Seriously cheat.  If its Monday, Tuesday or Wednesday, then it'll 
    // be the same week# as whatever Thursday, Friday or Saturday are,
    // and we always get those right
    DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
    if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
    {
        time = time.AddDays(3);
    }

    // Return the week of our adjusted day
    return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}

MSDN 페이지에서 언급한 바와 같이 ISO8601주와 사이에는 약간의 차이가 있습니다.순 주 번호 매기기.

MSDN 블로그의 이 기사를 참조하여 더 나은 설명을 얻을 수 있습니다. "Microsoft의 ISO 8601 Week of Year 형식입니다.네트"

간단히 말해서, .순으로 몇 주를 몇 년에 걸쳐 분할할 수 있는 반면 ISO 표준은 그렇지 않습니다.이 문서에는 해당 연도의 마지막 주에 대한 올바른 ISO 8601 주 번호를 얻을 수 있는 간단한 기능도 있습니다.

업데이트 다음 방법은 실제로 다음에 대해 1을 반환합니다.2012-12-31이는 ISO 8601(예: 독일)에서 정확합니다.

// This presumes that weeks start with Monday.
// Week 1 is the 1st week of the year with a Thursday in it.
public static int GetIso8601WeekOfYear(DateTime time)
{
    // Seriously cheat.  If its Monday, Tuesday or Wednesday, then it'll 
    // be the same week# as whatever Thursday, Friday or Saturday are,
    // and we always get those right
    DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
    if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
    {
        time = time.AddDays(3);
    }

    // Return the week of our adjusted day
    return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
} 

좋은 소식!꺼내기 요청 추가System.Globalization.ISOWeek 3.NET Core로 통합되었으며 현재 3.0 릴리스로 예정되어 있습니다.가까운 미래에 다른 .NET 플랫폼에 전파되기를 바랍니다.

이 유형에는 대부분의 ISO 주 요구 사항을 충족하는 다음과 같은 서명이 있습니다.

namespace System.Globalization
{
    public static class ISOWeek
    {
        public static int GetWeekOfYear(DateTime date);
        public static int GetWeeksInYear(int year);
        public static int GetYear(DateTime date);
        public static DateTime GetYearEnd(int year);
        public static DateTime GetYearStart(int year);
        public static DateTime ToDateTime(int year, int week, DayOfWeek dayOfWeek);
    }
}

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

업데이트: 이러한 API는 .NET Standard 2.1 버전에도 포함되어 있습니다.

1년에 52주 이상 있을 수 있습니다.매년 52주 + 1일 또는 +2일(윤년)이 추가됩니다.그들은 53주째를 차지합니다.

  • 52주 * 7일 = 364일.

그래서 여러분은 매년 하루에 적어도 하나를 더 갖게 됩니다.윤년을 위해 두 번.이 여분의 날들은 그들 자신의 다른 주들로 계산됩니까?

실제로 몇 주가 있는지는 한 주의 시작 날짜에 따라 달라집니다.2012년에 이를 고려해 보겠습니다.

  • 미국(일요일 -> 토요일): 2012-12-30 및 2012-12-31의 경우 52주 + 짧은 2일 주.이렇게 하면 총 53주가 됩니다.올해의 마지막 이틀(일요일 + 월요일)은 그들만의 짧은 한 주를 구성합니다.

현재 Culture의 설정을 확인하여 첫 번째 요일로 무엇을 사용하는지 확인합니다.

보시다시피 결과적으로 53점을 얻는 것은 정상입니다.

  • 유럽(월요일 -> 일요일):1월 2dn(2012-1-2)이 첫 번째 월요일이기 때문에 첫 번째 주의 첫 번째 날입니다.1월 1일의 주 번호를 물어보시면 2011년 1월 1일이 지난 주의 일부이기 때문에 52번을 돌려받을 수 있습니다.

54주차도 가능합니다.1월 1일과 12월 31일을 별개의 주로 취급할 때 28년마다 발생합니다.올해도 윤년이겠네요.

예를 들어, 2000년에는 54주가 있었습니다.1월 1일(토)은 첫째 주, 12월 31일(일)은 둘째 주였습니다.

var d = new DateTime(2012, 12, 31);
CultureInfo cul = CultureInfo.CurrentCulture;

var firstDayWeek = cul.Calendar.GetWeekOfYear(
    d,
    CalendarWeekRule.FirstDay,
    DayOfWeek.Monday);

int weekNum = cul.Calendar.GetWeekOfYear(
    d,
    CalendarWeekRule.FirstDay,
    DayOfWeek.Monday);

int year = weekNum == 52 && d.Month == 1 ? d.Year - 1 : d.Year;
Console.WriteLine("Year: {0} Week: {1}", year, weekNum);

출력: 연도: 2012 주: 54

위의 예에서 CalendarWeekRule을 FirstFullWeek 또는 FirstFourdayWeek로 변경하면 53이 반환됩니다.우리는 독일과 거래하고 있기 때문에 시작일을 월요일로 합시다.

따라서 53주차는 2012-12-31 월요일에 시작하여 하루 동안 지속되고 중단됩니다.

53번이 정답입니다.문화를 독일어로 바꾸려면 문화를 바꿔보세요.

CultureInfo cul = CultureInfo.GetCultureInfo("de-DE");

방법은 다음과 같습니다.

public int GetWeekNumber()
{
    CultureInfo ciCurr = CultureInfo.CurrentCulture;
    int weekNum = ciCurr.Calendar.GetWeekOfYear(DateTime.Now, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
    return weekNum;
}

은 가장중것은입니다.CalendarWeekRule매개 변수

다음을 참조하십시오. https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=IT-IT&k=k(System.Globalization.CalendarWeekRule);k(TargetFrameworkMoniker- .NET 프레임워크

A가 없는 것 같아서요.정확한 ISO-8601 주 번호를 산출하는 넷컬처, 저는 부분적으로 정확한 결과를 수정하려고 시도하는 대신에 내장된 주 결정을 완전히 무시하고 수동으로 계산하는 것이 좋습니다.

결국 다음과 같은 확장 방법을 사용하게 되었습니다.

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

은일단.((int)date.DayOfWeek + 6) % 7)평일 번호(0=1987, 6=일요일)를 결정합니다.

date.AddDays(-((int)date.DayOfWeek + 6) % 7)요청한 주 번호 앞의 월요일 날짜를 결정합니다.

3일 후에는 대상 목요일이 되는데, 이 목요일은 한 주가 몇 년도인지를 결정합니다.

해당 연도 내의 (제로 기준) 요일 번호를 7(반올림)으로 나누면 해당 연도의 (제로 기준) 주 번호가 표시됩니다.

c#에서 정수 계산 결과는 암시적으로 반올림됩니다.

.NET 3.0 이상에서는 -Method를 사용할 수 있습니다.

연도의 연도 + 주 번호 형식은 연도와 다를 수 있습니다.DateTime한 해의 경계를 넘는 몇 주 때문에.

Il_guru의 위 코드에서 Powershell 포트로 C#:

function GetWeekOfYear([datetime] $inputDate)
{
   $day = [System.Globalization.CultureInfo]::InvariantCulture.Calendar.GetDayOfWeek($inputDate)
   if (($day -ge [System.DayOfWeek]::Monday) -and ($day -le [System.DayOfWeek]::Wednesday))
   {
      $inputDate = $inputDate.AddDays(3)
   }

   # Return the week of our adjusted day
   $weekofYear = [System.Globalization.CultureInfo]::InvariantCulture.Calendar.GetWeekOfYear($inputDate, [System.Globalization.CalendarWeekRule]::FirstFourDayWeek, [System.DayOfWeek]::Monday)
   return $weekofYear
}

il_guru의 답변에 대한 확장 버전과 null 가능 버전이 있습니다.

확장:

public static int GetIso8601WeekOfYear(this DateTime time)
{
    var day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
    if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
    {
        time = time.AddDays(3);
    }

    return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}

null 가능:

public static int? GetIso8601WeekOfYear(this DateTime? time)
{
    return time?.GetIso8601WeekOfYear();
}

용도:

new DateTime(2019, 03, 15).GetIso8601WeekOfYear(); //returns 11
((DateTime?) new DateTime(2019, 03, 15)).GetIso8601WeekOfYear(); //returns 11
((DateTime?) null).GetIso8601WeekOfYear(); //returns null
var cultureInfo = CultureInfo.CurrentCulture;
var calendar = cultureInfo.Calendar;

var calendarWeekRule = cultureInfo.DateTimeFormat.CalendarWeekRule;
var firstDayOfWeek = cultureInfo.DateTimeFormat.FirstDayOfWeek;
var lastDayOfWeek = cultureInfo.LCID == 1033 //En-us
                    ? DayOfWeek.Saturday
                    : DayOfWeek.Sunday;

var lastDayOfYear = new DateTime(date.Year, 12, 31);

var weekNumber = calendar.GetWeekOfYear(date, calendarWeekRule, firstDayOfWeek);

 //Check if this is the last week in the year and it doesn`t occupy the whole week
return weekNumber == 53 && lastDayOfYear.DayOfWeek != lastDayOfWeek 
       ? 1  
       : weekNumber;

그것은 미국과 러시아 문화 모두에 효과가 있습니다.ISO 8601도 맞을 것입니다. 러시아 주간이 월요일부터 시작되기 때문입니다.

c# 및 DateTime 클래스를 사용하여 주 번호 ISO 8601 스타일을 가장 쉽게 확인할 수 있는 방법입니다.

이것을 물어보십시오. 일년 중 몇 번째 목요일이 이번 주 목요일입니다.정답은 원하는 주 번호와 같습니다.

var dayOfWeek = (int)moment.DayOfWeek;
// Make monday the first day of the week
if (--dayOfWeek < 0)
    dayOfWeek = 6;
// The whole nr of weeks before this thursday plus one is the week number
var weekNumber = (moment.AddDays(3 - dayOfWeek).DayOfYear - 1) / 7 + 1;

PowerShell 7.x.y의 경우: 일치하는 주년이 필요한 경우 다음 두 가지 코드라인이 모두 필요합니다.

[System.Globalization.ISOWeek]::GetWeekOfYear((get-date))
[System.Globalization.ISOWeek]::GetYear((get-date))

글로벌화된 주 번호를 원하는 경우 다른 답변: 여기에도 답변을 게시했습니다.

원래 답변에서:

답변 위에 구축: @bunny4

하지만 모든 사람이 미국에 위치하거나 여러 문화를 지원해야 하는 것은 아닙니다.이 솔루션을 사용하여 문화적으로 정의된 주 규칙 및 첫날 규칙을 지원합니다.예를 들어, 덴마크는 "첫 4일 주간" 규칙을 몇 주 동안, "월요일" 규칙을 첫 번째 요일로 사용합니다.

//for now, take the the current executing thread's Culture
var cultureInfo = Thread.CurrentThread.CurrentCulture;

//let's pick a date
DateTime dt = new DateTime(2020, 12, 21);

DayOfWeek firstDay = cultureInfo.DateTimeFormat.FirstDayOfWeek;
CalendarWeekRule weekRule = cultureInfo.DateTimeFormat.CalendarWeekRule;
Calendar cal = cultureInfo.Calendar;
int week = cal.GetWeekOfYear(dt, weekRule, firstDay);

.NET 5.0이 없는 경우 DateTime 클래스를 주 번호를 포함하도록 확장합니다.

public static class Extension {
    public static int Week(this DateTime date) {
        var day = (int)CultureInfo.CurrentCulture.Calendar.GetDayOfWeek(date);
        return CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(date.AddDays(4 - (day == 0 ? 7 : day)), CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
    }
}

질문은 다음과 같습니다.한 주가 2012년인지 2013년인지 어떻게 정의합니까?아마 6일이 2013년이기 때문에 이번 주를 2013년의 첫 주로 해야 될 것 같습니다.

이것이 옳은 길인지 잘 모르겠습니다.그 주는 2012년(12월 31일 월요일)에 시작되었으므로 2012년의 마지막 주로 표시되어야 하며, 따라서 2012년의 53번째 주가 되어야 합니다.2013년 첫 주는 7일 월요일에 시작해야 합니다.

이제 요일 정보를 사용하여 에지 위크(연의 첫 주와 마지막 주)의 특정 사례를 처리할 수 있습니다.모든 것은 당신의 논리에 달려 있습니다.

  DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
  DateTime date1 = new DateTime(2011, 1, 1);
  Calendar cal = dfi.Calendar;

  Console.WriteLine("{0:d}: Week {1} ({2})", date1, 
                    cal.GetWeekOfYear(date1, dfi.CalendarWeekRule, 
                                      dfi.FirstDayOfWeek),
                    cal.ToString().Substring(cal.ToString().LastIndexOf(".") + 1));      

il_guru님의 답변을 바탕으로 연도 구성 요소도 반환하는 제 자신의 필요에 따라 이 버전을 만들었습니다.

    /// <summary>
    /// This presumes that weeks start with Monday.
    /// Week 1 is the 1st week of the year with a Thursday in it.
    /// </summary>
    /// <param name="time">The date to calculate the weeknumber for.</param>
    /// <returns>The year and weeknumber</returns>
    /// <remarks>
    /// Based on Stack Overflow Answer: https://stackoverflow.com/a/11155102
    /// </remarks>
    public static (short year, byte week) GetIso8601WeekOfYear(DateTime time)
    {
        // Seriously cheat.  If its Monday, Tuesday or Wednesday, then it'll
        // be the same week# as whatever Thursday, Friday or Saturday are,
        // and we always get those right
        DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
        if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
        {
            time = time.AddDays(3);
        }
        // Return the week of our adjusted day
        var week = (byte)CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
        return ((short)(week >= 52 & time.Month == 1 ? time.Year - 1 : time.Year), week);
    }

우리의 한 주가 월요일에 시작한다고 가정하면 이 두 가지 방법이 도움이 될 것입니다.

/// <summary>
    /// Returns the weekId
    /// </summary>
    /// <param name="DateTimeReference"></param>
    /// <returns>Returns the current week id</returns>
    public static DateTime GetDateFromWeek(int WeekReference)
    {
        //365 leap
        int DaysOffset = 0;
        if (WeekReference > 1)
        {
            DaysOffset = 7;
            WeekReference = WeekReference - 1;
        }
        DateTime DT = new DateTime(DateTime.Now.Year, 1, 1);
        int CurrentYear = DT.Year;
        DateTime SelectedDateTime = DateTime.MinValue;

        while (CurrentYear == DT.Year)
        {
            int TheWeek = WeekReportData.GetWeekId(DT);
            if (TheWeek == WeekReference)
            {
                SelectedDateTime = DT;
                break;
            }
            DT = DT.AddDays(1.0D);
        }

        if (SelectedDateTime == DateTime.MinValue)
        {
            throw new Exception("Please check week");
        }

        return SelectedDateTime.AddDays(DaysOffset);
    }
/// <summary>
    /// Returns the weekId
    /// </summary>
    /// <param name="DateTimeReference"></param>
    /// <returns>Returns the current week id</returns>
    public static int GetWeekId(DateTime DateTimeReference)
    {
        CultureInfo ciCurr = CultureInfo.InvariantCulture;
        int weekNum = ciCurr.Calendar.GetWeekOfYear(DateTimeReference,
        CalendarWeekRule.FirstFullWeek, DayOfWeek.Monday);
        return weekNum;
    }

달력 주와 연도의 조합이 필요한 경우(예: 2022년 달력 주 1의 "1/22") 연도 구성 요소가 항상 입력 날짜의 연도와 같지는 않습니다.한 해의 첫 번째 날이 한 해의 마지막 달력 주에 속하기 때문에 주의 4일 이상이 작년에 속하기 때문입니다.따라서 한 해의 마지막 날은 한 해의 최소 4일이 다음 해에 속하는 경우 다음 해의 첫 번째 달력 주에 속합니다.

다음은 @Jogge가 답변에 제공한 확장을 기반으로 한 확장입니다.

public static class DateTimeExtensions
{
    public static int GetIso8601WeekOfYear(this DateTime time)
    {
        var day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
        if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
        {
            time = time.AddDays(3);
        }

        return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek,
            DayOfWeek.Monday);
    }

    public static int? GetIso8601WeekOfYear(this DateTime? time)
    {
        return time?.GetIso8601WeekOfYear();
    }

    public static string GetIso8601WeekAndYearString(this DateTime time)
    {
        var week = time.GetIso8601WeekOfYear();

        var year = time.Month == 1 && week >= 52
            ? time.Year - 1
            : time.Month == 12 && week == 1
                ? time.Year + 1
                : time.Year;

        return $"{week}/{new DateTime(year, 1, 1):yy}";
    }

    public static string GetIso8601WeekAndYearString(this DateTime? time)
    {
        return time?.GetIso8601WeekAndYearString();
    }
}

1년에는 52주가 있고 랩 이어의 경우 1일 또는 2일이 있습니다(52 x 7 = 364).2012-12-31은 53주차가 될 것이며, 2012년이 랩이어이기 때문에 이틀만 있을 수 있는 주입니다.

public int GetWeekNumber()
{
   CultureInfo ciCurr = CultureInfo.CurrentCulture;
   int weekNum = ciCurr.Calendar.GetWeekOfYear(DateTime.Now, 
   CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
   return weekNum;
}

언급URL : https://stackoverflow.com/questions/11154673/get-the-correct-week-number-of-a-given-date

반응형