NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » time structure check

February 04, 2010
by Solorbob
Solorbob's Avatar

If one had two time structures and wanted to see if timeA was greater or less than timeB, how would one go about it? Below is the structure def.

typedef struct { // structure for keeping time data

int seconds;

int minutes;

int hours;

}time;

. . .

time timeA,timeB;

thanks, Shawn

February 04, 2010
by Frozenlock
Frozenlock's Avatar

I'm quite a noob for writing in C, but if it's simply to check if timeA is greater than timeB, I would do sometime like this:

int A_bigger_B;
if (timeA.hours>timeB.hours){
    A_bigger_B=1;
}
elseif (timeA.minutes>timeB.minutes) {
    A_bigger_B=1;
}
elseif (timeA.seconds>timeB.seconds) {
    A_bigger_B=1;
else {
    A_bigger_B=0;
}

Warning, it doesn't check if there is an equality.

Frozenlock

February 04, 2010
by bretm
bretm's Avatar

If timeA is 4hr 30min and timeB is 5hr 20min, the first "if" will be skipped, but it will go into the second "if" because timeA.minutes is greater than timeB.minutes, so that's not quite right.

int sign = timeA.hours - timeB.hours;

if (sign == 0) 
{
    sign = timeA.minutes - timeB.minutes;
    if (sign == 0) sign = timeA.seconds - timeB.seconds;
}

I think that should work. Sign will be positive if A>B, negative if A<B, or zero if A=B.

February 05, 2010
by Solorbob
Solorbob's Avatar

Thanks all. I'll see if I can get my time checks working tonight.
Shawn

February 05, 2010
by Frozenlock
Frozenlock's Avatar

Didn't think of that, nice catch Solorbob!

February 05, 2010
by Frozenlock
Frozenlock's Avatar

Err, I meant bretm...

February 05, 2010
by N3Roaster
N3Roaster's Avatar

Another option to consider here is to simply convert the time structure to second equivalents and compare those. That is,

int a = (timeA.hours * 3600) + (timeA.minutes * 60) + timeA.seconds;
int b = (timeB.hours * 3600) + (timeB.minutes * 60) + timeB.seconds;

Then it's just a matter of comparing a with b.

February 05, 2010
by bretm
bretm's Avatar

That would work if sizeof(int) is 4, but it's probably going to be 2, so the expression will overflow at 9h 6m 8s.

February 06, 2010
by N3Roaster
N3Roaster's Avatar

Checking <stdint.h> shows you're right about the sizeof(int). If the overflow issue is relevant for this use, the basic concept still works. Just replace int with long int, unsigned long int, or if portability is required, a type that's explicit about how many bits it needs such as int32_t or uint32_t.

February 06, 2010
by Solorbob
Solorbob's Avatar

Thanks. I'll keep the overflow in mind while making the changes.

February 06, 2010
by wayward
wayward's Avatar

If you have the luxury of modifying the declaration of type "time", you could rewrite it into something more suitable for comparison; for example, (ab)using the fact that 16-bit AVRs are little-endian:

typedef union {
  struct {
    unsigned char s, m, h;
  } access;
  unsigned long value;
} time_t;

/* you can declare type_t variables and zero-initialize them at the same time,
   which is better than initializing them in the code block by writing
   t1.value = t2.value = 0;
 */
time_t t1 = {0}, t2 = {0};

// ...

t1.access.h = 1;
t1.access.m = 10;
t1.access.s = 10;

t2.access.h = 2;
t2.access.m = 5;
t2.access.s = 5;

// comparing t1.value and t2.value gives the result
if (t1.value < t2.value)
  ; // t1 was before t2
else if (t1.value > t2.value)
  ; // t1 was after t2
else
  ; // t1 and t2 mark the same point in time

NB. this works only on little-endian architectures, so 16-bit AVR (not AVR32 which is big-endian!) and x86 are both fine. For big-endianness you'd reverse the order of declarations inside the time_t.access struct, having hours up front and seconds at the end. Needless to say, use this approach only if you are 100% certain you will never ever want to port the code to another platform.

To wrap things up, here's a nifty function from Jan Wolter's UNIX Incompatibility Notes, showing how to determine endianness during runtime:

int am_big_endian()
{
   long one = 1;
   return !(*((char *)(&one)));
}

HTH, Zoran

February 07, 2010
by wayward
wayward's Avatar

Please replace all references to "16-bit AVR" with "8-bit AVR" in the above post. The code as shown would fail to work on a pure 16-bit architecture, anyway. :)

Post a Reply

Please log in to post a reply.

Did you know that you can follow NerdKits on Facebook, YouTube, and Twitter? Learn more...