bluebrigade23
bluebrigade23

Reputation: 71

Calculating months between 2 dates, then calculating days in each month

So I'm trying to create a graph by getting the start and end date from the user. I need to count the number of months between the dates, then for each month calculate the number of days and get the name of the month as well.

I've got the number of months between the 2 dates but can't seem to translate the remaining into code. I have a class called MonthRange

public class MonthRange
{
    public DateTime startDate { get; set; }

    public DateTime endDate { get; set; }

    public string monthName { get; set; }

    public MonthRange() {
    }

    public MonthRange(DateTime startDate, DateTime endDate, string monthName) {
        this.startDate = startDate;
        this.endDate = endDate;
        this.monthName = monthName;
    }
}

And my method:

private List<MonthRange> GetRangeOfMonthsBetweenDates(DateTime startDate, DateTime endDate) {

     List<MonthRange> result = new List<MonthRange>();
     int months = (endDate.Year - startDate.Year)*12 + endDate.Month - startDate.month;

foreach(var m in months){
     //get the start and end date of that month with the name and add it to the result list.
}

}

The kicker is that if the startDate is midway through the month, then that is what should be saved in the result list, likewise if the endDate is midway of the month, that is what should be saved. I'm a bit lost and would appreciate any help.

Edit: So this is an example of what I'm trying to achieve. I'm trying to create a graph that plots the number of times a person has had food in a given time range.

Edit 2: So i ended up going this way:

 private List<MonthRange> GetRangeOfMonthsBetweenDates(DateTime startDate, DateTime endDate) {

        List<MonthRange> result = new List<MonthRange>();

        DateTime holder = startDate;

        var months = (endDate.Year - startDate.Year) * 12 + endDate.Month - startDate.Month;


        for (int i = 0; i <= months; i++) {
            if (i == 0)
            {
                result.Add(new MonthRange(startDate, CalculateStartOfMonth(endDate), startDate.ToString("MMM")));
            }
            else if (i == months)
            {
                result.Add(new MonthRange(CalculateEndOfMonth(startDate), endDate, endDate.ToString("MMM")));
            }
            else {
                DateTime middleMonth = holder.AddMonths(1);
                result.Add(new MonthRange(CalculateStartOfMonth(middleMonth), CalculateEndOfMonth(middleMonth), middleMonth.ToString("MMM")));
            }
        }

        return result;
    }

    private DateTime CalculateStartOfMonth(DateTime endDate) {
        var startOfMonth = new DateTime(endDate.Year, endDate.Month, 1);
        return startOfMonth;
    }

    private DateTime CalculateEndOfMonth(DateTime startDate)
    {
        var endOfMonth = new DateTime(startDate.Year, startDate.Month, DateTime.DaysInMonth(startDate.Year, startDate.Month));
        return endOfMonth;
    }

Upvotes: 0

Views: 139

Answers (3)

xxbbcc
xxbbcc

Reputation: 17366

Note: this is not an answer to the question but a suggestion for a different approach. Since the question is about charting number of meals for a person over a period, I think the natural way to approach this (at least for representing the data) is to do it by day, not by month. (Visually, the data may have to be represented by month but it's much easier to first organize the data by days and then render it by month.)

Since the question is rather vague, I made some assumptions about the data. This class could be used to store information about a single day.

class DayEntry
{
    public DateTime Date { get; set; }
    public string MonthName { get; set; }
    public int NumberOfMeals { get; set; }
}

The following function creates a list of DayEntry objects, initialized for each day in the date range:

List<DayEntry> CreateDayEntries(DateTime dateStart, DateTime dateEnd)
{
    var dateDiff = dateEnd - dateStart;
    var dayCount = (int) Math.Ceiling(dateDiff.TotalDays) + 1;
    var dayRange = new List<DayEntry>(dayCount);

    for (var i = 0; i < dayCount; i++)
    {
        var date = dateStart.AddDays(i);
        var dayEntry = new DayEntry
        {
            Date = date,
            NumberOfMeals = 0, // TODO
            MonthName = date.ToString("MMMM", CultureInfo.CurrentCulture) 
        };

        dayRange.Add(dayEntry);
    }

    return (dayRange);
}

When the data is prepared for the given date range, it can then be shown in a UI, grouped by month - since each day entry has its own date (with the name of the month it belongs to) and are in order in the list, it's easy to iterate through them and create the UI output.

Upvotes: 1

IronGeek
IronGeek

Reputation: 4883

Based on your MonthRange structure, try this:

private IEnumerable<MonthRange> GetRangeOfMonthsBetweenDates(DateTime startDate, DateTime endDate) {        
    var start = startDate;  
    while(start<endDate) {
        var end = start.AddMonths(1).AddDays(-start.Day);           
        yield return new MonthRange(start, end < endDate ? end : endDate, start.ToString("MMMM"));

        start = end.AddDays(1);
    }
}

For example:

var start = new DateTime(2017,5,16);
var end = new DateTime(2017,7,24);

foreach(var m in GetRangeOfMonthsBetweenDates(start, end)) {
    Console.WriteLine("{0}: {1:dd/MM/yyyy}-{2:dd/MM/yyyy}", m.monthName, m.startDate, m.endDate);
}

Should print:

May: 16/05/2017-31/05/2017
June: 01/06/2017-30/06/2017
July: 01/07/2017-24/07/2017

Upvotes: 1

Hank
Hank

Reputation: 187

What i would suggest is for you to convert everything into days first.

eg. x= 361 ; // total number of days

then from there you can split them up into months and years .

months = x/30; // find months 
days = x%30; // find the remainder of the days from the month
years = months/12; // find years

This way its much easier to calculate.

Upvotes: 0

Related Questions