c# find same range of "named days" from 1 year ago - c#

using c# visual studio 2008.
Can anyone help with an algorithm to do this please
if i have a range of days selected for this week (eg monday to friday) i can find the dates for these using the datetime functions available.
What i want to do is compared to stored data for the same DAY range 1 year ago.
So basicly i need to go back 1 year and find the dates for the nearest Mon to fri DAY range from 1 year previous. I guess i also need to take into acount leap years.
Can anyone help with a suitable algorithm on how to achieve this.
Of course the DAY for todays date last year is not going to be the same day.
thanks in advance

Here's some code which might do what you want - but the test cases show that there are corner cases to consider:
using System;
public class Test
{
static void Main()
{
Console.WriteLine(SameDayLastYear(DateTime.Today));
Console.WriteLine(SameDayLastYear(new DateTime(2010, 12, 31)));
}
static DateTime SameDayLastYear(DateTime original)
{
DateTime sameDate = original.AddYears(-1);
int daysDiff = original.DayOfWeek - sameDate.DayOfWeek;
return sameDate.AddDays(daysDiff);
}
}
What would you want the result for the second call to be? This code returns January 1st 2010, because that's the closest date to "a year ago on the same day".
I strongly suggest that whatever you go with, you have unit tests checking leap years, start and end of year etc.

Let's say you select Wednesday 10-02-2010 - Friday 12-02-2010 this year.
Last year that would have been Tuesday 10-02-2009 - Thursday 12-02-2009.
So you can do the following: Go back a year by simply performing DateTime.AddYears(-1). Make sure you correct for leap years here.
Then you use .AddDays(1) until you end up on a Wednesday - Friday timeframe.
That way you only have to take leap years into account at one point and this should produce the result you need.

I just subtracted one year then ran backwards until I found a Monday. LastYear will end up being the first Monday before this date last year
DateTime LastYear = DateTime.Now.AddYears(-1)
DayOfWeek Check = LastYear.DayOfWeek;
while (Check != DayOfWeek.Monday)
{
LastYear = LastYear.addDays(-1);
Check = LastYear.DayOfWeek;
}
Console.WriteLine("{0}",LastYear);

DateTime now = DateTime.Now;
DateTime lastyear = now.AddYears(-1);
string dayOfWeek = lastyear.DayOfWeek.ToString();
if (dayOfWeek.Equals("Saturday")) { dayOfWeek = "Friday"; }
else if (dayOfWeek.Equals("Sunday")) { dayOfWeek = "Monday"; }
Console.WriteLine(dayOfWeek);
Console.ReadKey();
Get a datetime object for last year, then use the DayOfWeek property.

This was pretty fun.
// today's info
DateTime today = DateTime.Now;
DayOfWeek today_name = today.DayOfWeek;
// this day one year ago
DateTime year_ago = today - new TimeSpan( ((today.Year - 1) % 4) ? 365 : 366, 0, 0, 0);
// find the closest day to today's info's name
DayOfWeek today_name_a_year_ago = year_ago.DayOfWeek;
DateTime current_range_a_year_ago = year_ago - new TimeSpan( year_ago.DayOfWeek - today_name, 0, 0, 0);
Console.WriteLine( "Today is {0}, {1}", today_name, today);
Console.WriteLine( "One year from today was {0}, {1}", today_name_a_year_ago, year_ago);
Console.WriteLine( "New date range is {0}", current_range_a_year_ago);
I would highly recommend using the unit testing features built into VS2008 to make sure you account for corner cases.

Related

Get same day of same week in last year

I was looking for a way to fetch the same day of the current week as a year ago. For example, today is:
August 10th 2022 - Wednesday.
Assume this is the check-in date, the check-out date I expect to get is:
August 11, 2021 - Wednesday.
Because it's the same day (Wednesday) as last year. But I need to take leap years into account, so I need to see if the current year is a leap year and if it is, if it has passed the 29th of February, the same with the date last year.
How to do this using .net core ? I thought of something like:
private DateTime GetDayOneYearBefore()
{
if(DateTime.IsLeapYear(DateTime.Today.Year) && DateTime.Today.Month > 2){
return DateTime.Today.AddDays(-365);
}
else if(DateTime.IsLeapYear(DateTime.Today.Year) && DateTime.Today.Month <= 2){
return DateTime.Today.AddDays(-364);
}
}
Since you mention the "same week" I suppose you want to get the same day of the week in the same week number?
If so, you can do the following:
// In the System.DayOfWeek enum Sunday = 0, while Monday = 1
// This converts DateTime.DayOfWeek to a range where Monday = 0 and Sunday = 6
static int DayOfWeek(DateTime dt)
{
const int weekStart = (int)System.DayOfWeek.Monday;
const int daysInAWeek = 7;
return (daysInAWeek - (weekStart - (int)dt.DayOfWeek)) % daysInAWeek;
}
var calendar = CultureInfo.CurrentCulture.Calendar;
var weekNum = calendar.GetWeekOfYear(DateTime.Today, CalendarWeekRule.FirstFourDayWeek, System.DayOfWeek.Monday);
var todayLastYear = DateTime.Today.AddYears(-1);
var lastYearWeekNum = calendar.GetWeekOfYear(todayLastYear, CalendarWeekRule.FirstFourDayWeek, System.DayOfWeek.Monday);
var sameWeekLastYear = todayLastYear.AddDays(7 * (weekNum - lastYearWeekNum));
var sameDaySameWeekLastYear = sameWeekLastYear.AddDays(DayOfWeek(DateTime.Today) - DayOfWeek(sameWeekLastYear));
As you might notice there's a little convertion method, since I normally work with Monday being the first day of the week. If you prefer a different day to be the first day of the week, simply replace System.DayOfWeek.Monday with which ever day you'd like.
See this fiddle for a test run.

How to determine if now(utc) is within the range of the given days of the week and times of the day in ISO 8601 format

I run into this question of how to determine if DateTime.UtcNow (e.g. 2018-01-01T20:00:00Z) falls within the given range of days and times that are in another timezone. There are no specific dates given, just the days of the week, and the time of the day. The given time is in ISO 8601 standard format.
To simplify this question, it can be how to check if a UTC time is within business hours in China.
For example, the given day and time range is given by someone form China in time zone +08:00, it can be: FromDayOfWeek = "Friday", FromTimeOfDay = "17:00:00+8:00", ToDayOfWeek = "Monday", ToTimeOfWeek = "08:00:00+8:00". I need to determine if "now" in China is sometime between the given range (Friday 17:00:00+8:00 - Monday 08:00:00+8:00).
I'm stuck at how to convert the DateTime and get the day of the week in that local time, since 2018-01-01T20:00:00Z is Monday in UK, but at the same time, since China is +08:00, it is already Tuesday in China.
My approach:
// parse the time to get the zone first (+08:00)
TimeSpan ts = TimeSpan.Parse("-08:00");
// Create a custom time zone since the time zone id is not given, and cannot be searched by SearchTimeZoneById
TimeZoneInfo tzi = TimeZoneInfo.CreateCustomTimeZone(zoneId, ts, displayName, standardName);
DateTime localDateTime = TimeZoneInfo.ConvertTime(Date.UtcNow, tzi);
String localDay = localDateTime.DayOfWeek;
// Determine if localDay is between FromDayOfWeek and ToDayOfWeek
// cast the days to integers from 1 (Monday) to 7 (Sunday)
// create an array of days in integar days = [5, 6, 7, 1]
// if days.contains(localDays), check the times
...
Can anyone suggest some better solutions? I am not sure if mine works, and there are holes in how to deal with Day Light Saving time, since the zone will change, and how to check the time range. I am new to C#, any suggestions of libraries I can use is great!
Instead of converting both start and end times from UTC, just convert the other time into UTC
TimeZoneInfo chinaTimeZone = TimeZoneInfo.CreateCustomTimeZone(zoneID, TimeSpan.Parse("-08:00"), displayName, standardName);
DateTime FromTime = new DateTime(2018, 0, 19, 13, 0, 0); // year, month, day, hour, minute, second : Friday 1pm
DateTime ToTime = new DateTime(2018, 0, 21, 1, 0, 0); // year, month, day, hour, minute, second : Monday 1am
DateTime nowinUTC = DateTime.UtcNow;
DateTime nowInChina = TimeZoneInfo.ConvertTimeFromUtc(nowinUTC, chinaTimeZone);
if(FromTime< nowInChina && ToTime> nowInChina)
{
// Time is within the from and two times
}
Per the comments on #Moffen's answer, you only want to check if Now is within a specific DayOfWeek range:
public void CheckAll(List<SomeClass> spans)
{
var chinaTZ = TimeZoneInfo.CreateCustomTimeZone(zoneID, TimeSpan.Parse("-08:00"), displayName, standardName);
var nowInChina = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, chinaTZ);
foreach ( var span in spans )
{
if (InRange(nowInChina, span.startDay, span.endDay))
// Do something on success
// Check for valid times here
;
else
// Do something on Failure
;
}
}
public bool InRange(DateTime dateToCheck, DayOfWeek startDay, DayOfWeek endDay)
{
// Initialise as one day prior because first action in loop is to increment current
var current = (int)startDay - 1;
do
{
// Move to next day, wrap back to Sunday if went past Saturday
current = (current + 1) % 7;
if (dateToCheck.DayOfWeek == (DayOfWeek)current)
return true;
} while (current != (int)endDay);
return false;
}

Get datetime from given day

user just enter the day of week. For instance user enter friday. I need to find the exact date of given day and format will be like dd.MM.yyyy.
But I don't know how I do it.
Example:
label1 - Friday (entered by user)
label2 - 08.06.2012 (found by system)
label1 is just a string (just Friday). It's coming from webservice as a string variable. I need to find the date and compare with today, If it's not equal or small than today I give date of upcoming Friday, else I give the date of the Friday the week after.
"If it's not equal or small than today I give exact date, else I give next week date. "
Assuming that means that you return always the next date in future with the given day of week, the only exception is when today is the given day of week.
public static DateTime getNextWeekDaysDate(String englWeekDate)
{
var desired = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), englWeekDate);
var current = DateTime.Today.DayOfWeek;
int c = (int)current;
int d = (int)desired;
int n = (7 - c + d);
return DateTime.Today.AddDays((n >= 7) ? n % 7 : n);
}
Let's test:
DateTime Monday = getNextWeekDaysDate("Monday"); // 2012-06-11
DateTime Tuesday = getNextWeekDaysDate("Tuesday"); // 2012-06-05 <-- !!! today
DateTime Wednesday= getNextWeekDaysDate("Wednesday"); // 2012-06-06
DateTime Thursday = getNextWeekDaysDate("Thursday"); // 2012-06-07
DateTime Friday = getNextWeekDaysDate("Friday"); // 2012-06-08
Create enum of days (i.e. monday - 0, tuesday - 1, etc);
Get DateTime.Now DayOfWeek and cast in some way it to your enum value.
Calculate difference between Now.DayOfWeek and user's day of the week;
Use DateTime.AddDays(difference).DayofTheWeek;
get current time with DateTime.now
Current day is DateTime.Now.DayOfWeek
Then get the day of week your user entered
Then your result is DateTime.now.AddDays( NowDayOfWeek - UserDayOfWeek).

Behavior of DateTime.AddYears on leap year

Can anyone explain the mathematical or simply the reasoning behind the leap year calculations in .NET when using AddYears method on DateTime?
If you take the 29th Feb 2012 and add a year, you get the 28th Feb 2013, not the 1st Mar 2013 (day before one year later).
If you add one year to 31st Jan 2012, you get 31st Jan 2013 (same date one year later).
I think most people would assume that "one year from 29.02.leapX is 01.03.leapX+1".
Example:
// Testing with 29th Feb
var now1 = DateTime.Parse("2012-02-29 15:00:00");
var results1 = new DateTime[]
{
now1.AddYears(1),
now1.AddYears(2),
now1.AddYears(3),
now1.AddYears(4)
};
foreach(var dt in results1)
{
Console.WriteLine(dt.ToString("s"));
}
// Output:
// 2013-02-28T15:00:00
// 2014-02-28T15:00:00
// 2015-02-28T15:00:00
// 2016-02-29T15:00:00
// Testing with 31st Jan
var now2 = DateTime.Parse("2012-01-31 13:00:00");
var results2 = new DateTime[]
{
now2.AddYears(1),
now2.AddYears(2),
now2.AddYears(3),
now2.AddYears(4)
};
foreach(var dt in results2)
{
Console.WriteLine(dt.ToString("s"));
}
// Output:
// 2013-01-31T13:00:00
// 2014-01-31T13:00:00
// 2015-01-31T13:00:00
// 2016-01-31T13:00:00
I think most people would assume that "one year from 29.02.leapX is 01.03.leapX+1".
I wouldn't. I would normally expect truncation. It's fundamentally similar to adding one month to January 30th - I'd expect to get the last day in February. In both cases, you're adding a "larger unit" (month or year) and a "smaller unit" (day) is being truncated to fit in with the year/month combination.
(This is how Joda Time and Noda Time behave too, btw.)
As Tim mentioned in comments, it's documented that way too:
The AddYears method calculates the resulting year taking into account leap years. The month and time-of-day part of the resulting DateTime object remains the same as this instance.
So the month has to stay as February; the year will change based on how many years are being added, obviously - so the day has to adjust to stay valid.
With your rationale then 1-Mar-2012 would become 2-Mar-2012 when you added a year. If you add this shift for all prior leap years then you are going to find your calculation massively adrift. The only sensible response is to return 28-Feb for non-leap years.
It is interesting, nether-the-less ..
e.g. this function is sometimes used:
private static int Age(DateTime birthDate, DateTime asAtDate)
{
// Calculate age in years
int age = asAtDate.Year - birthDate.Year;
if (asAtDate < birthDate.AddYears(age)) age--;
if (age < 0) age = 0;
return age;
}
If a person was born on 29Feb2016, this function is going to conclude they have reached age 1 on 28Feb2017.
I noted Excel Function examples as per:
=DATEDIF(DATE(2016,2,28),DATE(2017,2,28),"Y")
gives result of 1
=DATEDIF(DATE(2016,2,29),DATE(2017,2,28),"Y")
gives result of 0
=DATEDIF(DATE(2016,2,29),DATE(2017,3,1),"Y")
gives result of 1
=DATEDIF(DATE(2016,3,1),DATE(2017,3,1),"Y")
gives result of 1

logic for Custom Start Day and End Day for a week. (c#)

We have a unique requirment where we have our own start day of a week and end day of a week(C#),
Contrary to the existing Date Time class whose start day is Sunday and end day is Saturday, we have Wednesday as our start day and Tuesday our EndDay (and this will vary per client).
and we need to implement the following logic
a) for a given date get the start Date of a week and end Date of a week
Ex: based on the above if the current day is 23/Sep/2010 (Thur) we need to get 22/Sep/2010 (Wed) as our Start Day and 28/Sep/2010 (Tue) as our end day
i apologize there is a correction the end day should be Tuesday (7 days a week)
Can anyone help here?
Thanks
Couldn't you just do
(dt.DayOfWeek + delta) % 7
?
Here is my inelegant crack at it:
public static void CalculateWeek (out DateTime WeekStart, out DateTime WeekEnd, DateTime InputDate)
{
DateTime tempDT = InputDate;
while (tempDT.DayOfWeek != DayOfWeek.Wednesday)
{
tempDT = tempDT.AddDays(-1);
}
WeekStart = tempDT.Date;
while (tempDT.DayOfWeek != DayOfWeek.Tuesday)
{
tempDT = tempDT.AddDays(1);
}
WeekEnd = tempDT.Date;
}
By no means clever or superefficient, although the loops will iterate no more than a trivial 7 times.

Categories