Number of Years

E

Eric Sosman

John said:
Eric Sosman said:
John said:
:


John F wrote:

[SNIP]

Use long instead.

why not just:

const long SEC_IN_YEAR=365*24*60*60;

Because if 31536000 does not fit in an int, this
will initialize SEC_IN_YEAR to the wrong value. (If
it manages to initialize SEC_IN_YEAR at all, that is:
this might be undefined behavior.)

Are you sure about this?

Yes. All three multiplications follow the rules for `int'
arithmetic, after which the result is converted to `long'. If
the product is too large for `int', Evil Things will happen.


I can see it now. I usually do not encounter it on my 32 bit targets
where both long and int are 32 bits wide.
That's why I was not so sure at first. But you are right it is a
matter of portability.

Strange how we can spot a problem in one context and then
completely miss the same flaw in another. You were the first
to mention that 31536000 might be too large for an `int',
suggesting you were well aware of the possiblity of an `int'
with fewer than ((runs a few logarithms)) 26 bits. And yet
you got tripped up by long experience with 32-bit `int' ...

Somewhere there's somebody working on a PhD thesis about
how to design programming languages/frameworks/what-have-you
so such oversights are harder to commit. Alas, I suspect the
PhD candidate is probably steeped in computer science when he
really ought to have a background in cognitive psychology ...

Meanwhile, I'll just keep kicking myself in the rear end
whenever I find I've made such a blunder. Unfortunately, it's
becoming uncomfortable to sit ...
 
D

David Paleino

Gregc. ha scritto:
G'day

I'm trying to work out the number of years since 1970, here is my code:

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


const int SEC_IN_MIN = 60;
const int SEC_IN_HOUR = SEC_IN_MIN * 60;
const int SEC_IN_DAY = SEC_IN_HOUR * 24;
const int SEC_IN_YEAR = SEC_IN_DAY * 365;


int secToYear(int seconds) //Function Protoype
{
seconds = (SEC_IN_YEAR);
return (seconds);
}


main () {
time_t now = time(0);
printf("%i seconds since 1/1/1970\n",secToYear(now));


}

For some reason the answer is coming out as 1. Could someone offer me
some guidance.

Sure. :)
You could use this code:

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

const int SEC_IN_YEAR = 31536000; /* Average seconds per year */

int main(void)
{
double years_r, months_r, days_r, hours_r, mins_r, secs_r;
/* "_r" stands for "raw" */
int years, months, days, hours, mins, secs;
time_t seconds;

seconds = time(NULL);

years_r = (double) seconds / SEC_IN_YEAR;
years = abs(years_r);

months_r = (years_r - (double)years) * 12;
months = abs(months_r);

days_r = (months_r - (double)months) * 30; /* Average days
per month... Who can write something better? */
days = abs(days_r);

hours_r = (days_r - (double)days) * 24;
hours = abs(hours_r);

mins_r = (hours_r - (double)hours) * 60;
mins = abs(mins_r);

secs_r = (mins_r - (double)mins) * 60;
secs = abs(secs_r);

printf("Years:\t%d\n", years);
printf("Months:\t%d\n", months);
printf("Days:\t%d\n", days);
printf("Hours:\t%d\n", hours);
printf("Mins:\t%d\n", mins);
printf("Secs:\t%d\n", secs);
printf("\n");
return 0;
}
---------------------------------------------------

It simply calculates years, months, days, hours, minutes and seconds
from 00:00:00 Jan 1, 1970 (also known as "Epoch").

If you just need the number of years, just delete all the code from
"months_r = (years_r ..." to "secs = abs(...". You should also fix the
variables declarations, and delete all those printfs...

No problem :)

David


P.S.: please tell me if this code is non-standard C... I've successfully
compiled it with `gcc -Wall -Wextra -ansi -pedantic'... (I'm just
learning C :p)
 
J

John F

Eric Sosman said:
John said:
Eric Sosman said:
John F wrote:

:


John F wrote:

[SNIP]


Use long instead.

why not just:

const long SEC_IN_YEAR=365*24*60*60;

Because if 31536000 does not fit in an int, this
will initialize SEC_IN_YEAR to the wrong value. (If
it manages to initialize SEC_IN_YEAR at all, that is:
this might be undefined behavior.)

Are you sure about this?

Yes. All three multiplications follow the rules for `int'
arithmetic, after which the result is converted to `long'. If
the product is too large for `int', Evil Things will happen.


I can see it now. I usually do not encounter it on my 32 bit
targets where both long and int are 32 bits wide.
That's why I was not so sure at first. But you are right it is a
matter of portability.

Strange how we can spot a problem in one context and then
completely miss the same flaw in another. You were the first
to mention that 31536000 might be too large for an `int',
suggesting you were well aware of the possiblity of an `int'
with fewer than ((runs a few logarithms)) 26 bits. And yet
you got tripped up by long experience with 32-bit `int' ...

That is what I call the convenience-effect. One gets used to code
messy really easily. I sometimes code for 8 bit. That's where reality
strikes back. This case shows that I need such a project again soon
:)
Somewhere there's somebody working on a PhD thesis about
how to design programming languages/frameworks/what-have-you
so such oversights are harder to commit.

*chuckle* Nice. I'm wondering what the rest of the experts were doing
the past decades...
Alas, I suspect the
PhD candidate is probably steeped in computer science when he
really ought to have a background in cognitive psychology ...

That's an argument for comparative interdomain studies... I did a
small part of chaos theory back then. Seems to stick with me now ;-)
Meanwhile, I'll just keep kicking myself in the rear end
whenever I find I've made such a blunder. Unfortunately, it's
becoming uncomfortable to sit ...

To make it on topic... Seems to be proportional to the (Number of
Years) ;-)

I recently added an additional layer of abstraction to such actions.
(Besides it is quite hard to actually kick oneself into benamed
areas...)

[OT]
something like

struct rear_end {
/*log momentanous color here*/
double red,
double green,
double blue
};

struct damping {
/*soft filter characteristics*/
double factor,
double attack,
double decay
};

struct damped_rear {
struct rear_end rear,
struct damping *softstuff
};

union rear_u{
struct damped_rear damped,
struct rear_end undamped
};

/*Do some intermediate layer work here..*/
int ProtectedRear(union rear_u* MyRear);

/*Without protection:*/
int UnprotectedRear(union rear_u* MyRear);

You know what I mean?
[/OT]

regards
John
 
R

Richard G. Riley

Gregc. ha scritto:

Wouldnt you like to avoid all that nasty seconds stuff?

Take a look at localtime() and time()

struct tm *timeThen;
time_t t;
time(&t);
timeThen = localtime(&t);

There you have all your discrete time elements at your beck and
call. I cant vouch for platform independance though. In my debugger I
see:

$3 = {tm_sec = 17, tm_min = 23, tm_hour = 17, tm_mday = 12, tm_mon = 2,
tm_year = 106, tm_wday = 0, tm_yday = 70, tm_isdst = 0, tm_gmtoff = 3600,
tm_zone = 0x804a040 "CET"}

The rest is trivial and a lot cleaner IMO.
 
K

Keith Thompson

David Paleino said:
Gregc. ha scritto:
I'm trying to work out the number of years since 1970, here is my code:
[bad code snipped]

For some reason the answer is coming out as 1. Could someone offer me
some guidance.

Sure. :)
You could use this code:

--------------------------------------------------- [better code snipped]
---------------------------------------------------

If a beginning programmer is asking for help with a program, supplying
him with a complete solution might not be the best way to help him
learn.
It simply calculates years, months, days, hours, minutes and seconds
from 00:00:00 Jan 1, 1970 (also known as "Epoch"). [...]
P.S.: please tell me if this code is non-standard C... I've successfully
compiled it with `gcc -Wall -Wextra -ansi -pedantic'... (I'm just
learning C :p)

I don't see anything non-standard in the code itself, but it does make
an assumption about the representation of time_t. On many systems,
time_t is a signed integer representing the number of seconds since
1970-01-01 00:00:00 GMT (I'd refer to it as UTC, but the UTC standard
wasn't introduced until some time after 1970). But the standard only
says that time_t is an arithmetic type capable of representing times.
Assuming that it's an integer type, or that its resolution is 1
second, or that 0 represents any particular epoch, or even that values
of time_t linearly and monotonically increase with increasing times,
is, strictly speaking, non-portable. You might never run across a
system that uses any other representation for time_t -- which means
that you might never detect the error by testing your code.

If you want to analyze time_t values portably, use localtime().
 
K

Keith Thompson

Richard G. Riley said:
Wouldnt you like to avoid all that nasty seconds stuff?

Take a look at localtime() and time()

struct tm *timeThen;
time_t t;
time(&t);
timeThen = localtime(&t);

There you have all your discrete time elements at your beck and
call. I cant vouch for platform independance though. In my debugger I
see:

$3 = {tm_sec = 17, tm_min = 23, tm_hour = 17, tm_mday = 12, tm_mon = 2,
tm_year = 106, tm_wday = 0, tm_yday = 70, tm_isdst = 0, tm_gmtoff = 3600,
tm_zone = 0x804a040 "CET"}

Better yet, look at the actual specification of the "struct tm" type.
An implementation is allowed to provide extra members. Yours
apparently has done so; tm_gmtoff and tm_zone are non-standard.

The required members of struct tm, according to the C99 standard, are:

int tm_sec; // seconds after the minute -- [0, 60]
int tm_min; // minutes after the hour -- [0, 59]
int tm_hour; // hours since midnight -- [0, 23]
int tm_mday; // day of the month -- [1, 31]
int tm_mon; // months since January -- [0, 11]
int tm_year; // years since 1900
int tm_wday; // days since Sunday -- [0, 6]
int tm_yday; // days since January 1 -- [0, 365]
int tm_isdst; // Daylight Saving Time flag

The value of tm_isdst is positive if Daylight Saving Time is in
effect, zero if Daylight Saving Time is not in effect, and
negative if the information is not available.
 
R

Richard G. Riley

Better yet, look at the actual specification of the "struct tm"
type.

Interesting point : the dump was more to show the "human readable
numbers", but I'm not so impressed with the man page definition
disagreeing with the compile time structure definition. Not that it
makes one iota of differenc for the problem in hand : possibly more
important in std.c.

But you would agree this is a tidier way of solving this problem?
 
D

Default User

Nick Keighley wrote:

I must be missing something. Why not just calculate the current year
(use localtime()) then subtract 1970?

That's what I was thinking. If I want to know how many years it's been
since, say, 1999, I don't go converting things to seconds. I compute
2006 - 1999 and get 7.

That assumes you only want whole years, which is what the OP's
follow-up post indicated.




Brian
 
K

Keith Thompson

Richard G. Riley said:
type.

Interesting point : the dump was more to show the "human readable
numbers", but I'm not so impressed with the man page definition
disagreeing with the compile time structure definition. Not that it
makes one iota of differenc for the problem in hand : possibly more
important in std.c.

What are you unimpressed about? The standard specifically says that
an implementation is allowed to add extra members. I don't know what
the man page says; it could follow either the standard or the
system-specific definition (if it does the latter, it should
acknowledge that two of the fields are implementation-defined.

Reading n1124 (or some other draft of the standard) would have avoided
this confusion.
But you would agree this is a tidier way of solving this problem?

If by "this" you mean using a debugger, no. If you mean using
localtime() rather than doing arithmetic on time_t values, I've
already addressed that point in this thread.
 
R

Richard G. Riley

What are you unimpressed about? The standard specifically says that
an implementation is allowed to add extra members. I don't know
what

Sigh. Its not easy here.

I'm not impressed because the dcoumentaion is different from the
implementation on a live development system.
the man page says; it could follow either the standard or the
system-specific definition (if it does the latter, it should
acknowledge that two of the fields are implementation-defined.

Reading n1124 (or some other draft of the standard) would have avoided
this confusion.

It would : but wouldnt have made one iota of difference to *my*
system. And since the OPs requirement was contained within the
standard there was no confusion : until you bought one up.
If by "this" you mean using a debugger, no. If you mean using

Whyt would I be referring to using a debugger? Are you always this
purposely obtuse? Of course I'm referring to the use of localtime
instead of oodles of seconds calculations.
localtime() rather than doing arithmetic on time_t values, I've
already addressed that point in this thread.

'Fraid I never saw it.
 
J

Jordan Abel

type.

Interesting point : the dump was more to show the "human readable
numbers", but I'm not so impressed with the man page definition
disagreeing with the compile time structure definition. Not that it
makes one iota of differenc for the problem in hand

Some implementations have extensions that are "hidden" if certain macros
are enabled or disabled. gmtoff and zone are bsd extensions, i believe.
 
K

Keith Thompson

Richard G. Riley said:
what

Sigh. Its not easy here.

I'm not impressed because the dcoumentaion is different from the
implementation on a live development system.

Ok, so the documentation shows the members of struct tm that are
specified in the standard, but the implementation (for whatever
reason) has some extra members. I don't have a problem with that. It
might be nice for the man page to mention the extra members *if and
only if* it makes it clear that they're not standard, and that any
code that attempts to use them will be non-portable.
It would : but wouldnt have made one iota of difference to *my*
system. And since the OPs requirement was contained within the
standard there was no confusion : until you bought one up.

You were the first one to mention the extra members (tm_gmtoff and
tm_zone) because you chose to show us the output of your debugger.
Whyt would I be referring to using a debugger? Are you always this
purposely obtuse? Of course I'm referring to the use of localtime
instead of oodles of seconds calculations.

You've been misunderstood enough times here that I'd think you'd allow
for the possibility that you're unclear.
'Fraid I never saw it.

GIYF.
 
R

Richard G. Riley

Ok, so the documentation shows the members of struct tm that are
specified in the standard, but the implementation (for whatever
reason) has some extra members. I don't have a problem with that.
It

Thats a relief.
might be nice for the man page to mention the extra members *if and
only if* it makes it clear that they're not standard, and that any
code that attempts to use them will be non-portable.

Actually it should mention them all the time : otherwise how the hell
will the programmer know what the hell they're for on that platform?
You were the first one to mention the extra members (tm_gmtoff and
tm_zone) because you chose to show us the output of your debugger.

Actually I never "mentioned them" directly : you bought attention to
them. I also mentioned that I couldnt state platform independance.
You bought them up just to make a point about the standards. Again.

So you have dragged a bit of sample code, that showed typical values
down to a slanging match over some platform independant fields which
had nothing to do with the required solution. I salute you.
You've been misunderstood enough times here that I'd think you'd allow
for the possibility that you're unclear.

Yawn. Petty and spiteful. I am surprised. And also untrue. Want to be
confused? Dress up as a newbie and go back to that globals chat.

It was perfectly obvious that I didnt mean the debugger "solved the
problem". How the hell does a debugger make reference to the correct
data structure and write sample code to get the guy going? Do you have
a cupboard full of Pedant medals?

Please dont use acronyms. It makes you angry.
 
K

Keith Thompson

Richard G. Riley said:
It

Thats a relief.


Actually it should mention them all the time : otherwise how the hell
will the programmer know what the hell they're for on that platform?

Perhaps they're only used internally, and not intended for user code.

FILE is typically a struct. I don't expect man pages or other user
documentation to explain all the members, since they're not part of
the intended programmer interface.
Actually I never "mentioned them" directly : you bought attention to
them. I also mentioned that I couldnt state platform independance.
You bought them up just to make a point about the standards. Again.

So you have dragged a bit of sample code, that showed typical values
down to a slanging match over some platform independant fields which
had nothing to do with the required solution. I salute you.

You couldn't state platform independence. I could and did. I don't
know why you have a problem with that.
Yawn. Petty and spiteful. I am surprised. And also untrue. Want to be
confused? Dress up as a newbie and go back to that globals chat.

It was perfectly obvious that I didnt mean the debugger "solved the
problem". How the hell does a debugger make reference to the correct
data structure and write sample code to get the guy going? Do you have
a cupboard full of Pedant medals?

I truly wasn't entirely sure what you meant, so I covered both
possibilities. Again, I don't know why you have a problem with that,
or why you choose to share whatever problem you might have with the
rest of us.
Please dont use acronyms. It makes you angry.

Nonsense.
 
G

Gregc.

Basically what I am trying to achieve is calculate the number of years
since 1/1/1970 (which apparently is the start of unix), using in the
time_t (now) procedure.

Greg
 
R

Richard Heathfield

Gregc. said:
Basically what I am trying to achieve is calculate the number of years
since 1/1/1970 (which apparently is the start of unix), using in the
time_t (now) procedure.

Basically you can succeed in achieving this by calling time() to get the
current time as a time_t, passing it to localtime() to get a pointer to a
struct tm, and then looking at the struct's tm_year member, which contains
the number of years since 1900 (i.e. 106 this year). Clearly, the number of
years since 1970 will be that value - 70. To calculate fractions of a year,
look at the tm_mon and tm_mday members too, and do the obvious with them.
 
G

ggrater

Wow! Now that was a fun rant to read...programmers with *way* too much
time on their hands. Really guys...come on...36 messages and GregC
still does have a solid function to call. Thanks for wasting all of
our time...since 1970.
 
V

Vladimir S. Oka

Wow! Now that was a fun rant to read...programmers with *way* too much
time on their hands. Really guys...come on...36 messages and GregC
still does have a solid function to call.

If he still doesn't have one, despite all the advice he was given, then
he probably doesn't deserve one. But, how would you know? Did he
complain to you?
Thanks for wasting all of our time...since 1970.

You're welcome.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,176
Messages
2,570,947
Members
47,501
Latest member
Ledmyplace

Latest Threads

Top