Reputation: 7248
What i want to do is to create a simple calendar, and I want to find the first day of the first week of a specific month. My calendar is a Monday -> Sunday calendar and the following code works, but as you can see it's not that nice. Anyone have any better idea on how to get the first date in the calendar.
var now = new DateTime(Year, Month, 1);
now = now.AddDays(1-(int)now.DayOfWeek);
now = now.Day > 15 ? now : now.AddDays(-7);
The calendar will end up looking like this:
| < | Jan 2011 | > |
------------------------------------
| Mo | Tu | We | Th | Fr | Sa | Su |
|[27]| 28 | 29 | 30 | 31 | 01 | 02 |
| 03 | 04 | 05 | 06 | 07 | 08 | 09 |
| .. | .. | .. | .. | .. | .. | .. |
| .. | .. | .. | .. | .. | .. | .. |
| 31 | 01 | 02 | 03 | 04 | 05 | 06 |
And in this "image" it's the [27] date that i'm trying to find.
Solution (Found i better/cleaner to loop then calculate):
public DateTime FirstDay()
{
var date = new DateTime(Date.Year, Date.Month, 1);
while (true)
{
if (date.DayOfWeek == DayOfWeek.Monday)
return date;
date = date.AddDays(-1);
}
return date;
}
public DateTime LastDay()
{
var date = new DateTime(Date.Year, Date.Month,
DateTime.DaysInMonth(Date.Year, Date.Month));
while (true)
{
if (date.DayOfWeek == DayOfWeek.Sunday)
return date;
date = date.AddDays(1);
}
return date;
}
/BR Andreas
Upvotes: 14
Views: 6426
Reputation: 11
DateTime start_date = Cal_start_date.SelectedDate;
DateTime end_date = Cal_end_date.SelectedDate;
Dictionary<string, int> dic_week_day = new Dictionary<string, int>();
dic_week_day["Sunday"] = 1;
dic_week_day["Monday"] = 2;
dic_week_day["Tuesday"] = 3;
dic_week_day["Wednesday"] = 4;
dic_week_day["Thursday"] = 5;
dic_week_day["Friday"] = 6;
dic_week_day["Saturday"] = 7;
DateTime first_day = start_date.AddDays(1 - start_date.Day);
int selected_day = dic_week_day[Drp_day_of_week.SelectedValue.ToString()];
string str_html = "";
for (DateTime i = first_day; i <= end_date; i = i.AddMonths(1))
{
int day_of_week = dic_week_day[i.DayOfWeek.ToString()];
DateTime temp_date;
if (day_of_week > selected_day)
{
temp_date = i.AddDays((7 - day_of_week) + selected_day);
}
else
{
temp_date = i.AddDays(selected_day - day_of_week);
}
DateTime last_day_of_month = (temp_date.AddMonths(1)).AddDays(-temp_date.Day);
if (Drp_occurrence.SelectedValue.ToString() == "odd")
{
if (start_date <= temp_date && temp_date <= end_date && temp_date <= last_day_of_month)
{
str_html += "<br />" + temp_date.ToString();
}
DateTime res_date = temp_date.AddDays(14);
if (start_date <= res_date && res_date <= end_date && res_date <= last_day_of_month)
{
str_html += " , " + res_date.ToString();
}
res_date = temp_date.AddDays(28);
if (start_date <= res_date && res_date <= end_date && res_date <= last_day_of_month)
{
str_html += " , " + res_date.ToString();
}
}
else if (Drp_occurrence.SelectedValue.ToString() == "even")
{
DateTime res_date = temp_date.AddDays(7);
if (start_date <= res_date && res_date <= end_date && res_date <= last_day_of_month)
{
str_html += "<br />" + res_date.ToString();
}
res_date = temp_date.AddDays(21);
if (start_date <= res_date && res_date <= end_date && res_date <= last_day_of_month)
{
str_html += " , " + res_date.ToString();
}
}
else
{
int occurrence = Int32.Parse(Drp_occurrence.SelectedValue.ToString());
DateTime res_date = temp_date.AddDays((occurrence - 1) * 7);
if (start_date <= res_date && res_date <= end_date && res_date <= last_day_of_month)
{
str_html += "<br />" + res_date.ToString();
}
}
}
Div_result.InnerHtml = str_html;
Upvotes: 0
Reputation: 3873
I found myself needing to do this quite often, so I created the following extension method.
public static DateTime FirstDateOfCalendarMonth(this DateTime dt, DayOfWeek firstDayOfWeek = DayOfWeek.Sunday)
{
dt = new DateTime(dt.Year, dt.Month, 1);
while (dt.DayOfWeek != firstDayOfWeek){
dt = dt.AddDays(-1);
}
return dt;
}
Use it like this
var firstCalDate = DateTime.Now.FirstDateOfCalendarMonth();
It defaults to Sunday as the first DayOfWeek, but you can pass it whatever DayOfWeek you like, like this:
var firstCalDate = DateTime.Now.FirstDateOfCalendarMonth(DayOfWeek.Monday);
Upvotes: 0
Reputation: 943
I do not like while loops, because they are expensive when used with LINQ
Hope someone else can reuse this code: (if you are in the USA, then just remove [ + 6) % 7)] in two lines)
/// <summary>
/// Expands the month.
/// | < | Jan 2011 | > |
/// ------------------------------------
/// | Mo | Tu | We | Th | Fr | Sa | Su |
/// |[27]| 28 | 29 | 30 | 31 | 01 | 02 |
/// | 03 | 04 | 05 | 06 | 07 | 08 | 09 |
/// | .. | .. | .. | .. | .. | .. | .. |
/// | .. | .. | .. | .. | .. | .. | .. |
/// | 31 | 01 | 02 | 03 | 04 | 05 | 06 |
/// </summary>
/// <param name="start">Some day in the month of interest, the start date is updated to become the date of firstDayInCalendar</param>
/// <returns>The number of days to show. This value is either (28, 35 or 42)</returns>
public static int ExpandMonth(ref DateTime start)
{
DateTime first = new DateTime(start.Year, start.Month, 1);
DateTime last = new DateTime(start.Year, start.Month, DateTime.DaysInMonth(start.Year, start.Month));
start = first.AddDays(-((int)first.DayOfWeek + 6) % 7);
last = last.AddDays(7 - ((int)last.DayOfWeek + 6) % 7);
return last.Subtract(start).Days;
}
//Thomas
Upvotes: 1
Reputation: 4084
UPDATE: Following code has a bug! Use modulo arithmetic, to compensate the circumstance, .NET begins the week on sunday! See other solutions here (without the one with an extra function).
If you need to find the "27" (i.e. the first day for the display of a month) simply use this:
DateTime monthStart = new DateTime(year, month, 1);
DateTime monthDisplayStart = monthStart.AddDays(-((int)monthStart.DayOfWeek - 1));
Upvotes: -1
Reputation: 241611
I would just do this. It is so easy to understand:
var firstDayOfMonth = new DateTime(year, month, 1);
DateTime startOfCalendar =
FirstDayOfWeekOnOrBefore(
firstDayOfMonth,
DayOfWeek.Monday
);
public static DateTime FirstDayOfWeekOnOrBefore(
DateTime date,
DayOfWeek dayOfWeek
) {
while(date.DayOfWeek != dayOfWeek) {
date = date.AddDays(-1);
}
return date;
}
Additionally, if you want to change your calendar to start on something other than Monday, it's trivial now. A solution using modulo arithmetic would not be as maintainable.
Upvotes: 9
Reputation: 108790
You can use modulo to calculate the number of filler days without a conditional statement:
DateTime firstOfMonth=new DateTime(year,month,1);
var weekDay=firstOfMonth.DayOfWeek;
int fillerDays=((int)weekDay+6)%7;
DateTime firstDayInCalendar=firstOfMonth.AddDays(-fillerDays);
Upvotes: 4
Reputation: 38200
You can try this assuming first day ur referring to is Monday
DateTime dt = new DateTime(2011, 2, 2);
Console.WriteLine(dt.AddDays((8 - (int)dt.DayOfWeek) % 7));
Upvotes: 1