Ada yang tahu cara mudah untuk mendapatkan tanggal hari pertama dalam seminggu (senin di sini di Eropa). Saya tahu tahun dan nomor minggu? Saya akan melakukan ini di C #.
Ada yang tahu cara mudah untuk mendapatkan tanggal hari pertama dalam seminggu (senin di sini di Eropa). Saya tahu tahun dan nomor minggu? Saya akan melakukan ini di C #.
Jawaban:
Saya memiliki masalah dengan solusi oleh @HenkHolterman bahkan dengan perbaikan oleh @RobinAndersson.
Membaca tentang standar ISO 8601 menyelesaikan masalah dengan baik. Gunakan hari Kamis pertama sebagai target dan bukan hari Senin. Kode di bawah ini juga akan berfungsi untuk Minggu 53 tahun 2009.
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);
}
Saya suka solusi yang diberikan oleh Henk Holterman. Tetapi untuk menjadi budaya yang lebih mandiri, Anda harus mendapatkan hari pertama dalam seminggu untuk budaya saat ini (tidak selalu hari Senin):
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
adalah nama variabel yang buruk untuk sesuatu yang mungkin bukan hari Senin. =)
UPDATE : .NET Core 3.0 dan .NET Standard 2.1 telah dikirimkan dengan tipe ini.
Kabar baik! Sebuah permintaan tarik menambahkan System.Globalization.ISOWeek
ke NET Core hanya bergabung dan saat ini dijadwalkan untuk rilis 3.0. Mudah-mudahan ini akan menyebar ke platform .NET lainnya dalam waktu yang tidak terlalu lama.
Anda harus bisa menggunakan ISOWeek.ToDateTime(int year, int week, DayOfWeek dayOfWeek)
metode untuk menghitung ini.
Anda dapat menemukan kode sumbernya di sini .
Cara termudah mungkin adalah menemukan hari Senin pertama dalam setahun, dan kemudian menambahkan jumlah minggu yang relevan. Berikut beberapa contoh kode. Ini mengasumsikan angka minggu mulai dari 1, dengan cara:
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);
}
}
Secara pribadi, saya akan memanfaatkan info budaya untuk mengetahui hari dalam seminggu dan kembali ke hari pertama budaya dalam seminggu. Saya tidak yakin apakah saya menjelaskannya dengan benar, berikut ini contohnya:
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;
}
menggunakan 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);
Menurut ISO 8601: 1988 yang digunakan di Swedia , minggu pertama dalam setahun adalah minggu pertama yang memiliki setidaknya empat hari dalam tahun baru.
Jadi, jika minggu Anda dimulai pada hari Senin, Kamis pertama setiap tahun dalam minggu pertama. Anda dapat DateAdd atau DateDiff dari itu.
Dengan asumsi angka minggu dimulai dari 1
DateTime dt = new DateTime(YearNumber, 1, 1).AddDays((WeekNumber - 1) * 7 - (WeekNumber == 1 ? 0 : 1));
return dt.AddDays(-(int)dt.DayOfWeek);
Ini akan memberi Anda hari pertama dalam minggu tertentu. Saya belum melakukan banyak pengujian, tapi sepertinya berhasil. Ini solusi yang lebih kecil daripada kebanyakan solusi lain yang saya temukan di web, jadi saya ingin berbagi.
new DateTime(1,1,YearNumber)
Perpustakaan Periode Waktu gratis untuk .NET menyertakan kelas sesuai ISO 8601 Minggu :
// ----------------------------------------------------------------------
public static DateTime GetFirstDayOfWeek( int year, int weekOfYear )
{
return new Week( year, weekOfYear ).FirstDayStart;
} // GetFirstDayOfWeek
Yang ini berhasil untuk saya, itu juga memiliki keuntungan dengan mengharapkan cultureinfo sebagai parameter untuk menguji formula dengan budaya yang berbeda. Jika kosong, ia mendapat info budaya saat ini ... nilai yang valid seperti: "it", "en-us", "fr", ... dan seterusnya. Triknya adalah dengan mengurangi angka minggu dari hari pertama tahun itu, yang mungkin 1 untuk menunjukkan bahwa hari pertama adalah dalam minggu pertama. Semoga ini membantu.
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
Berikut adalah metode yang kompatibel dengan angka minggu yang Google Analytics, dan juga skema penomoran yang sama yang kami gunakan secara internal di Intel, dan yang saya yakin juga digunakan dalam banyak konteks lain.
// 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);
}
Saya mencoba beberapa kode di atas dan beberapa memiliki kesalahan kecil, ketika Anda mencoba tahun yang berbeda dengan hari awal yang berbeda dalam seminggu Anda akan melihatnya, saya mengambil kode Jon Skeet, memperbaikinya dan berfungsi, kode yang sangat sederhana.
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
Sedikit mengubah kode Mikael Svenson. Saya menemukan minggu pada hari Senin pertama dan mengubah nomor minggu dengan tepat.
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;
}
Minggu 1 didefinisikan sebagai minggu yang dimulai pada hari Senin dan berisi hari Kamis pertama dalam setahun.
Untuk mengonversi di kedua arah, lihat di sini: Artikel Wikipedia tentang tanggal minggu ISO
Saya sedikit meningkatkan solusi Thomas dengan penggantian:
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;
}
*/
Jika tidak, tanggal tersebut sebelumnya satu minggu ..
Terima kasih Thomas, bantuan besar.
Saya menggunakan salah satu solusi tetapi memberi saya hasil yang salah, hanya karena menghitung hari Minggu sebagai hari pertama dalam seminggu.
Aku berubah:
var firstDay = new DateTime(DateTime.Now.Year, 1, 1).AddDays((weekNumber - 1) * 7);
var lastDay = firstDay.AddDays(6);
untuk:
var lastDay = new DateTime(DateTime.Now.Year, 1, 1).AddDays((weekNumber) * 7);
var firstDay = lastDay.AddDays(-6);
dan sekarang berfungsi sebagai pesona.
Solusi yang diusulkan tidak lengkap - ini hanya berfungsi untuk CalendarWeekRule.FirstFullWeek. Jenis aturan minggu lainnya tidak berfungsi. Ini dapat dilihat dengan menggunakan test case ini:
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);
}
}
Saya telah membuat versi perbaikan dari solusi yang diusulkan yang lebih sederhana dan parameter 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;
}
ini adalah solusi saya ketika kita ingin menghitung tanggal tahun tertentu, nomor minggu dan hari dalam seminggu.
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);
}
Saya menyederhanakan kode yang disediakan Mikael Svensson yang benar untuk banyak negara di Eropa.
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));
}
Saya telah menulis dan menguji kode berikut dan bekerja dengan baik untuk saya. Tolong beri tahu saya jika ada yang menghadapi masalah dengan ini, saya telah memposting pertanyaan juga untuk mendapatkan jawaban terbaik. Seseorang mungkin merasa berguna.
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)
untuk Minggu 29 tahun 2020 ini kembali 07/20/2020
. Tapi hari pertama minggu ke-29 adalah07/13/2020
Saat ini, tidak ada kelas C # yang menangani nomor ISO 8601week dengan benar. Meskipun Anda dapat membuat contoh suatu budaya, mencari yang paling dekat dan memperbaikinya, saya pikir lebih baik melakukan perhitungan lengkap sendiri:
/// <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;
}