简体   繁体   中英

Retrieve date from year, week number, day name in C#

I have fallen a big problem to retrieve date from C# by providing year, week number and day name.

Suppose I have

Year = 2016
Week number = 1
Day Name ='FRI'
First day of week='SUN'

Expected result:

01-01-2016

How can I do that?

There are numerous week numbering schemes. For example, ISO-8601 counts full weeks so 2016-01-01 is Week 53 of 2015. Your expected result though shows that you want to start counting from 1/1, not from the first full week.

You can avoid the hassle by using a library like NodaTime which already supports calculating a date from year, week number and day:

LocalDate date = LocalDate.FromWeekYearWeekAndDay(year, week, IsoDayOfWeek.Monday);

If you don't want to use an external library, the "trick" is to find the first week's starting date, add the specified number of weeks to it and then, add the number of days that corresponds to the targed week day:

var year=2016;
var weekNumber=1;
var dayOfWeek=(int)DayOfWeek.Friday;

//Doesn't really matter when the week starts
var firstDayOfWeek=(int)DayOfWeek.Sunday;

var yearStart=new DateTime(year,1,1);
var firstWeekDate=yearStart.AddDays( firstDayOfWeek -(int)yearStart.DayOfWeek);
//Use Calendar to add the number of weeks
Calendar myCal = CultureInfo.InvariantCulture.Calendar;
var targetDate=myCal.AddWeeks(firstWeekDate,weekNumber-1)
                .AddDays(dayOfWeek - firstDayOfWeek);

The result is 2016-1-1 . For Week 11, the result would be 2016-3-11 .

Simplifying for firstWeekDate the code becomes:

var targetDate=myCal.AddWeeks(yearStart,weekNumber-1)
                    .AddDays(dayOfWeek - (int)yearStart.DayOfWeek);

As a function that would look like:

DateTime FromWeekYearWeekAndDay(int year, int weekNumber, DayOfWeek dayOfWeek,
                                CultureInfo cultureInfo=null)
{
    cultureInfo=cultureInfo??CultureInfo.InvariantCulture;
    Calendar myCal = cultureInfo.Calendar;

    var yearStart=new DateTime(year,1,1);
    var targetDate=myCal.AddWeeks(yearStart,weekNumber-1)
                    .AddDays((int)dayOfWeek - (int)yearStart.DayOfWeek);

     return targetDate;
}

The final part is parsing the day name. If you use a full English day name, you could use Enum.Parse :

var dayOfWeek=(int)Enum.Parse(typeof(DayOfWeek),"Friday");

For abbreviations, you can retrieve the list of date abbreviations from a CultureInfo's DateTimeFormat.AbbreviatedDayNames property. The index position of an abbreviation corresponds to its DayOfWeek value.

To make lookups easier, you can convert this list to a dictionary:

var abbreviations=CultureInfo.InvariantCulture.DateTimeFormat.AbbreviatedDayNames;
var dayDict=abbreviations.Select((name,idx)=>new{name,idx})
                         .ToDictionary(l=>l.name,
                                       l=>(DayOfWeek)l.idx,
                                       StringComparer.InvariantCultureIgnoreCase);
var dayOfWeek= dayDict["FRI"];

In the end, you could find the targe date with the following code:

var dayOfWeek=dayDict["FRI"];
var targetDate=FromWeekYearWeekAndDay(2016,1,dayOfWeek);
//2016-01-01

or

var targetDate=FromWeekYearWeekAndDay(2016,11,dayOfWeek);
//2016-3-11

OK, assuming you want weekday X in year Y, in week W.

public static DateTime FirstDateOfWeekISO8601(int year, int weekOfYear)
{
    DateTime jan1 = new DateTime(year, 1, 1);
    int daysOffset = DayOfWeek.Thursday - jan1.DayOfWeek;

    DateTime firstThursday = jan1.AddDays(daysOffset);
    var cal = CultureInfo.CurrentCulture.Calendar;
    int firstWeek = cal.GetWeekOfYear(firstThursday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);

    var weekNum = weekOfYear;
    if (firstWeek <= 1)
    {
        weekNum -= 1;
    }
    var result = firstThursday.AddDays(weekNum * 7);
    return result.AddDays(-3);
}

Now you have the first day of week W. Now you use

DateTime input = FirstDateOfWeekISO8601(y, w);
input.DayOfWeek

This gets you the day of the week on day 0. Now you can loop with input.AddDays(1) until you have the day you search.

say

for(int i = 0; i < 7; ++i)
{
    if(input.AddDays(i).DayOfWeek == "here you need to the number from X which you passs as a string")
}

Or you can subtract the two dayofweek values, but in that case you'll need to correctly handle negative values, since the first day of week w doesn't have to be a monday.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM