Year, Month, Days, hours between two dates - c#

I need to find the difference between two dates and show the results
in year,month, day and hour format for e.g 1 year 2 months 6 days and 4 hour.
How can i do this. Day and hour is very simple. but year and month is giving me a hard time.
I need the result to be 100% accurate...we can't assume 30 days per month or 356 per year.
please help Thanks.

The best way to get accurate number of Years, Months and actually also days (because Timespan Days and TotalDays are number of days from between two dates) is to use the AddYears, AddMonths and AddDays method respectively.
I'll create a Class here named DateDiff that will compute the number of Years, Months and Days between two dates. However, I will give you only the code (and algo) for computing Years difference because if you know the Years you will know also how to do the Months and the Days. And of course so that you yourself has something to work on also ;-)
Here's the code:
DateDiff Class:
class DateDiff
{
public DateDiff(DateTime startDate, DateTime endDate)
{
GetYears(startDate, endDate); // Get the Number of Years Difference between two dates
GetMonths(startDate.AddYears(YearsDiff), endDate); // Getting the Number of Months Difference but using the Years difference earlier
GetDays(startDate.AddYears(YearsDiff).AddMonths(MonthsDiff), endDate); // Getting the Number of Days Difference but using Years and Months difference earlier
}
void GetYears(DateTime startDate, DateTime endDate)
{
int Years = 0;
// Traverse until start date parameter is beyond the end date parameter
while (endDate.CompareTo(startDate.AddYears(++Years))>=0) {}
YearsDiff = --Years; // Deduct the extra 1 Year and save to YearsDiff property
}
void GetMonths(DateTime startDate, DateTime endDate)
{
// Provide your own code here
}
void GetDays(DateTime startDate, DateTime endDate)
{
// Provided your own code here
}
public int YearsDiff { get; set; }
public int MonthsDiff { get; set; }
public int DaysDiff { get; set; }
}
You could test the code from the Main like this:
Test the Code:
DateTime date1 = new DateTime(2012, 3, 1, 8, 0, 0);
DateTime date2 = new DateTime(2013, 11, 4, 8, 0, 0);
DateDiff dateDifference = new DateDiff(date1, date2);
Console.WriteLine("Years = {0}, Months = {1}, Days = {2}", dateDifference.DiffYears, dateDifference.DiffMonths, dateDifference.DiffDays);

Look into DateTime: http://msdn.microsoft.com/en-us/library/system.datetime(v=vs.110).aspx
You can do things like
new DateTime(10,14,2012) - new DateTime(10,12,2012) ect..

var timeSpan = dateTime2 - dateTime1;
var years = timeSpan.Days / 365;
var months = (timeSpan.Days - years * 365)/30;
var days = timeSpan.Days - years * 365 - months * 30;
// and so on

class Program
{
static void Main()
{
DateTime oldDate = new DateTime(2014,1,1);
DateTime newDate = DateTime.Now;
TimeSpan dif = newDate - oldDate;
int leapdays = GetLeapDays(oldDate, newDate);
var years = (dif.Days-leapdays) / 365;
int otherdays = GetAnOtherDays(oldDate, newDate , years);
int months = (int)((dif.Days - (leapdays + otherdays)- (years * 365)) / 30);
int days = (int)(dif.Days - years * 365 - months * 30) - (leapdays + otherdays);
Console.WriteLine("Edad es {0} años, {1} meses, {2} días", years, months, days) ;
Console.ReadLine();
}
public static int GetAnOtherDays(DateTime oldDate, DateTime newDate, int years) {
int days = 0;
oldDate = oldDate.AddYears(years);
DateTime oldDate1 = oldDate.AddMonths(1);
while ((oldDate1.Month <= newDate.Month && oldDate1.Year<=newDate.Year) ||
(oldDate1.Month>newDate.Month && oldDate1.Year<newDate.Year)) {
days += ((TimeSpan)(oldDate1 - oldDate)).Days - 30;
oldDate = oldDate.AddMonths(1);
oldDate1 = oldDate.AddMonths(1);
}
return days;
}
public static int GetLeapDays(DateTime oldDate, DateTime newDate)
{
int days = 0;
while (oldDate.Year < newDate.Year) {
if (DateTime.IsLeapYear(oldDate.Year)) days += 1;
oldDate = oldDate.AddYears(1);
}
return days;
}
}

Related

Get Current Week Number (C#)

I have been looking at Microsoft's documents and many stack overflow posts but none seem to answer my question. I want to know the simplest and easiest way to get an accurate week number for the current date in c#. I am pretty new to c# so please try and keep it simple. I have tried using:
int week = DateTime.Now.DayOfYear/7;
Console.WriteLine(week)
but on Monday (when I would like it to move onto the next week) it would show as the previous week.
Eg: If the date was 21/12/2020 it would say the current week is the 50th, which is 2 weeks off. Then on 22/12/2020 it would say it is the 51st week, which is 1 week off.
Please Help & Thanks in advance.
This is probably what you are looking for:
DateTime dt = new DateTime(2020, 12, 21);
Calendar cal = new CultureInfo("en-US").Calendar;
int week = cal.GetWeekOfYear(dt, CalendarWeekRule.FirstDay, DayOfWeek.Monday);
Console.WriteLine(week);
You can change the CalendarWeekRule parameter to change the definition of the first week of the year:
FirstDay means that first week of the year can have any length. For example if the first day of the year was Sunday, it will be counted as week and the following Monday will be counted as part of second week.
FirstFourDayWeek means that the first week will be counted only if it mainly in this year. For example if the first day of the year will be Thursday the week will be counted, but if the year starts with Friday, the first week won't be counted.
FirstFullWeek means that the first week that will be counted will be the first full week of the year.
I have looked at this as well when I was writing an application in LotusNotes. From what I have found, the first week of the year must contain a Thursday. If you assume that Sunday is the last day of the week, then the lowest date for Sunday has to be the 4th. With this is mind (and I am very new to C# and all the intricacies) I wrote this code which will give you the week number of any given date and also the number of weeks for this year and the previous. #
public class DateCalculations
{
private readonly DateTime _weekDate;
private DateTime ThisSunday => GetSundayDate(_weekDate);
private DateTime FirstDay_ThisYear => DateTime.Parse($"01/01/{ ThisSunday.Year }");
private DateTime FirstDay_LastYear => DateTime.Parse($"01/01/{ ThisSunday.Year - 1 }");
private DateTime FirstDay_NextYear => DateTime.Parse($"01/01/{ ThisSunday.Year + 1 }");
private DateTime FirstSunday_ThisYear => GetSundayDate_WeekOne(FirstDay_ThisYear);
private DateTime FirstSunday_LastYear => GetSundayDate_WeekOne(FirstDay_LastYear);
private DateTime FirstSunday_NextYear => GetSundayDate_WeekOne(FirstDay_NextYear);
public DateCalculations(string weekDate)
{
if (DateTime.TryParse(weekDate, out _weekDate))
{
return;
}
else
{
throw new Exception("Incorrect date has been supplied");
}
}
private bool IsDateInFirstWeek(DateTime suppliedDate)
{
var output = false;
// First week must contain a Thursday, so lowest Sunday date possible is the 4th
if (suppliedDate.Day >= 4)
{
output = true;
}
return output;
}
private DateTime GetSundayDate(DateTime suppliedDate)
{
var checkDay = suppliedDate;
//Check if the day of the supplied date is a Sunday
while (checkDay.DayOfWeek != DayOfWeek.Sunday)
{
checkDay = checkDay.AddDays(1);
}
return checkDay;
}
private DateTime GetSundayDate_WeekOne(DateTime suppliedDate)
{
var checkDay = GetSundayDate(suppliedDate);
if (IsDateInFirstWeek(checkDay) == false)
{
checkDay = checkDay.AddDays(7);
}
return checkDay;
}
public int WeekNumber()
{
var output = 0;
if (ThisSunday == FirstSunday_ThisYear)
{
output = 1;
}
else if(ThisSunday > FirstSunday_ThisYear)
{
TimeSpan daysBetween = ThisSunday - FirstSunday_ThisYear;
output = (daysBetween.Days/7) + 1;
}
else
{
TimeSpan daysBetween = ThisSunday - FirstSunday_LastYear;
output = (daysBetween.Days / 7) + 1;
}
return output;
}
public int TotalWeeksThisYear()
{
TimeSpan daysBetween = FirstSunday_NextYear - FirstSunday_ThisYear;
return (daysBetween.Days / 7);
}
public int TotalWeeksLastYear()
{
TimeSpan daysBetween = FirstSunday_ThisYear - FirstSunday_LastYear;
return (daysBetween.Days / 7);
}
}
My console was used to test
class Program
{
static void Main()
{
var test = new DateCalculations("2021-01-03");
var weekNumber = test.WeekNumber();
var totalWeeks = test.TotalWeeksThisYear();
var pastWeeks = test.TotalWeeksLastYear();
Console.ReadLine();
}
}
The date format can be any string representation of a date (English or American)
Hope this helps. It may need refactoring though :)
Built on top of this answer: by #bunny4
But not everyone is located in the US or might have to support several cultures.
Use this solution to support a cultural defined week rule and first-Day rule.. e.g. Denmark has "FirstFourDayWeek" rule for weeks and "Monday" as first day of the week.
//for now, take the the current executing thread's Culture
var cultureInfo = Thread.CurrentThread.CurrentCulture;
//let's pick a date
DateTime dt = new DateTime(2020, 12, 21);
DayOfWeek firstDay = cultureInfo.DateTimeFormat.FirstDayOfWeek;
CalendarWeekRule weekRule = cultureInfo.DateTimeFormat.CalendarWeekRule;
Calendar cal = cultureInfo.Calendar;
int week = cal.GetWeekOfYear(dt, weekRule, firstDay);

Finding a DateTime After a TimeSpan Ignoring Weekdays and holidays [duplicate]

This question already has answers here:
AddBusinessDays and GetBusinessDays
(17 answers)
Closed 3 years ago.
I am trying to calculate a finishing date when adding a duration to a start date, but skipping weekends and holidays:
DateTime start = DateTime.Now;
TimeSpan duration = TimeSpan.FromHours(100);
List<DateTime> = //List of holidays
DateTime end = ?
For example if it is 11pm on a Friday and I add 2 hours, it would end on 1am Monday morning.
Is there a neat way of doing this?
I have a temporary fix which increments the time by an hour and checks the day of the week, but it is very inefficient.
Original Idea (untested):
public static DateTime calEndDate(DateTime start, TimeSpan duration, List<DateTime> holidays)
{
var startDay = start.Day;
var i = 0;
var t = 0;
while (TimeSpan.FromHours(t) < duration)
{
var date = start.Add(TimeSpan.FromHours(i));
if (date.DayOfWeek.ToString() != "Saturday" && date.DayOfWeek.ToString() != "Sunday") //and something like !holidays.contains(start)
{
t++;
}
i++;
}
return start.Add(TimeSpan.FromHours(t));
}
}
However is needs to run over 100 times for different start dates/durations on one asp.net page load. I don't know how to benchmark it, but it doesn't seem like an elegant solution?
Here's an algorithm I'd try.
I'm on my phone, and I'll get it wrong, but you should see the logic...
var end = start;
var timeToMidnight = start.Date.AddDays(1) -start;
if ( duration < timeToMidnight ) return start + duration;
end = endMoment + timeToMidnight;
duration = duration - timeToMidnight;
//Helper method
bool IsLeisure(Datetime dt) => (dt.DayOfWeek == DayOfWeek.Saturday) || (dt.DayOfWeek == DayOfWeek.Sunday) || holidays.Any( h => h.Date == dt.Date);
//We're at the first tick of the new day. Let's move to a work day, if needed.
while(IsLeisure(end)) { end = end.AddDays(1); };
//Now let's process full days of 'duration'
while(duration >= TimeSpan.FromDays(1) ) {
end = end.AddDays(1);
if(!IsLeisure(end)) duration = duration - TimeSpan.FromDays(1);
}
//Finally, add the reminder
end = end + duration;
Note: you haven't specified the logic for when start moment is a weekend or a holiday.
Yes there is :
DateTime currentT = DateTime.Now;
DateTime _time_ = currentTime.AddHours(10);
Simple and neat.

Set value to the first day of the month c# [duplicate]

I want to get the first day and last day of the month where a given date lies in. The date comes from a value in a UI field.
If I'm using a time picker I could say
var maxDay = dtpAttendance.MaxDate.Day;
But I'm trying to get it from a DateTime object. So if I have this...
DateTime dt = DateTime.today;
How to get first day and last day of the month from dt?
DateTime structure stores only one value, not range of values. MinValue and MaxValue are static fields, which hold range of possible values for instances of DateTime structure. These fields are static and do not relate to particular instance of DateTime. They relate to DateTime type itself.
Suggested reading: static (C# Reference)
UPDATE: Getting month range:
DateTime date = ...
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
UPDATE: From comments (#KarlGjertsen & #SergeyBerezovskiy)
DateTime date = ...
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddSeconds(-1);
//OR
var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddTicks(-1);
This is more a long comment on #Sergey and #Steffen's answers. Having written similar code myself in the past I decided to check what was most performant while remembering that clarity is important too.
Result
Here is an example test run result for 10 million iterations:
2257 ms for FirstDayOfMonth_AddMethod()
2406 ms for FirstDayOfMonth_NewMethod()
6342 ms for LastDayOfMonth_AddMethod()
4037 ms for LastDayOfMonth_AddMethodWithDaysInMonth()
4160 ms for LastDayOfMonth_NewMethod()
4212 ms for LastDayOfMonth_NewMethodWithReuseOfExtMethod()
2491 ms for LastDayOfMonth_SpecialCase()
Code
I used LINQPad 4 (in C# Program mode) to run the tests with compiler optimization turned on. Here is the tested code factored as Extension methods for clarity and convenience:
public static class DateTimeDayOfMonthExtensions
{
public static DateTime FirstDayOfMonth_AddMethod(this DateTime value)
{
return value.Date.AddDays(1 - value.Day);
}
public static DateTime FirstDayOfMonth_NewMethod(this DateTime value)
{
return new DateTime(value.Year, value.Month, 1);
}
public static DateTime LastDayOfMonth_AddMethod(this DateTime value)
{
return value.FirstDayOfMonth_AddMethod().AddMonths(1).AddDays(-1);
}
public static DateTime LastDayOfMonth_AddMethodWithDaysInMonth(this DateTime value)
{
return value.Date.AddDays(DateTime.DaysInMonth(value.Year, value.Month) - value.Day);
}
public static DateTime LastDayOfMonth_SpecialCase(this DateTime value)
{
return value.AddDays(DateTime.DaysInMonth(value.Year, value.Month) - 1);
}
public static int DaysInMonth(this DateTime value)
{
return DateTime.DaysInMonth(value.Year, value.Month);
}
public static DateTime LastDayOfMonth_NewMethod(this DateTime value)
{
return new DateTime(value.Year, value.Month, DateTime.DaysInMonth(value.Year, value.Month));
}
public static DateTime LastDayOfMonth_NewMethodWithReuseOfExtMethod(this DateTime value)
{
return new DateTime(value.Year, value.Month, value.DaysInMonth());
}
}
void Main()
{
Random rnd = new Random();
DateTime[] sampleData = new DateTime[10000000];
for(int i = 0; i < sampleData.Length; i++) {
sampleData[i] = new DateTime(1970, 1, 1).AddDays(rnd.Next(0, 365 * 50));
}
GC.Collect();
System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].FirstDayOfMonth_AddMethod();
}
string.Format("{0} ms for FirstDayOfMonth_AddMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].FirstDayOfMonth_NewMethod();
}
string.Format("{0} ms for FirstDayOfMonth_NewMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_AddMethod();
}
string.Format("{0} ms for LastDayOfMonth_AddMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_AddMethodWithDaysInMonth();
}
string.Format("{0} ms for LastDayOfMonth_AddMethodWithDaysInMonth()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_NewMethod();
}
string.Format("{0} ms for LastDayOfMonth_NewMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_NewMethodWithReuseOfExtMethod();
}
string.Format("{0} ms for LastDayOfMonth_NewMethodWithReuseOfExtMethod()", sw.ElapsedMilliseconds).Dump();
for(int i = 0; i < sampleData.Length; i++) {
sampleData[i] = sampleData[i].FirstDayOfMonth_AddMethod();
}
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_SpecialCase();
}
string.Format("{0} ms for LastDayOfMonth_SpecialCase()", sw.ElapsedMilliseconds).Dump();
}
Analysis
I was surprised by some of these results.
Although there is not much in it the FirstDayOfMonth_AddMethod was slightly faster than FirstDayOfMonth_NewMethod in most runs of the test. However, I think the latter has a slightly clearer intent and so I have a preference for that.
LastDayOfMonth_AddMethod was a clear loser against LastDayOfMonth_AddMethodWithDaysInMonth, LastDayOfMonth_NewMethod and LastDayOfMonth_NewMethodWithReuseOfExtMethod. Between the fastest three there is nothing much in it and so it comes down to your personal preference. I choose the clarity of LastDayOfMonth_NewMethodWithReuseOfExtMethod with its reuse of another useful extension method. IMHO its intent is clearer and I am willing to accept the small performance cost.
LastDayOfMonth_SpecialCase assumes you are providing the first of the month in the special case where you may have already calculated that date and it uses the add method with DateTime.DaysInMonth to get the result. This is faster than the other versions, as you would expect, but unless you are in a desperate need for speed I don't see the point of having this special case in your arsenal.
Conclusion
Here is an extension method class with my choices and in general agreement with #Steffen I believe:
public static class DateTimeDayOfMonthExtensions
{
public static DateTime FirstDayOfMonth(this DateTime value)
{
return new DateTime(value.Year, value.Month, 1);
}
public static int DaysInMonth(this DateTime value)
{
return DateTime.DaysInMonth(value.Year, value.Month);
}
public static DateTime LastDayOfMonth(this DateTime value)
{
return new DateTime(value.Year, value.Month, value.DaysInMonth());
}
}
If you have got this far, thank you for time! Its been fun :¬). Please comment if you have any other suggestions for these algorithms.
Getting month range with .Net API (just another way):
DateTime date = ...
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
var lastDayOfMonth = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month));
"Last day of month" is actually "First day of *next* month, minus 1". So here's what I use, no need for "DaysInMonth" method:
public static DateTime FirstDayOfMonth(this DateTime value)
{
return new DateTime(value.Year, value.Month, 1);
}
public static DateTime LastDayOfMonth(this DateTime value)
{
return value.FirstDayOfMonth()
.AddMonths(1)
.AddMinutes(-1);
}
NOTE:
The reason I use AddMinutes(-1), not AddDays(-1) here is because usually you need these date functions for reporting for some date-period, and when you build a report for a period, the "end date" should actually be something like Oct 31 2015 23:59:59 so your report works correctly - including all the data from last day of month.
I.e. you actually get the "last moment of the month" here. Not Last day.
OK, I'm going to shut up now.
DateTime dCalcDate = DateTime.Now;
dtpFromEffDate.Value = new DateTime(dCalcDate.Year, dCalcDate.Month, 1);
dptToEffDate.Value = new DateTime(dCalcDate.Year, dCalcDate.Month, DateTime.DaysInMonth(dCalcDate.Year, dCalcDate.Month));
Here you can add one month for the first day of current month than delete 1 day from that day.
DateTime now = DateTime.Now;
var startDate = new DateTime(now.Year, now.Month, 1);
var endDate = startDate.AddMonths(1).AddDays(-1);
If you only care about the date
var firstDay = new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind);
var lastDay = new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind).AddMonths(1).AddDays(-1);
If you want to preserve time
var firstDay = new DateTime(date.Year, date.Month, 1, date.Hour, date.Minute, date.Second, date.Kind);
var lastDay = new DateTime(date.Year, date.Month, 1, date.Hour, date.Minute, date.Second, date.Kind).AddMonths(1).AddDays(-1);
Try this one:
string strDate = DateTime.Now.ToString("MM/01/yyyy");
The accepted answer here does not take into account the Kind of the DateTime instance. For example if your original DateTime instance was a UTC Kind then by making a new DateTime instance you will be making an Unknown Kind instance which will then be treated as local time based on server settings. Therefore the more proper way to get the first and last date of the month would be this:
var now = DateTime.UtcNow;
var first = now.Date.AddDays(-(now.Date.Day - 1));
var last = first.AddMonths(1).AddTicks(-1);
This way the original Kind of the DateTime instance is preserved.
I used this in my script(works for me) but I needed a full date without the need of trimming it to only the date and no time.
public DateTime GetLastDayOfTheMonth()
{
int daysFromNow = DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month) - (int)DateTime.Now.Day;
return DateTime.Now.AddDays(daysFromNow);
}
For Persian culture
PersianCalendar pc = new PersianCalendar();
var today = pc.GetDayOfMonth(DateTime.Now);
var firstDayOfMonth = pc.GetDayOfMonth(DateTime.Now.AddDays(-(today-1)));
var lastDayOfMonth = pc.GetDayOfMonth(DateTime.Now.AddMonths(1).AddDays(-today));
Console.WriteLine("First day "+ firstDayOfMonth);
Console.WriteLine("Last day " + lastDayOfMonth);
You can do it
DateTime dt = DateTime.Now;
DateTime firstDayOfMonth = new DateTime(dt.Year, date.Month, 1);
DateTime lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
Give this a try. It basically calculates the number of days that has passed on DateTime.Now, then subtracts one from that and uses the new value to find the first of the current month. From there it uses that DateTime and uses .AddMonths(-1) to get the first of the previous month.
Getting the last day of last month does basically the same thing except it adds one to number of days in the month and subtracts that value from DateTime.Now.AddDays, giving you the last day of the previous month.
int NumberofDays = DateTime.Now.Day;
int FirstDay = NumberofDays - 1;
int LastDay = NumberofDays + 1;
DateTime FirstofThisMonth = DateTime.Now.AddDays(-FirstDay);
DateTime LastDayOfLastMonth = DateTime.Now.AddDays(-LastDay);
DateTime CheckLastMonth = FirstofThisMonth.AddMonths(-1);
You can try this for get current month first day;
DateTime.Now.AddDays(-(DateTime.Now.Day-1))
and assign it a value.
Like this:
dateEndEdit.EditValue = DateTime.Now;
dateStartEdit.EditValue = DateTime.Now.AddDays(-(DateTime.Now.Day-1));
Create an instance of DateTime class
DateTime dateTime = DateTime.Now;
If you want to get the last day of the month you can do this
int lastDayOfMonth = DateTime.DaysInMonth(caducidadPuntos.Year, caducidadPuntos.Month);
If you want to get the first day of the month, you can do this
DateTime firstDayMonth = new DateTime(dateTime.Year, dateTime.Month, 1);
We had the requirement of being able to get the start and end of a given dates month, including times, inclusively. We ended up utilizing the aforementioned solutions, huge thanks to everyone here, and combined it into a util class to be able to get the start and end for a given month and year number combination up to the last millisecond. Including what we moved forward with in the event it helps someone else.
The util:
public class DateUtil
{
public static (DateTime startOfMonth, DateTime endOfMonth) GetStartAndEndOfMonth(int month, int year)
{
DateTime startOfMonth = GetStartOfMonth(month, year);
DateTime endOfMonth = GetEndOfMonth(month, year);
return (startOfMonth, endOfMonth);
}
public static DateTime GetStartOfMonth(int month, int year)
{
return new DateTime(year, month, 1).Date;
}
public static DateTime GetEndOfMonth(int month, int year)
{
return new DateTime(year, month, 1).Date.AddMonths(1).AddMilliseconds(-1);
}
}
Usage:
(DateTime startOfMonth, DateTime endOfMonth) = DateUtil.GetStartAndEndOfMonth(2, 2021); // February, 2021
easy way to do it
Begin = new DateTime(DateTime.Now.Year, DateTime.Now.Month,1).ToShortDateString();
End = new DataFim.Text = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month)).ToShortDateString();
DateTime dCalcDate = DateTime.Now;
var startDate = new DateTime(Convert.ToInt32(Year), Convert.ToInt32(Month), 1);
var endDate = new DateTime(Convert.ToInt32(Year), Convert.ToInt32(Month), DateTime.DaysInMonth((Convert.ToInt32(Year)), Convert.ToInt32(Month)));

Get DateTime by Adding Minutes but consider working hours and weekends

Interesting issue I'm facing and I just can't come up with an algorim to calculate.
Basically, what I want is to calculate a DateTime based on DateTime.Now.AddMinutes() but the Adding of minutes should take into consideration Working Hours and weekends.
In other words, if the time is currently 16:50 and i add 20 minutes, the method should return a DateTime for tomorrow morning at 08:10 (if tomorrow is not a weekend day).
I've started with some logic, but it's not complete. Does anyone have a sample which can save me a few hours of coding? This is what i've got so far:
public DateTime CalculateSLAFromNow(int minutes)
{
DateTime now = DateTime.Now;
TimeSpan slatimeaddedon = CalculateToNextWeekDay(DateTime.Now);
TimeSpan finalMinutesAddedon = slatimeaddedon.Add(new TimeSpan(0, minutes, 0));
DateTime SLATime = DateTime.Now.AddMinutes(slatimeaddedon.TotalMinutes);
return SLATime;
}
private TimeSpan CalculateToNextWeekDay(DateTime dt)
{
//Calculate.
}
public static DateTime CalculateSLAFromNow(int minutes)
{
double days = (double)minutes / 540;
DateTime now = DateTime.Now;
DateTime later = now;
while (days >= 1)
{
later = later.AddDays(1);
if (later.DayOfWeek == DayOfWeek.Saturday)
{
later = later.AddDays(2);
}
days--;
}
days = days * 540;
later = later.AddMinutes(days);
if (later.Hour > 17)
{
later = later.AddHours(15);
}
if (later.DayOfWeek == DayOfWeek.Saturday)
{
later = later.AddDays(2);
}
else if(later.DayOfWeek == DayOfWeek.Sunday)
{
later = later.AddDays(1);
}
return later;
}
There now it accounts for any number of minutes added (not the prettiest code, but it works)
Ok. Friend of mine wrote the following which works 100%. Thanks J for this. Herewith the complete solution:
private static DateTime DoCalculation(DateTime startDate, int minutes)
{
if (startDate.DayOfWeek == DayOfWeek.Sunday)
{
// if the input date is a sunday, set the actual SLA start date to the following monday morning 7:00AM
startDate = startDate.AddHours(24);
startDate = new DateTime(startDate.Year, startDate.Month, startDate.Day, 7, 0, 0);
}
else if (startDate.DayOfWeek == DayOfWeek.Saturday)
{
// if the input date is a saturday, set the actual SLA start date to the following monday morning 7:00AM
startDate = startDate.AddHours(48);
startDate = new DateTime(startDate.Year, startDate.Month, startDate.Day, 7, 0, 0);
}
DateTime resultDate = startDate;
for (int i = 0; i < minutes; i++)
{
resultDate = resultDate.AddMinutes(1);
// it is 5PM and time to go home
if (resultDate.Hour >= 17)
{
// if tomorrow is saturday
if (resultDate.AddDays(1).DayOfWeek == DayOfWeek.Saturday)
{
//add 48 hours to get us through the whole weekend
resultDate = resultDate.AddHours(48);
}
// add 14 hours to get us to next morning
resultDate = resultDate.AddHours(14);
}
}
return resultDate;
}

Calculating Day, Month, Year

How do I calculate Day, Month, Year exactly?
Means..
From 2th Jan 1990 to 9th May 2009 is..
xxx Days, xxx Months, xxx Years.
Any idea how to do that?
I tried Timespan and Tick().. Both failed to do so..
I don't think there's anything built into the framework to do this. TimeSpan won't do it because the number of days etc depends on the exact starting and ending point, not just the duration of time between them.
Here's a simple way of doing it, but inefficient:
using System;
class Program
{
static void Main()
{
ShowDifference(new DateTime(1990, 1, 2),
new DateTime(2009, 5, 9));
}
static void ShowDifference(DateTime start,
DateTime end)
{
if (start > end)
{
throw new ArgumentException();
}
// See comment at the end
int years = end.Year - start.Year - 2;
while (start.AddYears(years) <= end)
{
years++;
}
years--;
Console.WriteLine("{0} years", years);
start = start.AddYears(years);
int months = 0;
while (start.AddMonths(months) <= end)
{
months++;
}
months--;
Console.WriteLine("{0} months", months);
start = start.AddMonths(months);
int days = 0;
while (start.AddDays(days) <= end)
{
days++;
}
days--;
Console.WriteLine("{0} days", days);
}
}
Obviously there are ways of making this more efficient, but they will be fiddly. EDIT: I've changed this to start off with a very conservative guess at the number of years - it may well be one lower than it needs to be, but I don't want to think about corner cases at the moment. It should definitely work, and the loops all have (fairly small) upper bounds for the number of times they'll run.
Note that at each step, you should add the complete number of years/days/months to the starting point, rather than doing it one month at a time. Otherwise, if you go from January 30th to March 30th, it will claim 2 months and 2 days because of the transition from January 30th to February 28th when you add a month, then February 28th to March 28th when you add a second month.
Hopefully Noda Time will make all this easier when I eventually get round to finishing it :)
You cannot do it through direct calculation (i.e. there's no "TotalMonths" or "TotalYears" property of TimeSpan, simply because those numbers do not make sense with arbitrary intervals of time).
Instead, you can just count the number in a loop, like so:
var dt1 = new DateTime(1990, 1, 2);
var dt2 = new DateTime(2009, 5, 9);
int years = 0;
while (dt1.AddYears(1) < dt2)
{
years ++;
dt1 = dt1.AddYears(1);
}
int months = 0;
while (dt1.AddMonths(1) < dt2)
{
months ++;
dt1 = dt1.AddMonths(1);
}
int days = (int) Math.Floor(dt2.Subtract(dt1).TotalDays);
I haven't tested this, so there might be off-by-one errors or whatever, but that's the basic idea.
How about something like this?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DateTimeTest
{
class Program
{
static void Main(string[] args)
{
var dt1 = new DateTime(1990, 1, 2);
var dt2 = new DateTime(2009, 5, 9);
int days = dt2.Day - dt1.Day;
int months = dt2.Month - dt1.Month;
int years = dt2.Year - dt1.Year;
if (months < 0)
{
months += 12;
years -= 1;
}
if (days < 0)
{
dt1.AddYears(years);
dt1.AddMonths(months);
days = dt2.Subtract(dt1).Days;
months -= 1;
}
Console.WriteLine("{0} Days, {1} Months, {2} Years", days, months, years);
}
}
}
Outputs
7 Days, 4 Months, 19 Years
Is that the output you were looking for? You might need a couple extra conditions depending on how you want to define a "month".

Categories

Resources