4

I'm programming a microcontroller in C that has an internal RTC and automatically increments a day counter (0-65536). So, given the initial date adjusted by the user (DD/MM/YYYY), I need to keep the calendar updated based on that counter. That is, I need to know how to calculate the date after x days. Does anyone know an algorithm for that? Couldn't find anything all over the web.

Thanks in advance. Daniel

x29a
  • 1,761
  • 1
  • 24
  • 43
Daniel Santos
  • 41
  • 1
  • 2
  • Unless it's a project requirement that the RTC should be seeded with month and date as well, I would recommend skipping month and date and seed the RTC with january 1 and the requested year. It will be so much simpler to count then, and you only need to keep track of the year so save a couple of bytes there. – Some programmer dude Nov 03 '12 at 12:27

2 Answers2

3

As @moooeeeep suggests in his answer to the same question,

For the sake of clarity and correctness, you should stick to the existing solutions.

#include <stdio.h>
#include <time.h>

int main()
{        
    /* initialize */
    int y=1980, m=2, d=5;    
    struct tm t = { .tm_year=y-1900, /* The number of years since 1900   */ 
                    .tm_mon=m-1,  /* month, range 0 to 11 */
                    .tm_mday=d };
    /* modify */
    t.tm_mday += 40;
    mktime(&t);
    /* show result */
    printf("%s", asctime(&t)); /* prints: Sun Mar 16 00:00:00 1980 */
    return 0;
}
Community
  • 1
  • 1
Mehrad
  • 4,093
  • 4
  • 43
  • 61
0

Check this. Maybe it need some adjustments. Somewhat brute-force, but speed should be enough even for microcontroller.

#include <stdio.h>

static int days_in_month[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int day, month, year;

unsigned short day_counter;

int is_leap(int y) {
    return ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0);
}

next_day()
{
    day += 1; day_counter++;
    if (day > days_in_month[month]) {
        day = 1;
        month += 1;
        if (month > 12) {
            month = 1;
            year += 1;
            if (is_leap(year)) {
                days_in_month[2] = 29;
            } else {
                days_in_month[2] = 28;
            }
        }
    }
}

set_date(int d, int m, int y) 
{
    m < 1 ? m = 1 : 0;
    m > 12 ? m = 12 : 0;
    d < 1 ? d = 1 : 0;
    d > days_in_month[m] ? d = days_in_month[m] : 0;
    if (is_leap(y)){
        days_in_month[2] = 29;
    } else {
        days_in_month[2] = 28;
    }
    day = d;
    month = m;
    year = y;
}

skip_days(int x)
{
    int i;
    for (i=0;i<x;i++) next_day();
}

print_date()
{
    printf ("day: %d month: %d year: %d\n", day, month, year);
}

int main(int argc, char **argv)
{
    int i;

    set_date(5, 2, 1980);

    skip_days(10000);
    day_counter = 0;
    /* after this call next_day each day */

    print_date();

    return 0;
}
J X
  • 55
  • 5
  • as I understand, skipping will be used only on initial date setting, then each day only next_day() will be executed. about efficiency - 10000 days skipping one million times will take about 1,5 seconds on 16MHz microcontroller. this is not extremely. does your answer includes leap year correction? – J X Nov 04 '12 at 08:08
  • This doesn't seem to handle leap year days properly though. for example in this case **a leap year** (2016)/Feb/28 would change to 2016/Mar/1 if added by one day. The correct answer is 2016/Feb/29 of course. – Mehrad Sep 06 '16 at 05:25