## Best way to parse total seconds to hour,min,sec

9 posts / 0 new
Author
Message

Trying to convert a 32bit register containing the current time of day in seconds into hours(24), min, sec format.

Using this causes time_calc to explode at the hours = (time_calc/3600) line.

```	hours = (time_calc/3600); //load up the hours
time_calc = (time_calc - (hours*3600));
minutes = time_calc/60; //load up the minutes
time_calc = (time_calc - (minutes*60));
seconds = time_calc;
```

time_calc has a value of 71166 going into this. After the 1st line hours goes to 19, which is correct, but time_calc goes to 181272576. I cant figure out why that's happening.

You don't gno-me!

Lets see your variable declarations. Hours is probably decalred as a char so the hours * 3600 won't work too well. You'll need to cast the variables to force the compiler to do 32bit calcs.

eg:
time_calc = time_calc - ((uint32_t)hours * 3600L);

also read up on the modulus % operator.

Quote:
also read up on the modulus % operator.
Using modulus would be wasteful here as it would invoke a second divide. However you can use ldiv() to get both the quot and the remainder in one divide.

Regards,
Steve A.

The Board helps those that help themselves.

Kartman wrote:

```	volatile uint32_t time_temp=0, time_calc=0;
volatile uint8_t hours=0, minutes=0, seconds=0;```

I changed to:

```time_calc = time_temp;
hours = ((uint32_t)time_calc/3600L); //load up the hours
time_calc = time_calc - ((uint32_t)hours * 3600L);
minutes = time_calc/60; //load up the minutes
time_calc = (time_calc - (minutes*60));
seconds = time_calc;```

and ran it and for whatever reason it seems to work. Although I cant understand why it works because after it runs hours = ((uint32_t)time_calc/3600L); time_calc goes to some ridiculously high value still. But the minutes calculation seems to come out correct still. Why would that line cause the value of time_calc to change when it shouldn't?

As I single step though the lines:
Going into: hours = ((uint32_t)time_calc/3600L); //load up the hour
time_calc value is 78886
On the next line: time_calc = time_calc - ((uint32_t)hours * 3600L);
hours is 21 and time_calc is 215351296 (wrong!)
Next: minutes = time_calc/60; //load up the minutes
time_calc is 3286
next: time_calc = (time_calc - (minutes*60));
time_calc is 3286 and minutes is 54
then the next two time_calc and sec turn into 46

You don't gno-me!

When single stepping, you may get weird values displayed as the compiler may not necessarily order the code as you expect. If you do a printf of the results, are they correct?

The next question is what toolset are you using? I did see some defect reports recently.

Koshchi wrote:
Using modulus would be wasteful here as it would invoke a second divide.
Well, you could use an optimizing compiler like avr-gcc.

With the current version of that compiler and optimizing for code size, you'll get

```toHMS:
ldi r18,lo8(60)
ldi r19,0
ldi r20,0
ldi r21,0
rcall __udivmodsi4
sts seconds,r22
movw r24,r18
ldi r22,lo8(60)
ldi r23,0
rcall __udivmodhi4
sts minutes,r24
sts hours,r22
ret```

out of

```unsigned char hours, minutes, seconds;

void toHMS (unsigned long time_calc)
{
unsigned tc;
seconds = time_calc % 60;
tc = time_calc / 60;

minutes = tc % 60;
hours   = tc / 60;
}
```

If you are after code site rather than after speed, you can perform the second divmod as long.

avrfreaks does not support Opera. Profile inactive.

As hours will be fairly small (0-23), and minutes also a rather small number (0-59) I think that repeated subtraction (as might be used for binary->BCD) might work out fine.

(Nice compiler work recognizing the divmod situation without explicitly being invoked.)

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.