Check if a datetime is in same week as other datetime - c#

Let's say I have a list of dates in a table. Now I want to find all rows, which is in the same week as the date provided as an argument.
Let's say I have a table with:
2014-09-11
2014-09-12
2014-09-15
And I give this function the argument 2014-09-09, it has to look from monday->sunday, and realize that 09-11 and 09-12 is part of the week, but not 09-15.
How on earth to solve this?
I have thought on making a check on year, month and weeknumber, but you cannot guarantee that month is the same...
So how do you solve a problem like this?

DxCk's comment is valid. This solution will work even if the first or last week of the year cross two different years:
Check that the first day of the week for both dates fall on the same day.
Here is the code:
private bool DatesAreInTheSameWeek(DateTime date1, DateTime date2)
{
var cal = System.Globalization.DateTimeFormatInfo.CurrentInfo.Calendar;
var d1 = date1.Date.AddDays(-1 * (int)cal.GetDayOfWeek(date1));
var d2 = date2.Date.AddDays(-1 * (int)cal.GetDayOfWeek(date2));
return d1 == d2;
}

why not?
bool AreFallingInSameWeek(DateTime date1, DateTime date2)
{
return date1.AddDays(-(int)date1.DayOfWeek) == date2.AddDays(-(int)date2.DayOfWeek);
}
if you want to use any day other than Sunday as start of the week
bool AreFallingInSameWeek(DateTime date1, DateTime date2, DayOfWeek weekStartsOn)
{
return date1.AddDays(-GetOffsetedDayofWeek(date1.DayOfWeek, (int)weekStartsOn)) == date2.AddDays(-GetOffsetedDayofWeek(date2.DayOfWeek, (int)weekStartsOn));
}
int GetOffsetedDayofWeek(DayOfWeek dayOfWeek, int offsetBy)
{
return (((int)dayOfWeek - offsetBy + 7) % 7)
}

Check the DateTime.Year and Calendar.GetWeekOfYear(DateTime, ...). No need to check for the month.
EDIT: This is wrong but I can't delete it. See #Sparrow's answer below.

Use: public virtual int GetWeekOfYear(DateTime time,CalendarWeekRule rule,DayOfWeek firstDayOfWeek) of Calendar class

My requirement was to find DOBs falling on the current week. Hope this helps with your doubt. Basically the idea behind this code is as follows:
Change the DOB to current year birthday (eg; 24-02-1988 to 24-02-2018(current year).
Add a year, if the brithday week contains both dec and jan
Get the first day of today's week.
Get last day of today's week.
check if the current year birthday falls between first day and last day of today's week.
private bool DatesAreInTheSameWeek(DateTime birthday)
{
if (birthday == DateTime.MinValue)
{
return false;
}
else
{
var birtdayWithCurrentYear = new DateTime(DateTime.Today.Year, birthday.Month, birthday.Day);
if (birthday.Month == 1 && DateTime.Today.Month != 1)
{
birtdayWithCurrentYear = birtdayWithCurrentYear.AddYears(1);
}
DateTime firstDayInWeek = DateTime.Today.Date;
while (firstDayInWeek.DayOfWeek != CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek)
firstDayInWeek = firstDayInWeek.AddDays(-1);var lastDayInWeek = firstDayInWeek.AddDays(7);
return birtdayWithCurrentYear < lastDayInWeek && birtdayWithCurrentYear >= firstDayInWeek;
}
}

Since the accepted answer contains error as #DxCK mentioned in comment, here is my solution for this:
public static class DateExtensions
{
private static void Swap<T>(ref T one, ref T two)
{
var temp = one;
one = two;
two = temp;
}
public static bool IsFromSameWeek(this DateTime first, DateTime second, DayOfWeek firstDayOfWeek = DayOfWeek.Monday)
{
// sort dates
if (first > second)
{
Swap(ref first, ref second);
}
var daysDiff = (second - first).TotalDays;
if (daysDiff >= 7)
{
return false;
}
const int TotalDaysInWeek = 7;
var adjustedDayOfWeekFirst = (int)first.DayOfWeek + (first.DayOfWeek < firstDayOfWeek ? TotalDaysInWeek : 0);
var adjustedDayOfWeekSecond = (int)second.DayOfWeek + (second.DayOfWeek < firstDayOfWeek ? TotalDaysInWeek : 0);
return adjustedDayOfWeekSecond >= adjustedDayOfWeekFirst;
}
}
Also here is link to another correct solution with slightly different approach.

Find start and end dates for the first date's week. Then check if the second date is between those two.
public static bool DateInsideOneWeek(DateTime date1, DateTime date2)
{
DayOfWeek firstDayOfWeek = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
DateTime startDateOfWeek = date1.Date;
while(startDateOfWeek.DayOfWeek != firstWeekDay)
{ startDateOfWeek = startDateOfWeek.AddDays(-1d); }
DateTime endDateOfWeek = startDateOfWeek.AddDays(6d);
return date2 >= startDateOfWeek && date2 <= endDateOfWeek;
}

If you don't want to use the Calendar class you can use this function:
public static int WeekOfYear(DateTime dt)
{
int startDays = 0;
// first day of the year
DateTime firstJanuary = new DateTime(dt.Year, 1, 1);
if (firstJanuary.DayOfWeek == DayOfWeek.Tuesday)
{
startDays = 1;
}
else if (firstJanuary.DayOfWeek == DayOfWeek.Wednesday)
{
startDays = 2;
}
else if (firstJanuary.DayOfWeek == DayOfWeek.Thursday)
{
startDays = 3;
}
else if (firstJanuary.DayOfWeek == DayOfWeek.Friday)
{
startDays = 4;
}
else if (firstJanuary.DayOfWeek == DayOfWeek.Saturday)
{
startDays = 5;
}
else if (firstJanuary.DayOfWeek == DayOfWeek.Sunday)
{
startDays = 6;
}
if (DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek == DayOfWeek.Sunday)
{
startDays++;
startDays = startDays % 7;
}
return ((dt.DayOfYear + startDays - 1) / 7) + 1;
}

Accepted answer doesn't work for a french calendar and when the dates are 03/10/2022 and 09/10/2022.
This worked for me :
public static partial class DateTimeExtensions
{
public static DateTime FirstDayOfWeek(this DateTime dt)
{
var culture = System.Threading.Thread.CurrentThread.CurrentCulture;
var diff = dt.DayOfWeek - culture.DateTimeFormat.FirstDayOfWeek;
if (diff < 0)
{
diff += 7;
}
return dt.AddDays(-diff).Date;
}
public static DateTime LastDayOfWeek(this DateTime dt) =>
dt.FirstDayOfWeek().AddDays(6);
public static DateTime FirstDayOfMonth(this DateTime dt) =>
new DateTime(dt.Year, dt.Month, 1);
public static DateTime LastDayOfMonth(this DateTime dt) =>
dt.FirstDayOfMonth().AddMonths(1).AddDays(-1);
public static DateTime FirstDayOfNextMonth(this DateTime dt) =>
dt.FirstDayOfMonth().AddMonths(1);
public static int GetWeeekNumber(this DateTime dt)
{
CultureInfo culture = System.Threading.Thread.CurrentThread.CurrentCulture;
Calendar myCal = culture.Calendar;
// Gets the DTFI properties required by GetWeekOfYear.
CalendarWeekRule myCWR = culture.DateTimeFormat.CalendarWeekRule;
DayOfWeek myFirstDOW = culture.DateTimeFormat.FirstDayOfWeek;
return myCal.GetWeekOfYear(dt, myCWR, myFirstDOW);
}
public static bool IsInTheSameWeek(this DateTime date1, DateTime date2)
{
return date1.GetWeeekNumber() == date2.GetWeeekNumber();
}
}
Usage :
item.Week.IsInTheSameWeek(Week)

Related

c# Web app How to get no of working days exclude weekends and public holidays

Background information
Just starting out to learn C#, im trying to build a simple web app that calculate the no of working day(s) between 2 dates.
The UI of the web app
The basic logic is when the user input a date (ie 01/05/2018) and click the button.It will calculate the total number of working day (exclude weekends and public holidays).
The problem now is the calculation isnt accurate ie between 23/05/2018 & 31/05/2018 it shows 6, it should be 7 days. And it doesnt take the dates into consideration during calculation
namespace testtest
{
public partial class First : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
//on btn click
protected void Button1_Click(object sender, EventArgs e)
{
string dt = TextBox1.Text;
DateTime dtDDMMYYYY = ParseDate(dt);
string dt2 = TextBox2.Text;
DateTime dtDDMMYYYY2 = ParseDate(dt2);
List<DateTime> list = new List<DateTime> {
DateTime.ParseExact("04/05/2018", "dd/MM/yyyy",
CultureInfo.InvariantCulture) };
DaysLeft(dtDDMMYYYY, dtDDMMYYYY2, true, list);
}
public DateTime ParseDate(string date)
{
DateTimeFormatInfo dateFormatProvider = new DateTimeFormatInfo();
dateFormatProvider.ShortDatePattern = "dd/MM/yyyy";
return DateTime.Parse(date, dateFormatProvider);
}
public int DaysLeft(DateTime startDate, DateTime endDate, Boolean
excludeWeekends, List<DateTime> excludeDates)
{
int count = 0;
for (DateTime index = startDate; index < endDate; index =
index.AddDays(1))
{
if (excludeWeekends && index.DayOfWeek != DayOfWeek.Sunday &&
index.DayOfWeek != DayOfWeek.Saturday)
{
bool excluded = false; ;
for (int i = 0; i < excludeDates.Count; i++)
{
if (index.Date.CompareTo(excludeDates[i].Date) == 0)
{
excluded = true;
break;
}
}
if (!excluded)
{
count++;
}
}
}
result.Text = count.ToString();
return count;
}
}
}
Keep it simple
public int DaysLeft(DateTime startDate, DateTime endDate, Boolean excludeWeekends, List<DateTime> excludeDates) {
int count = 0;
for (DateTime index = startDate; index <= endDate; index = index.AddDays(1)) {
if (excludeWeekends && (index.DayOfWeek == DayOfWeek.Sunday || index.DayOfWeek == DayOfWeek.Saturday))
continue;
if (excludeDates.Contains(index.Date))
continue;
count++;
}
return count;
}
If the date is a weekend and excludeWeekends flagged, continue on to next date, if date is included in excludeDates continue, else count the day.

Calling Get Months between 2 dates C#

I am trying to call the GetMonths() method during the Row_Inserting() method but it shows me an error. Also, how do I copy the value of this method to a variable named Total_Pay?
public override bool Row_Inserting(OrderedDictionary rsold, ref OrderedDictionary rsnew)
{
GetMonths(FROM_DATE, TO_DATE);
return true;
}
public int GetMonths(DateTime FROM_DATE, DateTime TO_DATE)
{
if (FROM_DATE > TO_DATE)
{
throw new Exception("Start Date is greater than the End Date");
}
int months = ((TO_DATE.Year * 12) + TO_DATE.Month) - ((FROM_DATE.Year * 12) + FROM_DATE.Month);
if (TO_DATE.Day >= FROM_DATE.Day)
{
months++;
}
return months;
}
Hope this helps..
public override bool Row_Inserting(OrderedDictionary rsold, ref OrderedDictionary rsnew)
{
int Total_Pay;
DateTime FROM_DATE = DateTime.Parse("02-May-2016"); //Replace with date you need
DateTime TO_DATE = DateTime.Parse("08-May-2016"); //Replace with date you need
Total_Pay = GetMonths(FROM_DATE, TO_DATE);
return true;
}
public int GetMonths(DateTime FROM_DATE, DateTime TO_DATE)
{
if (FROM_DATE > TO_DATE)
{
throw new Exception("Start Date is greater than the End Date");
}
int months = ((TO_DATE.Year * 12) + TO_DATE.Month) - ((FROM_DATE.Year * 12) + FROM_DATE.Month);
if (TO_DATE.Day >= FROM_DATE.Day)
{
months++;
}
return months;
}
And checkout this similar question Link

How to get the 4. Wednesday of the next Month as DateTime?

I need a function which gives me the nth DateTime of the next Month.
For Example: I need the 4th Wednesday of next Month.
My code delivers a wrong Date:
private static DateTime FindNextDay(DayOfWeek dayOfWeek, DateTime fday, Int32 instance)
{
DateTime day = new DateTime(fday.Year, fday.Month, 1, fday.Hour, fday.Minute, fday.Second);
// DateTime day is in this Example= 2014-08.01 11.00 AM
if (instance == 2)
{
day = day.AddDays(7);
}
else if (instance == 3)
{
day = day.AddDays(14);
}
else if (instance == 4) //if the 4th week is requested
{
day = day.AddDays(28); // i add 28 days
}
while (day.DayOfWeek != dayOfWeek)
{
day = day.AddDays(1); // and search the wednesday and return it back
}
return day;
}
Could you show me a better solution?
Something like this..
Get the first day of the next month, keep a count of the number of wednesdays you've encountered adding to it when you find one. Return when the count is 4.
private static DateTime GetFourthWednesday()
{
DateTime firstOfMonth = new DateTime(DateTime.Now.AddMonths(1).Year, DateTime.Now.AddMonths(1).Month, 1);
int count = 0;
while (count < 4)
{
if (firstOfMonth.DayOfWeek == DayOfWeek.Wednesday)
{
count++;
}
if (count == 4)
{
return firstOfMonth;
}
firstOfMonth = firstOfMonth.AddDays(1);
}
return firstOfMonth;
}
Gives 27/08/2014 if run today
Change the last else if to:
else if (instance == 4) //if the 4th week is requested
{
day = day.AddDays(21); // i add 28 days
}
You should add 21 days not 28.
Since because I'm too lazy, I wrote my code like;
DateTime firstDayOfNextMonth = new DateTime(2014, DateTime.Now.Month + 1, 1);
int count = 0;
if (firstDayOfNextMonth.DayOfWeek == DayOfWeek.Wednesday)
count = 1;
while (count != 4)
{
firstDayOfNextMonth = firstDayOfNextMonth.AddDays(1);
if (firstDayOfNextMonth.DayOfWeek == DayOfWeek.Wednesday)
count++;
}
Console.WriteLine(firstDayOfNextMonth);
Basicly, I check if the first day of next month is Wednesday or not, then I iterate my DateTime to found 4. Wednesday in next month.
It is working for today and it prints 27.08.2014 which is fourth Wednesday of next month.
You can write an extension method like;
public static class DateTimeExtensions
{
public static void FindInstanceNextMonth(DateTime Now, DayOfWeek day, int instance)
{
DateTime firstDayOfNextMonth = new DateTime(Now.Year, Now.Month + 1, 1);
int count = 0;
if (firstDayOfNextMonth.DayOfWeek == day)
count = 1;
while (count != instance)
{
firstDayOfNextMonth = firstDayOfNextMonth.AddDays(1);
if (firstDayOfNextMonth.DayOfWeek == day)
count++;
}
Console.WriteLine(firstDayOfNextMonth);
}
}
And call it as;
DateTimeExtensions.FindInstanceNextMonth(DateTime.Now,
DayOfWeek.Wednesday,
4);

Determine time stamp falling between a time range

I need to run a job/scheduler, which should only update records in database it is falling under the specified time range. In my case, the time range is from 3.30 AM to next day 1.30AM. So, with in this time frame the job needs to update the records. In order to get this time interval, I using TimeOfDay() function, but my logic is getting failed, bcoz if the currenttime is say 6.00 Am, then "currentTime <= todaysJob.ENDTIME.Value.TimeOfDay" is returning false. I am using the below code to check
var currentTime = DateTime.Now.TimeOfDay;
if (currentTime > todaysJob.STARTTIME.Value.TimeOfDay &&
currentTime <= todaysJob.ENDTIME.Value.TimeOfDay)
{
// Do logic
}
bool endTomorrow = true;
DateTime taskDate = new DateTime(2012, 08, 31);
TimeSpan Start = new TimeSpan(03, 30, 00);
TimeSpan End = new TimeSpan(01, 30, 00);
DateTime currentTime = DateTime.Now;
bool flag = false;
if (currentTime.TimeOfDay >= Start)
{
if (endTomorrow)
{
flag = currentTime.Date <= taskDate || (currentTime.Date == taskDate.AddDays(1) && currentTime.TimeOfDay < End);
}
else
{
flag = currentTime.TimeOfDay < End;
}
}
if (flag)
{
//do the task
}
EDIT
So I added:
a boolean flag, determining whether the task should end the next day
a datetime variable (taskDate) saying the date of the task
Start and End are equal to todaysJob.STARTTIME and todaysJob.ENDTIME, so you take them from DB as they are.
EDIT
If you could have your job like this:
public class Job
{
public TimeSpan STARTTIME;
public TimeSpan ENDTIME;
public DayOfWeek taskDayOfWeek;
public bool IsEndingTommorow;
public bool IsTomorrow(DayOfWeek d)
{
if (d == DayOfWeek.Sunday)
return taskDayOfWeek == DayOfWeek.Saturday;
else
return d <= taskDayOfWeek;
}
}
then you could
DateTime currentTime = DateTime.Now;
bool flag = false;
if (currentTime.TimeOfDay >= todaysJob.STARTTIME)
{
if (todaysJob.IsEndingTommorow)
{
flag = currentTime.DayOfWeek == todaysJob.taskDayOfWeek || (todaysJob.IsTomorrow(currentTime.DayOfWeek) && currentTime.TimeOfDay < todaysJob.ENDTIME);
}
else
{
flag = currentTime.TimeOfDay < todaysJob.ENDTIME;
}
}
if (flag)
{
//do the task
}
EDIT
I've edited my code another time: added a method to avoid problems with the DayOfWeek enum
You can use the Time Period Library for .NET, to determine, if a moment falls into multiple time periods:
// ----------------------------------------------------------------------
public bool CheckDateBetweenDatesSample()
{
DateTime now = DateTime.Now;
TimePeriodCollection periods = new TimePeriodCollection();
// read periods (Start/end) from database
// ...
periods.Add( new TimeRange( start, end ) );
return periods.HasIntersectionPeriods( now );
} // CheckDateBetweenDatesSample
Try this, its working for me. Correct me if i'm wrong.
TimeSpan timeOfDay = DateTime.Now.TimeOfDay;
TimeSpan startTimeToD = startTime.TimeOfDay;
TimeSpan endTimeToD = endTime.TimeOfDay;
if (timeOfDay > startTimeToD || timeOfDay < endTimeToD )
{
Console.WriteLine("Hello World");
}
timeOfDay = new TimeSpan(2, 30, 00); //testcase
if (timeOfDay > startTimeToD || timeOfDay < endTimeToD )
{
//will never execute.
}
You cannot use TimeOfDay property as it is the absolute distance(elapsed time) from a midpoint(Midnight). What is wrong with using just DateTime for comparison? Comparison operators( < > <= >=) work perfectly fine with DateTime datatype.
For Eg:
DateTime currentTime = DateTime.Now;
DateTime startTime = DateTime.AddMinutes(-50D); //in your case this would be a DT todaysJob.STARTTIME.Value
DateTime endTime = DateTime.AddMinutes(50);// in your case this would be a DT todaysJob.ENDTIME.Value
if(currentTime > startTime && currentTime <= endTime)
{
Console.Write("Works Fine"); //your logic
}

Compare system Day and DateTime

I'm using the code below to compare two Times:
DateTime systemtime = DateTime.Now;
DateTime timestart = Convert.ToDateTime(txtTimestart.Text);
DateTime timeend = Convert.ToDateTime(txtTimeend.Text);
if (systemtime < timestart || systemtime > timeend)
{
MessageBox.Show("not auth.");
}
else
{
MessageBox.Show("auth.");
}
But I also want to compare the current day. For example, if today is Monday or Thursday, the user is authenticated, not if otherwise. How do I do it? Thanks.
DateTime systemtime = DateTime.Now;
if(systemtime.DayOfWeek == DayOfWeek.Monday)
{
...
}
timestart.DayOfWeek will give you values like DayOfWeek.Thursday or DayOfWeek.Friday etc.
See here for documentation and an example: http://msdn.microsoft.com/en-us/library/system.datetime.dayofweek.aspx
The DateTime object will have a property DayOfWeek.
You could just compare the string.
try this
var systemtime = DateTime.Now;
var start = "Monday";
var finish = "Wednesday";
DayOfWeek startDay;
if (!Enum.TryParse<DayOfWeek>(start ,out startDay))
{
//handle parse error
}
DayOfWeek finishDay;
if (!Enum.TryParse<DayOfWeek>(finish, out finishDay))
{
//handle parse error
}
if (systemtime.DayOfWeek < startDay || systemtime.DayOfWeek > finishDay)
{
MessageBox.Show("not auth.");
}
else
{
MessageBox.Show("auth.");
}

Categories

Resources