Bất cứ ai cũng biết một cách dễ dàng để có được ngày của ngày đầu tiên trong tuần (thứ hai ở đây tại châu Âu). Tôi biết số năm và số tuần? Tôi sẽ làm điều này trong C #.
Bất cứ ai cũng biết một cách dễ dàng để có được ngày của ngày đầu tiên trong tuần (thứ hai ở đây tại châu Âu). Tôi biết số năm và số tuần? Tôi sẽ làm điều này trong C #.
Câu trả lời:
Tôi đã gặp vấn đề với giải pháp của @HenkHolterman ngay cả với bản sửa lỗi của @RobinAndersson.
Đọc lên tiêu chuẩn ISO 8601 giải quyết vấn đề độc đáo. Sử dụng thứ Năm đầu tiên làm mục tiêu và không phải thứ Hai. Mã dưới đây cũng sẽ hoạt động cho Tuần 53 năm 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);
}
Tôi thích giải pháp được cung cấp bởi Henk Holterman. Nhưng để độc lập hơn một chút về văn hóa, bạn phải có được ngày đầu tuần cho văn hóa hiện tại (không phải lúc nào cũng là thứ hai):
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
là một tên biến xấu cho một cái gì đó có thể không phải là thứ Hai. =)
CẬP NHẬT : .NET Core 3.0 và .NET Standard 2.1 đã xuất xưởng với loại này.
Tin tốt! Một yêu cầu kéo thêmSystem.Globalization.ISOWeek
vào .NET Core vừa được hợp nhất và hiện đang được dự kiến phát hành 3.0. Hy vọng rằng nó sẽ lan truyền đến các nền tảng .NET khác trong một tương lai không xa.
Bạn sẽ có thể sử dụng ISOWeek.ToDateTime(int year, int week, DayOfWeek dayOfWeek)
phương pháp để tính toán này.
Bạn có thể tìm thấy mã nguồn ở đây .
Cách dễ nhất có lẽ là tìm thứ Hai đầu tiên của năm, sau đó thêm số tuần có liên quan. Đây là một số mã mẫu. Nó giả sử số tuần bắt đầu từ 1, nhân tiện:
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);
}
}
Cá nhân tôi sẽ tận dụng thông tin văn hóa để có được ngày trong tuần và lặp lại ngày đầu tiên của văn hóa. Tôi không chắc liệu tôi có giải thích đúng không, đây là một ví dụ:
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;
}
sử dụng 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);
Giả sử số tuần bắt đầu từ 1
DateTime dt = new DateTime(YearNumber, 1, 1).AddDays((WeekNumber - 1) * 7 - (WeekNumber == 1 ? 0 : 1));
return dt.AddDays(-(int)dt.DayOfWeek);
Điều này sẽ cung cấp cho bạn ngày đầu tiên trong bất kỳ tuần nào. Tôi đã không thực hiện nhiều thử nghiệm về nó, nhưng có vẻ như nó hoạt động. Đó là giải pháp nhỏ hơn hầu hết các giải pháp khác mà tôi tìm thấy trên web, vì vậy muốn chia sẻ.
new DateTime(1,1,YearNumber)
Thư viện khoảng thời gian miễn phí cho .NET bao gồm Tuần lớp phù hợp ISO 8601 :
// ----------------------------------------------------------------------
public static DateTime GetFirstDayOfWeek( int year, int weekOfYear )
{
return new Week( year, weekOfYear ).FirstDayStart;
} // GetFirstDayOfWeek
Điều này làm việc cho tôi, nó cũng có lợi thế khi mong đợi một văn hóa làm thông số để kiểm tra công thức với các nền văn hóa khác nhau. Nếu trống, nó nhận được thông tin văn hóa hiện tại ... các giá trị hợp lệ như: "nó", "en-us", "fr", ... và cứ thế. Bí quyết là trừ đi số tuần của ngày đầu tiên của năm, có thể là 1 để chỉ ra rằng ngày đầu tiên nằm trong tuần đầu tiên. Hi vọng điêu nay co ich.
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
Đây là một phương pháp tương thích với các số tuần mà Google Analytics và cũng là sơ đồ đánh số tương tự mà chúng tôi đã sử dụng trong Intel và tôi chắc chắn cũng được sử dụng trong nhiều bối cảnh khác.
// 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);
}
Tôi đã thử một số mã ở trên và một số có lỗi nhỏ, khi bạn thử các năm khác nhau với các ngày bắt đầu khác nhau trong tuần bạn sẽ thấy chúng, tôi đã lấy mã của Jon Skeet, sửa nó và nó hoạt động, mã rất đơn giản.
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
Thay đổi nhẹ mã Mikael Svenson. Tôi tìm thấy tuần của thứ hai đầu tiên và thay đổi số tuần thích hợp.
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;
}
Tuần 1 được định nghĩa là tuần bắt đầu vào thứ Hai và chứa thứ Năm đầu tiên của năm.
Để chuyển đổi theo cả hai hướng, xem tại đây: Bài viết Wikipedia về ngày trong tuần ISO
Tôi đã cải thiện một chút về giải pháp của Thomas bằng cách ghi đè:
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;
}
*/
Nếu không thì ngày trước một tuần ..
Cảm ơn Thomas, giúp đỡ rất nhiều.
Tôi đã sử dụng một trong những giải pháp nhưng nó cho tôi kết quả sai, đơn giản vì nó tính Chủ nhật là ngày đầu tuần.
Tôi đã thay đổi:
var firstDay = new DateTime(DateTime.Now.Year, 1, 1).AddDays((weekNumber - 1) * 7);
var lastDay = firstDay.AddDays(6);
đến:
var lastDay = new DateTime(DateTime.Now.Year, 1, 1).AddDays((weekNumber) * 7);
var firstDay = lastDay.AddDays(-6);
và bây giờ nó đang làm việc như một lá bùa.
Giải pháp đề xuất chưa hoàn tất - nó chỉ hoạt động cho CalendarWeekRule.FirstFullWeek. Các loại quy tắc tuần khác không hoạt động. Điều này có thể được nhìn thấy bằng cách sử dụng trường hợp thử nghiệm này:
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);
}
}
Tôi đã thực hiện một phiên bản tinh chỉnh của giải pháp được đề xuất đơn giản hơn và tham số hóa đầu tiênDayOfWeek:
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;
}
đây là giải pháp của tôi khi chúng tôi muốn tính một ngày nhất định, số tuần và ngày trong tuần.
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);
}
Tôi đã đơn giản hóa mã Mikael Svensson cung cấp chính xác cho nhiều quốc gia ở châu Âu.
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));
}
Tôi đã viết và kiểm tra mã sau đây và đang làm việc hoàn toàn tốt cho tôi. Xin vui lòng cho tôi biết nếu có ai gặp rắc rối với điều này, tôi cũng đã đăng một câu hỏi để có được câu trả lời tốt nhất có thể. Ai đó có thể thấy nó hữu ích.
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)
cho tuần 29 năm 2020 này trở lại 07/20/2020
. Nhưng ngày đầu tiên của tuần thứ 29 là07/13/2020
Hiện tại, không có lớp C # nào xử lý chính xác các số ISO 8601week. Mặc dù bạn có thể khởi tạo một nền văn hóa, hãy tìm thứ gần nhất và sửa nó, tôi nghĩ tốt hơn là tự mình thực hiện phép tính hoàn chỉnh:
/// <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;
}