Herkes haftanın ilk gününün tarihini almanın kolay bir yolunu bilir (Pazartesi burada Avrupa'da). Yıl ve hafta sayısını biliyorum. Bunu C # ile yapacağım.
Herkes haftanın ilk gününün tarihini almanın kolay bir yolunu bilir (Pazartesi burada Avrupa'da). Yıl ve hafta sayısını biliyorum. Bunu C # ile yapacağım.
Yanıtlar:
@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);
}
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);
}
firstMonday
Pazartesi olmayabilir bir şey için kötü bir değişken adıdır. =)
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 .
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);
}
}
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;
}
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);
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.
new DateTime(1,1,YearNumber)
.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
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
İş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);
}
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
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;
}
Hafta 1, Pazartesi günü başlayan ve yılın ilk Perşembe gününü içeren hafta olarak tanımlanır.
Her iki yönde de dönüştürmek için buraya bakın: ISO hafta tarihleri hakkındaki Wikipedia makalesi
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.
Çö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.
Ö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);
}
}
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;
}
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);
}
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));
}
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;
}
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
Ş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;
}