Problem: Calculating the Date from the Day Number of the Year in C

Problem

We want to create a function in C language that takes two values as input:

  • a number indicating the year;
  • a number indicating the number of days elapsed from January 1st of that year.

This function must return the month and the day of the month corresponding to them.

For example, taking as input the values year = 2023 and days = 156, it should return as output the values month = 6 (that is, June) and day = 5.

Implementation

As can be inferred from the exercise text, the function to be implemented must take two values as input and return two values as output. This is why we must use pointers as function arguments.

The possible function signature can be the following:

void calculate_date(unsigned int year,
                    unsigned int day_of_the_year,
                    unsigned int *month,
                    unsigned int *day);

First of all, we must note that the months of the year do not have equal duration. Some months are 30 days long, others 31, while February is 28 days long.

To handle these differences, we can use an array that contains the number of days corresponding to each month:

void calculate_date(unsigned int year,
                    unsigned int day_of_the_year,
                    unsigned int *month,
                    unsigned int *day) {

    unsigned int days_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    /* ... */
}

The days_month array contains the days of the month according to the corresponding index. So 0 equals January and therefore the corresponding value will be 31. Similarly, February will correspond to index 1, so at the location with index 1 the value 28 is stored, and so on.

The second step consists of verifying whether the year passed as a parameter is a leap year or not. In case it is a leap year, we must change the value corresponding to the number of days in February.

A year is a leap year when:

  • It is not a secular year (that is, it is not divisible by 100) and is divisible by 4;
  • Or it is a secular year divisible by 400.

Therefore:

void calculate_date(unsigned int year,
                    unsigned int day_of_the_year,
                    unsigned int *month,
                    unsigned int *day) {

    unsigned int days_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    /* Verify if the year is a leap year or not */
    if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
        /* In case of a leap year, add one day to February */
        days_month[1] = 29;
    }

    /* ... */
}

The next step consists of creating a for loop that iterates through the months and subtracts the number of days corresponding to the value of day_of_the_year. The loop terminates when the number of remaining days is less than the number of days in the next month. In that case, the index of the for loop represents the calculated month.

Therefore, we add a support variable i for the loop and write the function this way:

void calculate_date(unsigned int year,
                    unsigned int day_of_the_year,
                    unsigned int *month,
                    unsigned int *day) {

    unsigned int days_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    /* Verify if the year is a leap year or not */
    if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
        /* In case of a leap year, add one day to February */
        days_month[1] = 29;
    }

    /*
     * Iterate through the days_month array and decrement day_of_the_year
     * until reaching the corresponding month,
     * that is, when day_of_the_year is less than or equal to the number
     * of days in the current month
     */
    for (i = 0; day_of_the_year > days_month[i]; i++) {
        day_of_the_year -= days_month[i];
    }

    *month = i + 1;
    *day = day_of_the_year;
}

Complete Program

Let's now try to write the complete program:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>

void calculate_date(unsigned int year,
                    unsigned int day_of_the_year,
                    unsigned int *month,
                    unsigned int *day);

int main() {
    unsigned int year, day_of_the_year, month, day;

    printf("Enter the year: ");
    scanf("%u", &year);

    printf("Enter the day of the year: ");
    scanf("%u", &day_of_the_year);

    calculate_date(year, day_of_the_year, &month, &day);

    printf("Day %u of year %u corresponds to %u/%u/%u\n",
              day_of_the_year, year, day, month, year);

    return 0;
}

void calculate_date(unsigned int year,
                    unsigned int day_of_the_year,
                    unsigned int *month,
                    unsigned int *day) {

    unsigned int days_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    unsigned int i;

    /* Verify if the year is a leap year or not */
    if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
        /* In case of a leap year, add one day to February */
        days_month[1] = 29;
    }

    /*
     * Iterate through the days_month array and decrement day_of_the_year
     * until reaching the corresponding month,
     * that is, when day_of_the_year is less than or equal to the number
     * of days in the current month
     */
    for (i = 0; day_of_the_year > days_month[i]; i++) {
        day_of_the_year -= days_month[i];
    }

    *month = i + 1;
    *day = day_of_the_year;
}

If we try to compile and execute the program, we get:

Enter the year: 2019
Enter the day of the year: 365
Day 365 of year 2019 corresponds to 31/12/2019

Trying to execute with different data, we get:

Enter the year: 2023
Enter the day of the year: 156
Day 156 of year 2023 corresponds to 5/6/2023