How to count number Holidays between 2 dates C# - c#

How can I count the number of holidays from database between 2 days
I already count the number of business days but how can i minus to week days the number of holidays counted between 2 days.
Assuming that I have a Holidays table with
Halloween 11-01
Christmas 12-25
Dates:
start date = 10-25
end date = 01-30
Answer should be: Business days - Holiday Number between 2 dates ;
Here's my code:
public static void GetBusinessDays(DateTime startD, DateTime endD)
{
double calcBusinessDays =
1 + ((endD - startD).TotalDays * 5 -
(startD.DayOfWeek - endD.DayOfWeek) * 2) / 7;
if (endD.DayOfWeek == DayOfWeek.Saturday) calcBusinessDays--;
if (startD.DayOfWeek == DayOfWeek.Sunday) calcBusinessDays--;
MessageBox.Show(" " + calcBusinessDays);
}
from this link :Calculate the number of business days between two dates?
Button:
private void button1_Click(object sender, EventArgs e)
{
GetBusinessDays(Convert.ToDateTime(metroDateTime1.Value.ToString("yyyy-MM-dd")), Convert.ToDateTime(metroDateTime2.Value.ToString("yyyy-MM-dd")));
}
PS: I'm new to c#

While only
while (Start.Date <= End.Date)
{
if (Start.DayOfWeek == DayOfWeek.Saturday || Start.DayOfWeek == DayOfWeek.Sunday)
holidays++;
Start = Start.AddDays(1);
}
Could calculate the holiday count, but the code below is more efficient, as we already know that every 7 days has 2 holiday in it and don't have to go through it and only checking days % 7 (6 days at most) for holidays is enough.
int days = (int)(End - Start).TotalDays + 1;
int holidays = days / 7 * 2;
int remain = days % 7;
DateTime dt = End.AddDays(-remain);
while (dt.Date <= End.Date)
{
if (dt.DayOfWeek == DayOfWeek.Saturday || dt.DayOfWeek == DayOfWeek.Sunday)
holidays++;
dt = dt.AddDays(1);
}
int year = Start.Year;
do
{
dt = new DateTime(year, 12, 25); //is chritsmass right?
if (dt >= Start && dt <= End && dt.DayOfWeek!=DayOfWeek.Saturday && dt.DayOfWeek != DayOfWeek.Sunday) holidays++;
dt = new DateTime(year, 7, 4); // 4th of july
if (dt >= Start && dt <= End && dt.DayOfWeek!=DayOfWeek.Saturday && dt.DayOfWeek != DayOfWeek.Sunday) holidays++;
dt = new DateTime(year, 10, 31); // holoween
if (dt >= Start && dt <= End && dt.DayOfWeek!=DayOfWeek.Saturday && dt.DayOfWeek != DayOfWeek.Sunday) holidays++;
year++;
} while (year <= End.Year);
int businessDays = days - holidays;
Live Demo

Related

Find largest TimeSpan in range that don't overlap with data-table-posts

Trying to find the largest cohesive time for non-working-hours diff in a specific range.
The range that is looked at is defined by:
sDate = range start
eDate = range end
in this defined range, there could be existing registrations (orange blocks in image).
Could someone please give me some input on how to solve this issue.
This code will not compare existing post with each other.
public TimeSpan TimeNightRest(DateTime WhatDay, int dayRange, DataTable TimeData)
{
DateTime DayRangeStart = new DateTime(WhatDay.Year, WhatDay.Month, WhatDay.Day, 0, 0, 0);
DateTime DayRangeEnd = new DateTime(WhatDay.Year, WhatDay.Month, WhatDay.AddDays(dayRange).Day, 0, 0, 0);
TimeSpan nightRest = new TimeSpan();
foreach (DataRow drUnfiltered in TimeData.Rows)
{
DateTime sDate = DateTime.Parse(TimeData.Rows[0]["sDate"].ToString());
DateTime eDate = DateTime.Parse(TimeData.Rows[0]["eDate"].ToString());
//1. db-post cover range
if (sDate < WhatDay && eDate > WhatDay.AddDays(dayRange))
{
nightRest = TimeSpan.FromHours(0);
break;
}
//2. Post exists, start outside ends inside range
if(sDate < WhatDay && eDate < WhatDay.AddDays(dayRange))
{
nightRest = (WhatDay.addDays(dayRange) - eDate)
//More posts could exists that lower this value!!!
}
//3. Post exists, start inside ends outside range
if ((sDate > WhatDay && sDate <WhatDay.AddDays(dayRange)) && eDate > WhatDay.AddDays(dayRange))
{
nightRest = (sDate - WhatDay);
//More posts could exists that lower this value!!!
}
}
return nightRest;
}
I tried to write a different version, this code will compare different post trying to find the largest diff between them. But will fail to find posts that overlaps (no diff) and it will also fail with finding the correct diff with post that starts outside and ends inside the range and opposite.
`
///<Alternative></Alternative>
//1. - No Data Rest = 24h x DayRange
if (timeData.Rows.Count == 0)
{
nightRest = TimeSpan.FromHours(24 * dayRange);
}
///<Alternative></Alternative>
//2. - One Post, Compare to day start/end time
if (timeData.Rows.Count == 1)
{
DateTime sDate = Convert.ToDateTime(timeData.Rows[0]["sDate"].ToString());
DateTime eDate = Convert.ToDateTime(timeData.Rows[0]["eDate"].ToString());
TimeSpan range1 = (sDate - DayRangeStart);
TimeSpan range2 = (DayRangeEnd - eDate);
if (range1 > range2)
{
nightRest = range1;
}
else
{
nightRest = range2;
}
}
///<Alternative></Alternative>
//3. - If DataTable containes more than 1 post, then loop through to calculate diffrence
between post and day start/end
if (timeData.Rows.Count > 1)
{
int i = 1;
int RowCount = timeData.Rows.Count;
foreach (DataRow dr in timeData.Rows)
{
DateTime sDate = Convert.ToDateTime(dr["sdate"]);
DateTime eDate = Convert.ToDateTime(dr["edate"]);
DateTime prevPostSdate = new DateTime();
DateTime nextPostSdate = new DateTime();
//Only 1st time in loop
if (i != 1)
{
//Prev row
DataRow lastRow = timeData.Rows[(i - 1) - 1];
prevPostSdate = Convert.ToDateTime(lastRow["edate"]);
//prevPostEdate = Convert.ToDateTime(lastRow["edate"]);
}
else
{
prevPostSdate = DayRangeStart;
}
//If we are on EOF-post then dont get next post value, get instead range end value
if (i != RowCount)
{
//Next row
DataRow nextRow = timeData.Rows[(i - 1) + 1];
nextPostSdate = Convert.ToDateTime(nextRow["sdate"]);
}
else
{
nextPostSdate = DayRangeEnd;
}
///<Compare>Type #1
///Sdate inside && eDate inside
///</ Compare >
if (DayRangeStart < sDate && DayRangeEnd > eDate)
{
//Compair Range with Post-sdate & Post
//1. Range with Post-sdate
TimeSpan value1 = (sDate - prevPostSdate);
//2. Post-eDate with NextPostSdate
TimeSpan value2 = (nextPostSdate - eDate);
if (value1 > nightRest) nightRest = value1;
if (value2 > nightRest) nightRest = value2;
}
///<Compare>Type #2
///Sdate outside && eDate inside
///</ Compare >
if (DayRangeStart >= sDate && DayRangeEnd > eDate)
{
//Compair Range with Post-sdate & Post
//1. Range with Post-sdate
TimeSpan value1 = (nextPostSdate - eDate);
if (value1 > nightRest) nightRest = value1;
}
///<Compare>Type #3
///Sdate indise && eDate outside
///</ Compare >
if (DayRangeStart < sDate && DayRangeEnd <= eDate)
{
//Compare Range Post-sdate & Post
//1. Range with Post-sdate
TimeSpan value1 = (sDate - prevPostSdate);
//Console.WriteLine(value1);
if (value1 > nightRest) nightRest = value1;
}
///<Compare>Type #4
///Sdate outside && eDate outside
///</ Compare >
if (DayRangeStart >= sDate && DayRangeEnd <= eDate)
{
nightRest = TimeSpan.FromHours(0);
}
i++;
}
}
`
Well i manage to solve this. Probably some much better code out there but this does the work!
public DataTable FilterTable(DataTable table, DateTime startDate, DateTime endDate)
{
var filteredRows =
from row in table.Rows.OfType<DataRow>()
where (DateTime)row["sDate"] < endDate && startDate <= (DateTime)row["eDate"]
select row;
var filteredTable = table.Clone();
filteredRows.ToList().ForEach(r => filteredTable.ImportRow(r));
return filteredTable;
}
public TimeSpan TimeNightRest(DateTime WhatDay, int dayRange, DataTable TimeData)
{
DateTime DayRangeStart = DateTime.Parse(WhatDay.ToShortDateString());
DateTime DayRangeEnd = DateTime.Parse(DayRangeStart.AddDays(dayRange).ToShortDateString());
TimeSpan nightRest = new TimeSpan();
DataTable dtTime = FilterTable(TimeData, WhatDay, WhatDay.AddDays(dayRange));
//1. - No posts
if (dtTime.Rows.Count == 0)
{
nightRest = TimeSpan.FromHours(24 * dayRange);
}
//2. - One post Exists!
if (dtTime.Rows.Count == 1)
{
DateTime sDate = Convert.ToDateTime(dtTime.Rows[0]["sDate"].ToString());
DateTime eDate = Convert.ToDateTime(dtTime.Rows[0]["eDate"].ToString());
if (sDate < DayRangeEnd && DayRangeStart <= eDate)
{
TimeSpan range1 = (sDate - DayRangeStart);
TimeSpan range2 = (DayRangeEnd - eDate);
if (range1 > range2)
{
nightRest = range1;
}
else
{
nightRest = range2;
}
//Negative TimeSpans is ==> Zero
if(nightRest < TimeSpan.Zero)
{
nightRest = TimeSpan.FromHours(0);
}
}
else
{
nightRest = TimeSpan.FromHours(24 * dayRange);
}
}
//3. More then 1 post i db
if (dtTime.Rows.Count > 1)
{
int i = 1;
int RowCount = dtTime.Rows.Count;
foreach (DataRow dr in dtTime.Rows)
{
DateTime sDate = Convert.ToDateTime(dr["sdate"]);
DateTime eDate = Convert.ToDateTime(dr["edate"]);
if (sDate < DayRangeEnd && DayRangeStart <= eDate)
{
DateTime prevPostSdate = new DateTime();
DateTime nextPostSdate = new DateTime();
//1st loop
if (i != 1)
{
//Prev row
DataRow lastRow = dtTime.Rows[(i - 1) - 1];
prevPostSdate = Convert.ToDateTime(lastRow["edate"]);
}
else
{
prevPostSdate = DayRangeStart;
}
//If we are on EOF-post then dont get next post value, get instead range end value
if (i != RowCount)
{
//Next row
DataRow nextRow = dtTime.Rows[(i - 1) + 1];
nextPostSdate = Convert.ToDateTime(nextRow["sdate"]);
}
else
{
nextPostSdate = DayRangeEnd;
}
if (DayRangeStart < sDate && DayRangeEnd > eDate)
{
TimeSpan value1 = (sDate - prevPostSdate);
TimeSpan value2 = (nextPostSdate - eDate);
if (value1 > nightRest) nightRest = value1;
if (value2 > nightRest) nightRest = value2;
}
if (DayRangeStart >= sDate && DayRangeEnd > eDate)
{
TimeSpan value1 = (nextPostSdate - eDate);
if (value1 > nightRest) nightRest = value1;
}
if (DayRangeStart < sDate && DayRangeEnd <= eDate)
{
TimeSpan value1 = (sDate - prevPostSdate);
if (value1 > nightRest) nightRest = value1;
}
if (DayRangeStart >= sDate && DayRangeEnd <= eDate)
{
nightRest = TimeSpan.FromHours(0);
}
}
else
{
nightRest = TimeSpan.FromHours(24 * dayRange);
}
i++;
}
}
return nightRest;
}

how to calculated the age on birthday date for shamsi calendar with WPF in GridView

I have a grid view in wpf(C#) which contain Birth Day Date. I used bellow code for calculated the age for first row.
Now how to calculated the all row (ages)?
private void Window_Loaded(object sender, RoutedEventArgs e)
{
string birth_day = "";
var query = from u in db.tbl_User select u;
var result = query.ToList();
if (result.Count > 0)
{
birth_day = result[0].BirthDayDate;
DateTime birthdaydate = DateTime.Parse(ShamsiToMiladi(birth_day));
DateTime todaydate = DateTime.Parse(ShamsiToMiladi(PublicVariable.TodayDate));
int days = todaydate.Day - birthdaydate.Day;
if (days < 0)
{
todaydate = todaydate.AddMonths(-1);
days += DateTime.DaysInMonth(todaydate.Year, todaydate.Month);
}
int months = todaydate.Month - birthdaydate.Month;
if (months < 0)
{
todaydate = todaydate.AddYears(-1);
months += 12;
}
int years = todaydate.Year - birthdaydate.Year;
MessageBox.Show(string.Format("{0} year{1}, {2} month{3} and {4} day{5}",
years, (years == 1) ? "" : "s",
months, (months == 1) ? "" : "s",
days, (days == 1) ? "" : "s"));
}
Just a simple foreach:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var query = db.tbl_User.ToList();
if (!query.Any())return;
var results = new List<string>();
foreach(var user in query){
var birth_day = user.BirthDayDate;
DateTime birthdaydate = DateTime.Parse(ShamsiToMiladi(birth_day));
DateTime todaydate = DateTime.Parse(ShamsiToMiladi(PublicVariable.TodayDate));
int days = todaydate.Day - birthdaydate.Day;
if (days < 0)
{
todaydate = todaydate.AddMonths(-1);
days += DateTime.DaysInMonth(todaydate.Year, todaydate.Month);
}
int months = todaydate.Month - birthdaydate.Month;
if (months < 0)
{
todaydate = todaydate.AddYears(-1);
months += 12;
}
int years = todaydate.Year - birthdaydate.Year;
results.Add(
string.Format(
"{0} year{1}, {2} month{3} and {4} day{5}",
years, (years == 1) ? "" : "s",
months, (months == 1) ? "" : "s",
days, (days == 1) ? "" : "s"
)
);
}
}
Not enough rep to comment but to use foreach:
if (result.Count > 0)
{
birth_day = result[0].BirthDayDate;
becomes
foreach (var item in result)
{
// Use result.BirthDayDate

Arrays within month

My program is currently working to get the next day except I seem to have an array to which I want removing. Whenever I remove the array within my Day property then my month is having an issue. Any ideas for a solution towards this issue. Please do not mention me not wanting to use DateTime or whatever, as I am doing this, as a challenge for myself. Basically the issue is when I remove my array I am having a problem or issue with the month and this array is useless, as I have if statements within my nextDay method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace date
{
class Program
{
static void Main(string[] args)
{
string british, american; // sets two strings one for british and other for american
Console.Title = "NextDate Application";
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("\t\t\t\t\t\tNextDate Application\n\t\t\t\t\t-------------------------------------"); // title
Console.ResetColor();
Console.WriteLine("This application will allow you to enter a valid date and this will get the next day."); // intro of what the application does
Console.WriteLine("The application takes leap years into account\n"); // intro of what the application does
Console.WriteLine("enter key 'b' for British Format or 'a' for American Format"); // writes the line
char key = Console.ReadKey().KeyChar;
if (key == 'b') // if key b is entered
{
british = GetValidInput("\nplease enter date as dd/MM/yyyy\n"); // tells user to input a date in the format
int day; // sets variable
int month; // sets variable
int year; // sets variable
Date date; // instance of class Date
string[] read = british.Split('/'); // "/" can be read from each value and sets new array
day = int.Parse(read[0]); // day is first position in array
month = int.Parse(read[1]); // month is second position in array
year = int.Parse(read[2]); // year is third position in array
try
{
date = new Date(day, month, year); // initialises a new date class
for (int i = 0; i < 1; i++)
{
date.nextDay(); // calls nextDay method
Console.WriteLine("{0}/{1}/{2}", date.Day, date.Month, date.Year); // writes the line in a format of d/m/y
Console.ReadLine(); // reads the line
}
}
catch (ArgumentOutOfRangeException exc)
{
Console.WriteLine(exc.Message); // states the message for ArgumentOutOfRangeException
Console.Read(); // breaks
}
}
else if (key == 'a')
{
american = GetValidInput("\nplease enter date as MM/dd/yyyy\n"); // tells user to input a date in the format
int day; // sets variable
int month; // sets variable
int year; // sets variable
Date date; // instance of class Date
string[] read = american.Split('/'); // "/" can be read from each value and sets new array
month = int.Parse(read[0]); // month is first position in array
day = int.Parse(read[1]); // day is second position in array
year = int.Parse(read[2]); // year is third position in array
try
{
date = new Date(day, month, year); // initialises a new date class
for (int i = 0; i < 1; i++)
{
date.nextDay(); // calls nextDay method
Console.WriteLine("{0}/{1}/{2}", date.Month, date.Day, date.Year); // writes the line in a format of m/d/y
Console.ReadLine(); // reads the line
}
}
catch (ArgumentOutOfRangeException exc)
{
Console.WriteLine(exc.Message); // states the message for ArgumentOutOfRangeException
Console.Read(); // breaks
}
}
}
static string GetValidInput(string prompt)
{
while (true)
{
string input;
Console.WriteLine(prompt);
input = Console.ReadLine();
if (!string.IsNullOrEmpty(input))
{
return input;
}
Console.WriteLine("error no input");
}
}
class Date
{
private int _month; // 1-12
private int _day; // 1-31 depending on month
private int _year; // sets the year
public Date(int day, int month, int year)
{
Month = month;
Day = day;
Year = year;
}
public void nextDay() // nextDay method
{
{
if (_day == 31 && _month == 1) // jan
{
_day = 1;
_day = _day - 1;
_month = 2;
}
if (_day == 28 && _month == 2) // feb
{
_day = 1;
_day = _day - 1;
_month = 3;
}
if (_day == 31 && _month == 3) // march
{
_day = 1;
_day = _day - 1;
_month = 4;
}
if (_day == 30 && _month == 4) // april
{
_day = 1;
_day = _day - 1;
_month = 5;
}
if (_day == 31 && _month == 5) // May
{
_day = 1;
_day = _day - 1;
_month = 6;
}
if (_day == 30 && _month == 6) // June
{
_day = 1;
_day = _day - 1;
_month = 7;
}
if (_day == 31 && _month == 7) // July
{
_day = 1;
_day = _day - 1;
_month = 8;
}
if (_day == 31 && _month == 8) // Aug
{
_day = 1;
_day = _day - 1;
_month = 9;
}
if (_day == 30 && _month == 9) // Sept
{
_day = 1;
_day = _day - 1;
_month = 10;
}
if (_day == 31 && _month == 10) // Oct
{
_day = 1;
_day = _day - 1;
_month = 11;
}
if (_day == 30 && _month == 11) // Nov
{
_day = 1;
_day = _day - 1;
_month = 12;
}
if (_day == 31 && _month == 12) // Dec
{
_day = 1;
_month = 1;
_year = _year + 1;
}
else
{
_day = _day + 1;
}
}
}
public int Year // property called Year
{
get { return _year; } // return the year
set // set statement
{
if (value >= 1820 && value <= 2020) // if value is higher than or equal to 1820 and less than or equal to 2020
_year = value; // sets year as value
else
throw new ArgumentOutOfRangeException("Year must be between 1820 and 2020"); // throws an exception
}
}
public int Month // property called Month
{
get { return _month; } // return month
set // set statement
{
if (value > 0 && value <= 12) // if value is higher than 0 and less than or equal to 12
_month = value; // sets month as value
else
throw new ArgumentOutOfRangeException("Month must be between 1-12"); // throws an exception
}
}
public int Day // property called Day
{
get { return _day; }
set
{
// array Max days of each month
int[] days = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (value > 0 && value <= days[_month]) // if value is higher than 0 and less than or equal to days of month
_day = value; // sets day as value
// check for the leap year
else if (_month == 2 && value == 29 && // else if month is equal to 2 and value is equal to 29
(_year % 400 == 0 || (_year % 4 == 0 && _year % 100 != 0)))
_day = value;
else
throw new ArgumentOutOfRangeException("Day is out of range"); // throws an exception
}
}
}
}
}
There are several issues:
Each if block is being evaluated independently:
if (...)
{
}
if (...)
{
}
else
{
}
The else block here is only paired with the if block before it. Instead, you should be using else if in the middle ones.
After you make the above change, then you can remove the extraneous _day = _day - 1; calls.
The February check needs to account for leap year.
if (_day == 28 && _month == 2)
Should be
if (_month == 2 && (_day == IsLeapYear(_year) ? 29 : 28))
If you don't want to use DateTime.IsLeapYear, then extract your implementation from the Day setter into a method and use it in both places.
Regarding your question:
Whenever I remove the array within my Day property...
The only array in your Day property is the one called days, which you are indeed using correctly in your logic, so it doesn't make sense to remove it.

To get the mondays to saturdays in the current month

In a month i want to know mondays to sataurdays for the current month eg: in oct month 2011 there are
3-oct-2011 to 8-oct-2011,
10-OCt-11 to 15-Oct-11,
17-Oct-11 to 22-oct-2011,
24-Oct-2011 to 29-Oct-2011
all these sequence of days All these days like 3-oct-2011,4-oct-2011 ....29-oct-11 etc need to get in the array format or in the datatable.
var today = DateTime.Today;
var daysInMonth = DateTime.DaysInMonth(today.Year, today.Month);
var dates = Enumerable.Range(1, daysInMonth)
.Select(n => new DateTime(today.Year, today.Month, n))
.Where(date => date.DayOfWeek != DayOfWeek.Sunday)
.ToArray();
This will look at the number of days in the current month, create a DateTime object for each, then only return those dates which are not a Sunday as an array.
var today = DateTime.Today;
var daysInMonth = DateTime.DaysInMonth(today.Year, today.Month);
var dates = Enumerable.Range(1, daysInMonth)
.Select(n => new DateTime(today.Year, today.Month, n))
.Where(date => date.DayOfWeek != DayOfWeek.Sunday)
.SkipWhile(date => date.DayOfWeek != DayOfWeek.Monday)
.TakeWhile(date => date.DayOfWeek != DayOfWeek.Monday || (date.DayOfWeek == DayOfWeek.Monday && daysInMonth - date.Day > 7))
.ToArray();
This will do the same, except get rid of any Monday -> Saturday ranges which are not in the current month. (Week started in the previous month, or ends in the next).
Edit:
Here is a .NET 2 solution which will do the same thing as my previously posted LINQ solution.
DateTime today = DateTime.Today;
int daysInMonth = DateTime.DaysInMonth(today.Year, today.Month);
List<DateTime> dates = new List<DateTime>();
bool foundFirst = false;
for (int n = 1; n <= daysInMonth; n++)
{
var date = new DateTime(today.Year, today.Month, n);
// Skip untill we find the first Monday of the month.
if (date.DayOfWeek != DayOfWeek.Monday && !foundFirst)
continue;
foundFirst = true;
// Add all days except Sundays.
if (date.DayOfWeek != DayOfWeek.Sunday)
dates.Add(date);
int remainingDays = daysInMonth - n;
// Verify that there are enough days left in this month to add all days upto the next Saturday.
if (date.DayOfWeek == DayOfWeek.Saturday && remainingDays < 7)
break;
}
DateTime[] dateArray = dates.ToArray();
most easy:
int month = DateTime.Now.Month;
int year = DateTime.Now.Year;
int days= DateTime.DaysInMonth(year, month);
int totalSaturdays = 0;
for(int i=1;i<=days;i++)
{
var day = new DateTime(year, month, i);
if(day.DayOfWeek==DayOfWeek.Saturday)
{
totalSaturdays++;
}
}
Console.WriteLine(("Total Saturdays ="+totalSaturdays.ToString()));
Console.ReadLine();
Efficient solution;
var x = DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month);
int i = 1;
while (i <= x)
{
if (new DateTime(DateTime.Now.Year, DateTime.Now.Month, i).DayOfWeek == DayOfWeek.Saturday)
{
Console.WriteLine(new DateTime(DateTime.Now.Year, DateTime.Now.Month, i));
i += 6;
}
i++;
}

Calculate number of days between two dates separated by month

I need to calculate the number of days between two dates (DateTime) but with a twist. I want to know how many days fall into each of the months that the two days span. Is there an easy way two do it?
Example:
I have start date 30/03/2011 and end date 05/04/2011 then the result should be something like:
var result = new Dictionary<DateTime, int>
{
{ new DateTime(2011, 3, 1), 2 },
{ new DateTime(2011, 4, 1), 5 }
};
You could try something like this:
using System;
using System.Collections.Generic;
static class Program {
// return dictionary tuple<year,month> -> number of days
static Dictionary<Tuple<int, int>, int> GetNumberOfDays(DateTime start, DateTime end) {
// assumes end > start
Dictionary<Tuple<int, int>, int> ret = new Dictionary<Tuple<int, int>, int>();
DateTime date = end;
while (date > start) {
if (date.Year == start.Year && date.Month == start.Month) {
ret.Add(
Tuple.Create<int, int>(date.Year, date.Month),
(date - start).Days + 1);
break;
} else {
ret.Add(
Tuple.Create<int, int>(date.Year, date.Month),
date.Day);
date = new DateTime(date.Year, date.Month, 1).AddDays(-1);
}
}
return ret;
}
static void Main(params string[] args) {
var days = GetNumberOfDays(new DateTime(2011, 3, 1), new DateTime(2011, 4, 1));
foreach (var m in days.Keys) {
Console.WriteLine("{0}/{1} : {2} days", m.Item1, m.Item2, days[m]);
}
}
}
You can use the class Month of the Time Period Library for .NET:
// ----------------------------------------------------------------------
public Dictionary<DateTime,int> CountMonthDays( DateTime start, DateTime end )
{
Dictionary<DateTime,int> monthDays = new Dictionary<DateTime, int>();
Month startMonth = new Month( start );
Month endMonth = new Month( end );
if ( startMonth.Equals( endMonth ) )
{
monthDays.Add( startMonth.Start, end.Subtract( start ).Days );
return monthDays;
}
Month month = startMonth;
while ( month.Start < endMonth.End )
{
if ( month.Equals( startMonth ) )
{
monthDays.Add( month.Start, month.DaysInMonth - start.Day + 1 );
}
else if ( month.Equals( endMonth ) )
{
monthDays.Add( month.Start, end.Day );
}
else
{
monthDays.Add( month.Start, month.DaysInMonth );
}
month = month.GetNextMonth();
}
return monthDays;
} // CountMonthDays
Usage:
// ----------------------------------------------------------------------
public void CountDaysByMonthSample()
{
DateTime start = new DateTime( 2011, 3, 30 );
DateTime end = new DateTime( 2011, 4, 5 );
Dictionary<DateTime, int> monthDays = CountMonthDays( start, end );
foreach ( KeyValuePair<DateTime, int> monthDay in monthDays )
{
Console.WriteLine( "month {0:d}, days {1}", monthDay.Key, monthDay.Value );
}
// > month 01.03.2011, days 2
// > month 01.04.2011, days 5
} // CountDaysByMonthSample
Simple yes, fast no:
DateTime StartDate = new DateTime(2011, 3, 30);
DateTime EndDate = new DateTime(2011, 4, 5);
int[] DaysPerMonth = new int[12];
while (EndDate > StartDate)
{
DaysPerMonth[StartDate.Month]++;
StartDate = StartDate.AddDays(1);
}
Here's my solution. I did a quick check and it seems to work... let me know if there are any problems:
public Dictionary<DateTime, int> GetMontsBetween(DateTime startDate, DateTime EndDate)
{
Dictionary<DateTime, int> rtnValues = new Dictionary<DateTime, int>();
DateTime startMonth = new DateTime(startDate.Year, startDate.Month, 1);
DateTime endMonth = new DateTime(EndDate.Year, EndDate.Month, 1);
//some checking
if (startDate >= EndDate)
{
rtnValues.Add(startMonth, 0); // Or return null;
}
else if (startDate.Month == EndDate.Month && startDate.Year == EndDate.Year)
{
rtnValues.Add(startMonth, EndDate.Day - startDate.Day);
}
else
{
//Add first month remaining days
rtnValues.Add(startMonth, DateTime.DaysInMonth(startDate.Year, startDate.Month) - startDate.Day);
//Add All months days inbetween
for (DateTime st = startMonth.AddMonths(1); st < endMonth; st = st.AddMonths(1))
{
rtnValues.Add(new DateTime(st.Year, st.Month, 1), DateTime.DaysInMonth(st.Year, st.Month) );
}
//Add last month days
rtnValues.Add(new DateTime(EndDate.Year, EndDate.Month, 1), EndDate.Day);
}
return rtnValues;
}
Little example of how we can accurately get the total months and days between 2 dates using the built-in DateTime.DaysInMonth method which gives us the number of days in each month so we can get 100% accuracy.
DateTime date1 = DateTime.Now.AddDays(60);
DateTime date2 = DateTime.Now;
TimeSpan ts = date1 - date2;
int totalDays = int.Parse(ts.TotalDays.ToString("0"));
int totalMonths = Math.Abs((date1.Month - date2.Month) + 12 * (date1.Year - date2.Year));
int months = 0;
int days = 0;
int totalDaysInMonths = 0;
for (int i = totalMonths; i > 0; i--)
{
int month = date2.Month + i;
int year = date1.Year;
if (month > 12)
{
year++;
int newMonth = month - 12;
month = newMonth;
}
totalDaysInMonths = totalDaysInMonths + DateTime.DaysInMonth(year, month);
}
if (totalDays > totalDaysInMonths)
{
months = totalMonths - 1;
days = totalDays - totalDaysInMonths;
}
else if (totalDays < totalDaysInMonths)
{
months = totalMonths - 1;
int tempTotalDaysInMonths = 0;
for (int i = months; i > 0; i--)
{
int month = date2.Month + i;
int year = date1.Year;
if (month > 12)
{
year++;
int newMonth = month - 12;
month = newMonth;
}
tempTotalDaysInMonths = tempTotalDaysInMonths + DateTime.DaysInMonth(year, month);
}
days = totalDays - tempTotalDaysInMonths;
}
else
{
months = totalMonths;
}
return string.Format("{0} months and {1} days", months, days);
A very quick and dirty run at it using linqpad:
DateTime start = DateTime.Parse("03/30/2011");
DateTime end = new DateTime(2011,04,05,23,59,59);
var startNextMonthFirstDay = new DateTime(start.Year, start.Month+1, 1);
var diffForStartMonth = (startNextMonthFirstDay - start);
var totalDiff = (end-start);
var diff = Math.Round(totalDiff.TotalDays);
var diffForEndMonth = diff - diffForStartMonth.Days;
Dictionary<DateTime, int> result = new Dictionary<DateTime, int>();
result.Add(new DateTime(start.Year, start.Month, 1), diffForStartMonth.Days);
result.Add(new DateTime(end.Year, end.Month, 1), (int)diffForEndMonth);
//Dictionary<DateTime,int>{{new DateTime(2011,3,1),2},{new DateTime(2011,4,1),5}}
result.Dump();
DateTime dt1 = new DateTime(2011, 12, 12);
DateTime dt2 = new DateTime(2011, 06, 12);
TimeSpan ts = dt1.Subtract(dt2);
String s = ts.Days.ToString();
MessageBox.Show(s);

Categories