Take the 2-minute tour ×
Electrical Engineering Stack Exchange is a question and answer site for electronics and electrical engineering professionals, students, and enthusiasts. It's 100% free, no registration required.

I have written the following function to calculate the current timestamp (since 00h Jan 1 1900). The output I get is:

Current Time & Date : 20:5:32 25/7/2014<\r>
2014 7 25 20 5 32<\r>
retval 1 3597523200<\r>
retval 2 3597523200<\r>
retval 3 3613161600<\r>
retval 4 3615235200<\r>
retval 5 3615241664<\r>
retval 6 3615241964<\r>
retval 7 3615241996<\r>
retval 8 3615241996<\r>
Current time timestamp 3615241996

Basically I am printing the retval (function return value) at every step to check and verify the calculations.

The calculation match up till retval 4 (when current day hours are converted to seconds). I think it might be due to arithmetic overflow but not sure.

The issue seems to be happening in this line:

retval += (d.hr * 60 * 60); printf("retval 5 %"PRIu32"\r", retval);

retval is uint32_t and d.hr is uint16_t

uint32_t DS1307_GET_CURRENT_TIMESTAMP()
{
    uint32_t retval = SECONDS_SINCE_1900_TO_2014;
    ds1307 d;
    DS1307_GET_DATETIME(&d);
    printf("%u %u %u %u %u %u\r", d.yy,d.mm,d.dd,d.hr, d.min, d.sec);
    printf("retval 1 %"PRIu32"\r", retval);
    //process complete years since 2014 to current year
    uint8_t i=0;
    for(i=0; i<(d.yy - 2014); i++)
    {
        if(DS1307_IS_LEAP_YEAR(2014+i)==0) retval += 31622400;
        else retval += 31536000;
    }
        printf("retval 2 %"PRIu32"\r", retval);

    //process complete months from beginning of current year to current date/time
    for(i=1; i<d.mm; i++)
    {
        if((i==1) || (i==3) || (i==5) || (i==7) || (i==8) || (i==10) || (i==12))
        {
            //31 days
            retval += (31 * 86400);
        }
        else if ((i==4) || (i==6) || (i==9) || (i==11))
        {
            //30 days
            retval += (30 * 86400);
        }
        else 
        {
            //i==2==february. check if leap year
            if(DS1307_IS_LEAP_YEAR(d.yy)==0) retval += (29 * 86400);
            else retval += (28 * 86400);
        }
    }
        printf("retval 3 %"PRIu32"\r", retval);

    //process complete days from beginning of month till current date
    retval += ((d.dd-1) * 86400);
    printf("retval 4 %"PRIu32"\r", retval);

    //process hours, min and seconds - CALCULATION DEVIATES HERE.
    retval += (d.hr * 60 * 60); printf("retval 5 %"PRIu32"\r", retval);
    retval += (d.min * 60); printf("retval 6 %"PRIu32"\r", retval);
    retval += d.sec; printf("retval 7 %"PRIu32"\r", retval);

        printf("retval 8 %"PRIu32"\r", retval);

    return retval;
}
share|improve this question

2 Answers 2

up vote 2 down vote accepted

20 * 60 * 60 = 72000

You need to perform the multiplication in 32 bits in order to avoid an overflow.

retval += (d.hr * 60UL * 60);
share|improve this answer
    
Ok. So when I write a c arithmetic statement (multiplication in this context) how does c decide what would be the overflow point or what's the maximum size of that operation? Does it depend on the size of the storage registers the platform provides (16 bit in AVR case)? –  Ankit Jul 25 '14 at 20:56
    
It depends on the size of int unless one of the operands overrides it, hence the L suffix on the literal (for long). –  Ignacio Vazquez-Abrams Jul 25 '14 at 21:23
    
Now that I think about it, there's no reason for it to be signed... –  Ignacio Vazquez-Abrams Jul 25 '14 at 23:21
    
This fixed it. Thank you ! –  Ankit Jul 26 '14 at 6:27

(3615235200-3613161600)/(24*60*60) = 24, so the change at 'retval 4' is correct and not an overflow, so your assertion that they are correct "til you get to retval 4" is false.

retval 5 however gives (3615241664-3615235200) = 60*60*20 - 2**16, so there is an overflow. Use a uint32_t on the right hand side of retval += d.hr * uint32_t(60 * 60u).

Before your edit, you were missing a space between "retval 3" and "3613161600" .

share|improve this answer
    
The space after retval 3 is a typo. I'm taking that into consideration. Also as mentioned, retval 4 is correct. It's retval 5 that is giving the wrong result. Lastly, as shown in output, the code is being run @ July 25, 2014 –  Ankit Jul 25 '14 at 16:14

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.