1
\$\begingroup\$

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;
}
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

20 * 60 * 60 = 72000

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

retval += (d.hr * 60UL * 60);
\$\endgroup\$
3
  • \$\begingroup\$ 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)? \$\endgroup\$
    – Ankit
    Jul 25, 2014 at 20:56
  • \$\begingroup\$ It depends on the size of int unless one of the operands overrides it, hence the L suffix on the literal (for long). \$\endgroup\$ Jul 25, 2014 at 21:23
  • \$\begingroup\$ Now that I think about it, there's no reason for it to be signed... \$\endgroup\$ Jul 25, 2014 at 23:21
0
\$\begingroup\$

(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" .

\$\endgroup\$
1
  • \$\begingroup\$ 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 \$\endgroup\$
    – Ankit
    Jul 25, 2014 at 16:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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