Better way of getting day of year for a different calendar

Viewed 65

I'm trying to get the day of month for following calendar:

enter image description here

I wrote two different functions that accomplish this:

public int DayOfYear(int year, int month, int day)
{
 
    var months = new[] {31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30, 31};

    var dayOfYear = day;

    if (month == 1) return dayOfYear;
    for (var i = 0; i < month-1; i++)
    {
        dayOfYear += months[i];
    }

    return  dayOfYear;
}

And to do this without a loop:

public int DayOfYear(int year, int month, int day)
{
 
    var dayOfYear = day;
        
    if (month <= 5)
        dayOfYear += 31 * (month-1);
    else
        dayOfYear += 31 * 5 + 30 * ((month - 5) - 2);

    if (month == 12)
        dayOfYear += 31;
        
        
    return dayOfYear;
}

For the 12th month lets assume it has always 31 days. I feel that there is a beter mathematical way of doing this, but I can't really come up with it.

An example: (522, 12, 14) is the 349th day of the year according to my calendar. This is correct using both functions. And (522, 1, 1) would be the first day of the year.

For some visualization, (522, 5, 18) would be done as following: 31 + 31 + 31 + 31 + 18

And (522, 9, 18) as:

31 + 31 + 31 + 31 + 31 + 30 + 30 + 30 + 18

2 Answers

The one-line solution:

public int DayOfYear(int year, int month, int day) =>
   31 * (month - 1) - Math.Max(0, month - 6) + day;

It just assumes 31 days in each month before it first. so 31*(month-1), but since at 6th month it's 30 days so we subtract Math.Max(0, month-6), and then simply add the day(s).

It will work for leap years as well, but only for for valid dates.

Create a dictionary of month => total days up until that point.

private static readonly Dictionary<int, int> TotalDays = new Dictionary<int, int>
{
  [1] = 0,
  [2] = 31,
  [3] = 62,
  [4] = 93,
  // etc
};

// for day of month validation
private static readonly Dictionary<int, int> DaysPerMonth = new Dictionary<int, int>
{
  [1] = 31,
  [2] = 31,
  [3] = 31,
  [4] = 31,
  // etc
};

Then calculate the day of year based on the days up to that point plus the day of this month:

public int DayOfYear(int year, int month, int day)
{
    // validate your parameters 

    if (!TotalDays.TryGetValue(month, out var total)) 
        throw new Exception("invalid month");

    if (day <= 0 || day > DaysPerMonth[month]) 
       throw new Exception("day too big or small");

    return total + day;
}
Related