我需要返回给定日期的年份和星期。听起来很简单。但是要正确2012-01-01必须返回2011-52,因为2012年第1周将从1月2日开始。
要查找周,我使用:
GregorianCalendar calw = new GregorianCalendar(GregorianCalendarTypes.Localized);
return calw.GetWeekOfYear(DateTime.Parse("2012-01-01"), CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday).ToString();
此回报52.(正确)
但我怎样才能获得这一年?
编辑:
在此处提供帮助:http://codebetter.com/petervanooijen/2005/09/26/iso-weeknumbers-of-a-date-a-c-implementation/
这似乎有效:
private int weekYear(DateTime fromDate)
{
GregorianCalendar cal = new GregorianCalendar(GregorianCalendarTypes.Localized);
int week = weekNumber(fromDate);
int month = cal.GetMonth(fromDate);
int year = cal.GetYear(fromDate);
//week starts after 31st december
if (week > 50 && month == 1)
year = year - 1;
//week starts before 1st January
if (week < 5 && month == 12)
year = year + 1;
return year;
}
private int weekNumber(DateTime fromDate)
{
// Get jan 1st of the year
DateTime startOfYear = fromDate.AddDays(-fromDate.Day + 1).AddMonths(-fromDate.Month + 1);
// Get dec 31st of the year
DateTime endOfYear = startOfYear.AddYears(1).AddDays(-1);
// ISO 8601 weeks start with Monday
// The first week of a year includes the first Thursday
// DayOfWeek returns 0 for sunday up to 6 for saterday
int[] iso8601Correction = { 6, 7, 8, 9, 10, 4, 5 };
int nds = fromDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek];
int wk = nds / 7;
switch (wk)
{
case 0:
// Return weeknumber of dec 31st of the previous year
return weekNumber(startOfYear.AddDays(-1));
case 53:
// If dec 31st falls before thursday it is week 01 of next year
if (endOfYear.DayOfWeek < DayOfWeek.Thursday)
return 1;
else
return wk;
default: return wk;
}
}
答案 0 :(得分:9)
Noda Time很容易为您处理:
using System;
using NodaTime;
public class Test
{
static void Main()
{
LocalDate date = new LocalDate(2012, 1, 1);
Console.WriteLine($"WeekYear: {date.WeekYear}"); // 2011
Console.WriteLine($"WeekOfWeekYear: {date.WeekOfWeekYear}"); // 52
}
}
using System;
using NodaTime;
using NodaTime.Calendars;
public class Test
{
static void Main()
{
LocalDate date = new LocalDate(2012, 1, 1);
IWeekYearRule rule = WeekYearRules.Iso;
Console.WriteLine($"WeekYear: {rule.GetWeekYear(date)}"); // 2011
Console.WriteLine($"WeekOfWeekYear: {rule.GetWeekOfWeekYear(date)}"); // 52
}
}
那是使用ISO日历系统,其中第一周的第一周开始,同一年至少有4天。 (与CalendarWeekRule.FirstFourDayWeek
类似。)如果您需要其他日历系统,请在LocalDate
构造函数中指定它。在1.x和2.x之间,周年规则的处理方式略有不同。
编辑:请注意,这为这种情况提供了正确的价值(周年少于比日历年)和一年中另一年的情况,其中一周 - 年可以更多比日历年。例如,2012年12月31日是2013年第1周。
让图书馆为你做这件事的美妙之处在于:它的工作就是了解这类事情。您的代码不应该担心它。你应该只能问你想要什么。
答案 1 :(得分:4)
您可以通过这种方式根据CalendarWeekRule
获取周数:
var d = new DateTime(2012, 01, 01);
System.Globalization.CultureInfo cul = System.Globalization.CultureInfo.CurrentCulture;
var firstDayWeek = cul.Calendar.GetWeekOfYear(
d,
System.Globalization.CalendarWeekRule.FirstDay,
DayOfWeek.Monday);
int weekNum = cul.Calendar.GetWeekOfYear(
d,
System.Globalization.CalendarWeekRule.FirstFourDayWeek,
DayOfWeek.Monday);
int year = weekNum >= 52 && d.Month == 1 ? d.Year - 1 : d.Year;
您可能希望将CalendarWeekRule.FirstDay
与CalendarWeekRule.FirstFourDayWeek
进行比较。通过这种方式,您可以获得周数和年份(DateTime.Year-1
,如果它们不同)。
答案 2 :(得分:2)
这只是一个边缘情况,您必须为其添加特殊代码。从日期字符串中获取年份,然后如果周= 52且月份= 1,则从年份中减去一个。
答案 3 :(得分:0)
在我的方法中,我利用了这一事实,GetWeekOfYear()
显示了与同一周的同一年相同年份的正确ISO-8601
周数。所以我查找周四属于同一周的给定日期,然后在其上调用GetWeekOfYear()
。
我无法做到这一点来获得正确的一年,因为没有符合iso8601标准的方法,所以如果星期四属于与给定日期不同的年份,我会进行一年的调整。
解决方案基本上是一个三线程:
using System.Globalization;
namespace TESTS
{
class Program
{
static void Main(string[] args)
{
//sample dates with correct week numbers in comments:
string[] dats = new string[] {
"2011-12-31","2012-01-01" //1152
,"2012-12-31","2013-01-01" //1301
,"2013-12-31","2014-01-01" //1401
,"2014-12-31","2015-01-01" //1501
,"2015-12-31", "2016-01-01" //1553
};
foreach (string str in dats)
{
Console.WriteLine("{0} {1}", str, GetCalendarWeek(DateTime.Parse(str)));
}
Console.ReadKey();
}
public static int GetCalendarWeek(DateTime dat)
{
CultureInfo cult = System.Globalization.CultureInfo.CurrentCulture;
// thursday of the same week as dat.
// value__ for Sunday is 0, so I need (true, not division remainder %) mod function to have values 0..6 for monday..sunday
// If you don't like casting Days to int, use some other method of getting that thursday
DateTime thursday = dat.AddDays(mod((int)DayOfWeek.Thursday-1,7) - mod((int)dat.DayOfWeek-1,7));
//week number for thursday:
int wk = cult.Calendar.GetWeekOfYear(thursday, cult.DateTimeFormat.CalendarWeekRule, cult.DateTimeFormat.FirstDayOfWeek);
// year adjustment - if thursday is in different year than dat, there'll be -1 or +1:
int yr = dat.AddYears(thursday.Year-dat.Year).Year;
// return in yyww format:
return 100 * (yr%100) + wk;
}
// true mod - helper function (-1%7=-1, I need -1 mod 7 = 6):
public static int mod(int x, int m)
{
return (x % m + m) % m;
}
}
答案 4 :(得分:0)
我已经解决了类似的问题,结果应该在&#34; YYYYWW&#34;格式。我想避免硬编码日期和使用第三方库。
我的测试用例是日期1.1.2017,应该返回201652年(Iso YearWeek)
要获得周数,我使用了线程:Get the correct week number of a given date,它返回没有年份的周数。 最后我从星期一(iso周的第一天)到达所需日期的正确年份:
// returns only week number
// from [Get the correct week number of a given date] thread
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
var week = CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return week;
}
// returns int YearWeek in format "YYYYWW"
public static int GetIso8601YearWeekOfYear(DateTime time)
{
var delta = (-((time.DayOfWeek - CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek + 7) % 7));
var firstDayofWeek = time.AddDays(delta); // takeMonday
var week = GetIso8601WeekOfYear(time);
var yearWeek = (firstDayofWeek.Year * 100) + week;
return yearWeek;
}