Hafta numarasından tarihi hesapla


Yanıtlar:


251

@RobinAndersson tarafından yapılan düzeltmeyle bile @HenkHolterman'ın çözümü ile ilgili sorunlar yaşadım.

ISO 8601 standardını okumak sorunu güzel bir şekilde çözer. İlk Perşembe günü Pazartesi olarak değil hedef olarak kullanın. Aşağıdaki kod 2009 yılının 53. haftasında da geçerli olacaktır.

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
Burada verilen hemen hemen her çözümü denedim, şu anda benim için doğru çalışan tek çözüm bu. Şu anda, 7 Şubat 2012 günü. Nr haftası # 6. Bu kod bana 6 Şubat'ı haftanın başlangıç ​​tarihi olarak veriyor. Diğer çözümlerin hepsi bana 13 Şubat'ı verdi, ki bu aslında 7 numaralı haftanın başlangıç ​​tarihi.
HaukurHaf

1
Bir cazibe gibi çalışır .. birkaç veri test etti: pastebin.com/mfx8s1vq Tüm kusursuz çalışır! Teşekkürler Mikael!
Mittchel

1
@ RobinWassén-Andersson O zaman bu soruyu tekrar gözden geçirdiğiniz iyi bir şey: D 6 oy daha ve ben "değil" doğru cevap hehe ile bağlayacağım.
Mikael Svenson

2
Öneri: Yöntem adının "ISO8601" değerini girin, çünkü evrensel 'doğru' cevap yoktur.
Henk Holterman

1
@Muflix SQL ve bilmek için tarihler / takvimler hakkında yeterince bilgim yok - ancak CLR yapmak işe yarayacak.
Mikael Svenson

36

Henk Holterman'ın sunduğu çözümü seviyorum. Ancak kültürden biraz daha bağımsız olmak için, mevcut kültür için haftanın ilk gününü almanız gerekiyor (her zaman pazartesi değil):

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

Bu Mannex, Calendar ve DateTimeFormatInfo için bir genişletme yöntemi olarak ekledim. Ayrıca kredi için bu cevaba çapraz referans verdim.
Atif Aziz

1
Makinemde düzgün çalışmıyor. 2010 yerine 0010 ile bir tarih gösterir. .Net çerçevesinde veya bu işlevde bir sorun olup olmadığını bilmiyorum. Yine de güzel bir deneme ...
Eduardo Xavier

6
firstMondayPazartesi olmayabilir bir şey için kötü bir değişken adıdır. =)
mflodin

11

GÜNCELLEME : .NET Core 3.0 ve .NET Standard 2.1 bu türle birlikte gönderilmiştir.

İyi haberler! .NET Core'a eklenen bir çekme isteğiSystem.Globalization.ISOWeek yeni birleştirildi ve şu anda 3.0 sürümü için destekleniyor. Umarım çok uzak olmayan bir gelecekte diğer .NET platformlarına da yayılır.

Bunu ISOWeek.ToDateTime(int year, int week, DayOfWeek dayOfWeek)hesaplamak için yöntemi kullanabilmelisiniz .

Kaynak kodu burada bulabilirsiniz .


9

En kolay yol muhtemelen yılın ilk Pazartesi günü bulmak ve daha sonra ilgili hafta sayısını eklemektir. İşte bazı örnek kod. Bu arada, 1'den başlayarak bir hafta sayısını varsayar:

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
Evet, ama yılın ilk pazartesi, bir önceki yılın 52-53. Haftasına ait olabilir.
Henk Holterman

1
Şeyleri nasıl tanımlamak istediğinize bağlıdır. Maalesef burada devam etmek için çok fazla bilgimiz yok ... Bunun faydalı olduğunu umuyorum.
Jon Skeet

3

Kişisel olarak haftanın gününü almak ve kültürün haftanın ilk gününe geçmek için kültür bilgisinden faydalanırım. Düzgün açıklıyor muyum emin değilim, işte bir örnek:

    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

Akıcı DateTime kullanma 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

İsveç'te yılın ilk haftasında kullanılan ISO 8601: 1988'e göre, yeni yıl içinde en az dört günü olan ilk haftadır.

Yani haftanız Pazartesi günü başlarsa, herhangi bir yıl ilk Perşembe ilk hafta içinde olur. Bundan DateAdd veya DateDiff yapabilirsiniz.


2

Hafta sayısının 1'de başladığını varsayarsak

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

Bu size herhangi bir haftadaki ilk günü verecektir. Üzerinde çok fazla test yapmadım, ama işe yarıyor gibi görünüyor. Web'de bulduğum diğerlerinden daha küçük bir çözüm, bu yüzden paylaşmak istedim.


Kötü cevap. DateTime'ın yıl, ay ve gün süren bir yapıcısı olduğundan DateTime.Parse öğesinin kullanılması gerekmez. new DateTime(1,1,YearNumber)
Jamiec

Ayrıştırma kullanmak yerine yeni bir DateTime oluşturmak için kod güncellendi. Geç olmuştu. ;)
QuinnG

2

.NET için ücretsiz Zaman Dönemi Kitaplığı, Haftada ISO 8601 uygunluk sınıfını içerir :

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

2

Bu benim için çalıştı, ayrıca farklı kültürlerle formülü test etmek için parametre olarak bir kültür bilgisi beklemek gibi bir avantaja sahip. Boşsa, geçerli kültür bilgisini alır ... geçerli değerler şöyle: "it", "en-us", "fr", ... ve benzeri. İşin püf noktası, yılın ilk gününün hafta sayısını çıkarmaktır; bu, ilk günün ilk hafta içinde olduğunu belirtmek için 1 olabilir. Bu yardımcı olur umarım.

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

İşte Google Analytics'in hafta sayılarıyla uyumlu bir yöntem ve ayrıca Intel'de dahili olarak kullandığımız aynı numaralandırma şeması ve eminim ki birçok bağlamda da kullanılıyor.

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

Yukarıdaki bazı kodları denedim ve bazılarının küçük hataları var, haftanın farklı başlangıç ​​günleri ile farklı yıllar denediğinizde onları göreceksiniz, Jon Skeet'in kodunu aldım, düzeltin ve işe yarıyor, çok basit bir kod.

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 kodunu biraz değiştirdi. İlk Pazartesi haftasını buldum ve hafta numarasını uygun şekilde değiştirdim.

 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

Hafta 1, Pazartesi günü başlayan ve yılın ilk Perşembe gününü içeren hafta olarak tanımlanır.


1
Bu bir tanım, başkaları da var.
Henk Holterman

1
ISO standardı 1. haftayı, yılın ilk Perşembe günü olan hafta olarak tanımlar.
RickardN


0

Thomas'ın çözümünü bir geçersiz kılma ile biraz geliştirdim:

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

Aksi takdirde tarih bir hafta önceydi.

Teşekkürler Thomas, büyük yardım.


0

Çözümlerden birini kullandım, ancak Pazar gününü haftanın ilk günü saydığı için yanlış sonuçlar verdi.

Değiştim:

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

için:

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

ve şimdi bir cazibe olarak çalışıyor.


1
Fakat bu OP'nin sorusunu cevaplıyor mu? 1/1 artı sabit gün sayısı. Haftanın ilk günü kavramı yok.
Gert Arnold

0

Önerilen çözüm tam değil - sadece CalendarWeekRule.FirstFullWeek için çalışıyor. Diğer haftalık kural türleri çalışmaz. Bu, bu test durumu kullanılarak görülebilir:

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

Ben daha basit ve firstDayOfWeek parametreler önerilen çözümün rafine bir sürümünü yaptık:

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

verilen bir tarihi, hafta numarasını ve haftanın gününü hesaplamak istediğimde bu benim çözümüm.

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

Avrupa'daki birçok ülke için doğru olan Mikael Svensson kodunu basitleştirdim.

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

Aşağıdaki kodu yazıp test ettim ve benim için mükemmel çalışıyor. Birisi bununla sorun yaşarsa lütfen bana bildirin, mümkün olan en iyi cevabı almak için de bir soru gönderdim. Birisi faydalı bulabilir.

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

Bu yanlış - en azından birçok Avrupa ülkesi için. GetFirstDateOfWeekByWeekNumber(2020, 29)2020 yılının 29. haftasında bu geri dönüyor 07/20/2020. Ancak 29. haftanın ilk günü07/13/2020
Matthias Burger

0

Şu anda, ISO 8601week sayılarını doğru şekilde işleyen C # sınıfı yoktur. Bir kültürü başlatabilir, en yakın şeyi arayabilir ve düzeltebilirsiniz, ancak tam hesaplamayı kendiniz yapmak daha iyidir:

    /// <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;
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.