Uzyskać prawidłowy numer tygodnia danej daty

Dużo googlowałem i znalazłem wiele rozwiązań, ale żadne z nich nie podaje poprawnego numeru tygodnia na 2012-12-31. Nawet przykład na MSDN (link) nie powiedzie się.

2012-12-31 jest poniedziałek, dlatego powinien być Tydzień 1, ale każda metoda jaką wypróbowałam daje mi 53. Oto niektóre z metod, które wypróbowałem:

Z biblioteki MDSN:

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

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

Rozwiązanie 2:

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

Rozwiązanie 3:

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

Update

The następująca metoda zwraca 1, gdy data jest 2012-12-31. Innymi słowy, mój problem polegał na tym, że moje metody nie były zgodne z normą 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);
}
Author: Stefano Altieri, 2012-06-22

18 answers

Jak zaznaczono na tej stronie MSDN istnieje niewielka różnica między numeracją tygodnia ISO8601 a numeracją tygodnia. Net.

Aby dowiedzieć się więcej na ten temat, zapoznaj się z tym artykułem na blogu MSDN: "ISO 8601 Week of Year format w Microsoft. Net "

Mówiąc najprościej,. Net pozwala na podział tygodni na lata, podczas gdy norma ISO tego nie robi. W artykule znajduje się również prosta funkcja, aby uzyskać prawidłowy numer tygodnia ISO 8601 dla ostatniego tygodnia roku.

Update następująca metoda zwraca 1 dla 2012-12-31, co jest poprawne w ISO 8601 (np. Niemcy).

// 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);
} 
 333
Author: il_guru,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-23 03:42:30

W ciągu roku może być więcej niż 52 tygodnie. Każdy rok ma 52 pełne tygodnie +1 lub + 2 (rok przestępny) dodatkowe dni. Nadrabiają 53. tydzień.

  • 52 tygodnie * 7 dni = 364 dni.
Więc za każdy rok masz co najmniej jeden dodatkowy dzień. Dwa za lata przestępne. Czy te dodatkowe dni liczone są jako osobne tygodnie?

Ile tygodni jest naprawdę zależy od początkowego dnia tygodnia. Rozważmy to na rok 2012.

  • US (niedziela - > sobota): 52 tygodnie + jeden krótki 2 dniowy tydzień na 2012-12-30 i 2012-12-31. Daje to w sumie 53 tygodnie. Dwa ostatnie dni tego roku (niedziela + poniedziałek) tworzą swój krótki tydzień.

Sprawdź ustawienia bieżącej kultury, aby zobaczyć, czego używa ona jako pierwszego dnia tygodnia.

Jak widzisz, to normalne, że w rezultacie otrzymujesz 53.

  • EUROPA( Poniedziałek - > Niedziela): 2 stycznia (2012-1-2) jest pierwszym poniedziałkiem, więc jest to pierwszy dzień pierwszego tygodnia. Zapytaj numer tygodnia na 1. z Stycznia i dostaniesz z powrotem 52 Jak to jest uważane za część 2011 zeszłego tygodnia.
Możliwe jest nawet 54 tydzień. Dzieje się co 28 lat, gdy 1 stycznia i 31 grudnia są traktowane jako oddzielne tygodnie. To musi być też rok przestępny. Na przykład rok 2000 miał 54 tygodnie. 1 stycznia (sobota) był pierwszym tygodniowym dniem, a 31 grudnia (niedziela) drugim tygodniowym dniem.
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);

Wydruki: Rok: 2012 tydzień: 54

Zmień CalendarWeekRule w powyższym przykładzie do FirstFullWeek lub FirstFourDayWeek i dostaniesz z powrotem 53. Zacznijmy od poniedziałku, bo mamy do czynienia z Niemcami.

Więc tydzień 53 zaczyna się w poniedziałek 2012-12-31, trwa jeden dzień, a następnie się kończy.

53 to prawidłowa odpowiedź. Zmień kulturę na Niemcy, jeśli chcesz spróbować.

CultureInfo cul = CultureInfo.GetCultureInfo("de-DE");
 33
Author: Christophe Geers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-16 09:58:43

Dobre wieści! Po prostu połączono pull request dodanie System.Globalization.ISOWeek do.Net Core i jest obecnie planowane na wydanie 3.0. Mam nadzieję, że w niedalekiej przyszłości rozpowszechni się na inne platformy. NET.

Typ ma następującą sygnaturę, która powinna obejmować większość ISO week potrzeb:

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

Kod źródłowy znajdziesz tutaj .

Aktualizacja : te API zostały również zawarte w wersji 2.1. Net Standard .

 29
Author: khellang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-17 10:32:19

Oto sposób:

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

Najważniejszy jest parametr CalendarWeekRule.

Zobacz tutaj: https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=IT-IT&k=k(System.Globalization.CalendarWeekRule);k(TargetFrameworkMoniker-.NETFramework

 22
Author: daniele3004,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-19 08:59:53

Ponieważ nie wydaje się, że istnieje kultura.Net, która daje prawidłowy numer tygodnia ISO-8601, wolałbym całkowicie ominąć wbudowane określenie tygodnia i wykonać obliczenia ręcznie, zamiast próbować poprawić częściowo poprawny wynik.

Skończyło się na następującej metodzie rozszerzenia:

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

Po Pierwsze, ((int)date.DayOfWeek + 6) % 7) określa liczbę dni tygodnia, 0 = poniedziałek, 6 = niedziela.

date.AddDays(-((int)date.DayOfWeek + 6) % 7) określa datę poniedziałku poprzedzającego żądany tydzień numer.

Trzy dni później jest czwartek docelowy, który określa, w którym roku jest tydzień.

Jeśli podzielisz (zero) liczbę dni w ciągu roku przez siedem (zaokrąglenie w dół), otrzymasz (zero) numer tygodnia w roku.

W c# wyniki obliczeń całkowitych są zaokrąglane w dół.

 13
Author: realbart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-08 09:01:59

W. NET 3.0 i nowszych można użyć ISOWeek.GetWeekOfDate-metoda .

Zauważ, że rok w formacie numeru roku + tygodnia może różnić się od roku DateTime z powodu tygodni, które przekraczają granicę roku.

 6
Author: johh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-26 16:27:00

C# do portu Powershell z powyższego kodu z il_guru :

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
}
 4
Author: Rainer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-07 11:33:39

Oto wersja rozszerzona i zerowa il_guru'S answer.

Rozszerzenie:

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

Nullable:

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

Zastosowania:

new DateTime(2019, 03, 15).GetIso8601WeekOfYear(); //returns 11
((DateTime?) new DateTime(2019, 03, 15)).GetIso8601WeekOfYear(); //returns 11
((DateTime?) null).GetIso8601WeekOfYear(); //returns null
 3
Author: Jogge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-30 07:21:40

Najprostszym sposobem na określenie numeru tygodnia ISO 8601 styl przy użyciu c# I klasy DateTime.

Zapytaj: ile-et-czwartek roku jest czwartkiem tego tygodnia. Odpowiedź równa się poszukiwanemu numerowi tygodnia.

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;
 2
Author: user6887101,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-02 11:28:38
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;
Działa dobrze zarówno dla nas, jak i dla kultur rosyjskich. ISO 8601 też będzie poprawne, bo rosyjski tydzień zaczyna się w poniedziałek.
 1
Author: Donskikh Andrei,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-11 10:10:01

Pytanie brzmi: Jak określić, czy tydzień jest w 2012 czy w 2013? Twoje przypuszczenie, jak sądzę, jest takie, że ponieważ 6 dni tygodnia są w 2013 roku, Ten tydzień powinien być oznaczony jako pierwszy tydzień 2013.

Nie wiem, czy to dobra droga. Tydzień Ten rozpoczął się w 2012 roku (w poniedziałek 31 grudnia), więc powinien być oznaczony jako ostatni tydzień 2012 roku, dlatego powinien być 53. Pierwszy tydzień 2013 roku powinien rozpocząć się w poniedziałek 7.

Teraz poradzisz sobie z konkretnymi przypadek tygodni skrajnych (pierwszy i ostatni tydzień roku) z wykorzystaniem informacji o dniu tygodnia. Wszystko zależy od twojej logiki.

 0
Author: Samy Arous,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-22 11:00:57
  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));      
 0
Author: Imran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-01 06:40:40

Na podstawie odpowiedzi il_guru stworzyłem tę wersję na własne potrzeby, która również zwraca komponent year.

    /// <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);
    }
 0
Author: NKCSS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-05 08:23:20

Te dwie metody pomogą, ponieważ nasz tydzień zaczyna się w poniedziałek

/// <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;
    }
 0
Author: Mnyikka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-21 10:37:35

Jeśli nie masz. NET 5.0, rozszerz klasę DateTime o numer tygodnia.

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);
    }
}
 0
Author: Ronen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-02 08:33:42

W PowerShell 7.x. y: Będziesz potrzebował obu następujących linii kodowych, jeśli potrzebujesz pasującego tygodnia.

[System.Globalization.ISOWeek]::GetWeekOfYear((get-date))
[System.Globalization.ISOWeek]::GetYear((get-date))
 0
Author: B-Art,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-12 11:23:30

Rok ma 52 tygodnie i 1 dzień lub 2 w przypadku roku okrążenia(52 x 7 = 364). 2012-12-31 będzie tydzień 53, tydzień, który będzie miał tylko 2 dni, ponieważ 2012 to rok okrążenia.

 -1
Author: CarlosJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-22 10:54:25
public int GetWeekNumber()
{
   CultureInfo ciCurr = CultureInfo.CurrentCulture;
   int weekNum = ciCurr.Calendar.GetWeekOfYear(DateTime.Now, 
   CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
   return weekNum;
}
 -2
Author: Meghnath Das,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-06 06:11:13