tsingle@sunland.gsfc.nasa.gov (Tim Singletary) (01/19/91)
Help! I need something to convert yy-ddd-hh:mm:ss (i.e. year, day_of_year, hour, minute, second) to a unix-style _number_of_seconds_since_00:00:00_GMT,_Jan._1,_1970_. I tried to use Sun's timelocal() function but couldn't get it to work (it lets you pass both _day_of_year_ and _month,_day_of_month_ with no way to specify which is correct!). Ideally what I'm looking for is source code to a timelocal() function, but any tips or suggestions will be appreciated. Thanks in advance, tim -- Tim Singletary, August Automation Inc., (301) 286-7942 -- NRA extremist, etc.
jap@convex.cl.msu.edu (Joe Porkka) (01/19/91)
tsingle@sunland.gsfc.nasa.gov (Tim Singletary) writes: >Help! I need something to convert yy-ddd-hh:mm:ss (i.e. year, >day_of_year, hour, minute, second) to a unix-style >_number_of_seconds_since_00:00:00_GMT,_Jan._1,_1970_. >I tried to use Sun's timelocal() function but couldn't get it to work (it Since your using a Sun you can use strptime(), at least in SunOS 4.1. I have no idea if this is a Sun defined function, or an ANSI function.
mike@bria.UUCP (Michael Stefanik) (01/20/91)
In article <TSINGLE.91Jan18120847@sunland.gsfc.nasa.gov> sunland.gsfc.nasa.gov!tsingle (Tim Singletary) writes: >Help! I need something to convert yy-ddd-hh:mm:ss (i.e. year, >day_of_year, hour, minute, second) to a unix-style >_number_of_seconds_since_00:00:00_GMT,_Jan._1,_1970_. I am doing this with the full knowledge that people are going to send me flaming mail about what an ugly solution this is, but ... here is a little ditty I wrote that seems to even work ... /* @(#)tmparse.c 1.1 parse a time specification */ #include <stdio.h> #include <string.h> #include <ctype.h> #include <time.h> #define ONE_DAY 86400L #define ONE_YEAR 31564800L #define ONE_THIRD 28800L int mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; main() { long now; char buf[64]; for (;;) { printf("Enter date: "); if ( gets(buf) == NULL ) break; tmparse(buf,&now); printf("%s",ctime(&now)); } } long tmparse(buf,when) char *buf; long *when; { long date, now; int year = 1970, month = 0, day = 0; int hours = 0, mins = 0, secs = 0, count; char *ptr, *next; struct tm *lt; time(&now); lt = localtime(&now); if ( strchr(buf,'/') == NULL && strchr(buf,'-') == NULL ) { month = lt->tm_mon; day = lt->tm_mday - 1; year = lt->tm_year + 1900; next = buf; } else { month = atoi(strtok(buf,"/-")) - 1; day = atoi(strtok(NULL,"/-")) - 1; year = atoi(strtok(NULL," ")); next = NULL; if ( year == 0 ) year = lt->tm_year + 1900; else if ( year < 100 ) year += 1900; } if ( year < 1970 ) { *when = 0L; return(0L); } if ( (ptr = strtok(next,":")) != NULL ) { while ( isspace(*ptr) ) ++ptr; hours = atoi(ptr); mins = atoi(strtok(NULL,":")); secs = atoi(strtok(NULL,"")); } date = 0L; for ( count = 1970; count < year; count++) { date += ONE_YEAR; if ( count % 4 == 0 || count % 400 == 0 ) date += ONE_DAY; } date -= (year - 1971) * ONE_THIRD; for ( count = 0; count < month; count++) { date += mdays[count] * ONE_DAY; if ( count == 1 && (year % 4 == 0 || year % 400 == 0) ) date += ONE_DAY; } date += (day * ONE_DAY) + secs + (mins * 60) + (hours * 3600); lt = localtime(&date); date += (hours - lt->tm_hour) * 3600; *when = date; return(date); } -- Michael Stefanik, Systems Engineer (JOAT), Briareus Corporation UUCP: ...!uunet!bria!mike -- technoignorami (tek'no-ig'no-ram`i) a group of individuals that are constantly found to be saying things like "Well, it works on my DOS machine ..."
guy@auspex.auspex.com (Guy Harris) (01/21/91)
In article <TSINGLE.91Jan18120847@sunland.gsfc.nasa.gov> tsingle@sunland.gsfc.nasa.gov (Tim Singletary) writes: > Help! I need something to convert yy-ddd-hh:mm:ss (i.e. year, > day_of_year, hour, minute, second) to a unix-style > _number_of_seconds_since_00:00:00_GMT,_Jan._1,_1970_. > > I tried to use Sun's timelocal() function but couldn't get it to work (it > lets you pass both _day_of_year_ and _month,_day_of_month_ with no way > to specify which is correct!). It lets you pass day-of-year, but it ignores it. It looks at month and day-of-month. (As one of the Timezone Caballeros, and as the person who put the "Arthur Olson" timezone stuff, including "timelocal()" - which was adapted from code by Robert Elz, from an idea by Bob Kridle - into SunOS 4.x, I know whereof I speak here.) > Ideally what I'm looking for is source code to a timelocal() function, > but any tips or suggestions will be appreciated. Try grabbing the source to the "Arthur Olson" timezone code - the SunOS code, as indicated, comes from that - from some archive site; it was posted to "comp.sources.unix" or somesuch at some point. In article <1991Jan18.200700.11045@msuinfo.cl.msu.edu> jap@convex.cl.msu.edu (Joe Porkka) writes: >Since your using a Sun you can use strptime(), at least >in SunOS 4.1. No, not entirely. "strptime()" converts a character string into a "struct tm"; "timelocal()" - and "mktime()", in ANSI C and/or POSIX-compliant systems such as SunOS 4.1 (POSIX, not ANSI C, in the case of 4.1) - convert a "struct tm" into a UNIX time. Think of "strptime()" as being the "inverse" of "strftime()", and "timelocal()"/"mktime()" as being the "inverse" of "localtime()". >I have no idea if this is a Sun defined function, or an ANSI >function. It's a Sun-defined function, and it doesn't really do what such a function should do (as the person who defined it, I have the right to say it's the wrong answer :-)). It shouldn't be responsible for figuring out which fields of a time/date specification may be elided, because that means it has to interpret the format specification in more detail than is appropriate. Instead, it should blindly match the string against the format, and some higher-level routine should try matching various format strings, e.g. one with the "seconds" field of a time and then one without. Unfortunately, AT&T's S5R4 "getdate()" routine, which operates similarly to the aforementioned higher-level routine, doesn't seem to be quite right, either; it's not affected, as far as I know, by the LANG or LC_TIME environment variables except to the extent that it might change the names it's willing to accept for months - I don't think you can set LANG and have it change the syntaxes it's willing to accept for dates, times, or date+time.
timr@gssc.UUCP (Tim Roberts) (02/12/91)
> int mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
I have seen this construct in date solutions several times over the past
two weeks. In my experience, it is almost always better to use an array of
the _accumulated_ days through the end of the month, rather than the actual
days in the month. This generally lets one eliminate at least one loop.
For example:
int mdays[12] = { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
--
timr@gssc.gss.com Tim N Roberts, CCP Graphic Software Systems
Beaverton, OR
This is a very long palindrome. .emordnilap gnol yrev a si sihT
ansok@stsci.EDU (Gary Ansok) (02/12/91)
In article <6586@gssc.UUCP> timr@gssc.UUCP (Tim Roberts) writes: >> int mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; > >I have seen this construct in date solutions several times over the past >two weeks. In my experience, it is almost always better to use an array of >the _accumulated_ days through the end of the month, rather than the actual >days in the month. This generally lets one eliminate at least one loop. > >For example: > >int mdays[12] = { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; This is likely to go off into a "speed vs. style" war, but I tend to agree with those who say that unless this is a very time-critical piece of code (hard to imagine for a date conversion routine, but I suppose it's possible), the benefits of the first in readability and maintainability far outweigh any speed gained by the second. Another suggestion -- depending on how the rest of your code represents months (and unless you're extremely tight on memory), use int mdays[13] = { 0, 31, 28, ... This makes mdays[1] correspond to January, the way most people expect. Of course, if January is 0 throughout your code, you may as well be consistenly confusing. Besides, it doesn't necessarily mean another loop to do it this way. See _The Elements of Programming Style_, pp. 52-54 (by Kernighan and Plauger). True, it did add another statement to the body of the loop. Gary Ansok ansok@stsci.edu
ts@cup.portal.com (Tim W Smith) (02/18/91)
If your standard libraries have a seconds to date string converter, then there is a simple way to convert the other way. 1. Get rough lower and upper bounds on the answer, such as YEAR * 365 * 24 * 3600 and (YEAR+1) * 366 * 24 * 3600. 2. Write a function that compares two dates in string form and determines which is first. 3. Do a binary search of the 3e6 possible values between the bounds determined in step #1, using the library routine that converts a time from seconds to a date string and the function your wrote in step #2. With this method, you don't have to know about leap years, or other funny things. For example, if the next release of the library for your system knows about certain leap seconds, all you have to do is relink, and they your code knows about them too. Tim Smith
hugh@fivegl.co.nz (Hugh Grierson) (02/18/91)
In article <2323@stsci.EDU> ansok@stsci.EDU (Gary Ansok) writes: >In article <6586@gssc.UUCP> timr@gssc.UUCP (Tim Roberts) writes: >>> int mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; >>int mdays[12] = { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; >This is likely to go off into a "speed vs. style" war, but I tend to >agree with those who say that unless this is a very time-critical >piece of code (hard to imagine for a date conversion routine, but I >suppose it's possible), the benefits of the first in readability and >maintainability far outweigh any speed gained by the second. Maintainability???? How often *do* you have to change the number of days in a month????? (Sept 1752 notwithstanding) Readability? A one-line comment... -- Hugh Grierson hugh@fivegl.co.nz | Perfection is attained not when there is 5GL International Ltd, | no more that can be added, but when there Auckland, New Zealand | is no more that can be taken away.
pwb@newt.phys.unsw.OZ.AU (Paul W. Brooks) (02/21/91)
In article <1991Feb18.133937.28469@fivegl.co.nz>, hugh@fivegl.co.nz (Hugh Grierson) writes: > In article <2323@stsci.EDU> ansok@stsci.EDU (Gary Ansok) writes: > >In article <6586@gssc.UUCP> timr@gssc.UUCP (Tim Roberts) writes: > >>> int mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; > > >>int mdays[12] = { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; : : : > >suppose it's possible), the benefits of the first in readability and > >maintainability far outweigh any speed gained by the second. > > Maintainability???? How often *do* you have to change the number > of days in a month????? (Sept 1752 notwithstanding) And how many times do you have to account for leap years? With the first form, if leap year add 1 to mdays[1]. With the second form add 1 to each of mdays[1] to mdays[11]. I know which I'd rather! Paul Brooks |Internet: pwb@newt.phys.unsw.edu.au Uni. of N.S.W. |If you have trouble sleeping, try lying on the end of Kensington NSW 2033| your bed. With a little luck you'll drop off. AUSTRALIA | - Mark Twain.
steve@taumet.com (Stephen Clamage) (02/23/91)
In article <1991Feb18.133937.28469@fivegl.co.nz>, hugh@fivegl.co.nz (Hugh Grierson) writes: | In article <2323@stsci.EDU> ansok@stsci.EDU (Gary Ansok) writes: | >In article <6586@gssc.UUCP> timr@gssc.UUCP (Tim Roberts) writes: | >>> int mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | | >>int mdays[12] = { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; | | >suppose it's possible), the benefits of the first in readability and | >maintainability far outweigh any speed gained by the second. | | Maintainability???? How often *do* you have to change the number | of days in a month????? (Sept 1752 notwithstanding) But what about when the program isn't working? As Kernighan and Plauger point out in "The Elements of Programming Style", it is easy to look at the first version and know it is right ("Thirty days hath September," etc). This allows you to move on to look for errors elsewhere. Quick Quiz: is the second version (31, 59, ...) quoted in this posting correct? Did I change any of the numbers accidently (or on purpose)? To find out, you have to do some arithmetic. -- Steve Clamage, TauMetric Corp, steve@taumet.com
dgil@pa.reuter.COM (Dave Gillett) (02/25/91)
In <1991Feb18.133937.28469@fivegl.co.nz> hugh@fivegl.co.nz (Hugh Grierson) writes: >Maintainability???? How often *do* you have to change the number >of days in a month????? (Sept 1752 notwithstanding) >Readability? A one-line comment... Sorry. If I'm trying to find a defect in the program's date-handling, I can verify by eye the {31, 28, ... } form. Even with a comment, it may take several moments to understand what the {31, 59, ... } form is trying to do -- especially if I didn't write this piece of code (which happens, you know). And it will take several minutes to verify that these magic numbers are in fact calculated correctly, a waste of both the author's and the maintainer's time and effort. If your algorithm, for efficiency's sake, really must use the numbers in this form, then the table should be built by the machine at run time, and the numbers in the source should be the familiar ones that anyone can easily verify. Dave
enag@ifi.uio.no (Erik Naggum) (02/26/91)
In article <790@saxony.pa.reuter.COM>, Dave Gillett writes: | In article <1991Feb18.133937.28469@fivegl.co.nz>, Hugh Grierson writes: | >Maintainability???? How often *do* you have to change the number | >of days in a month????? (Sept 1752 notwithstanding) | >Readability? A one-line comment... | Sorry. If I'm trying to find a defect in the program's date- | handling, I can verify by eye the {31, 28, ... } form. Even with a | comment, it may take several moments to understand what the {31, 59, | ... } form is trying to do -- especially if I didn't write this | piece of code (which happens, you know). Hey, that's what comments are for. | And it will take several minutes to verify that these magic numbers | are in fact calculated correctly, a waste of both the author's and | the maintainer's time and effort. If your algorithm, for | efficiency's sake, really must use the numbers in this form, then | the table should be built by the machine at run time, and the | numbers in the source should be the familiar ones that anyone can | easily verify. I can't believe this. At run-time, you do useful things, not table generation. You can easily do it pre-compile-time, once. You write a few shell commands to do that, or some simple-minded elisp code, and include the code as a comment: /* * cumulative days into year at beginning of month */ int cumulative_yday[] = { /* * This list was generated by piping these three lines into * /bin/sh. Repeat with "3!!sh<CR>" in vi. days=0 for i in 31 28 31 30 31 30 31 31 30 31 30 31 do echo -n $days,; days=`expr $days + $i`; done */ 0,31,59,90,120,151,181,212,243,273,304,334, }; Ok, so this is UNIX-centric par excellence. /* * cumulative days into year at beginning of month */ int cumulative_yday[] = { /* * This list was generated by eval'ing this code (C-X C-E): (let ((mday '(31 28 31 30 31 30 31 31 30 31 30 31)) (ydays 0)) (while mday (insert (int-to-string ydays) ",") (setq ydays (+ ydays (car mday)) mday (cdr mday)))) */ 0,31,59,90,120,151,181,212,243,273,304,334, }; Ok, this is GNU Emacs-centric. So sue me. If you don't have quality editors, you should get one before you do anything else. This code was the direct result of a desire to amend a perceived lack of tool-building initiative. I also have flint stones to make fire, if you're interested. The little tool built above is not necessarily the best possible tool, but it should give an indication of the desire to minimize the work you would do. (I spent 45 seconds writing the shell lines, and a few minutes fumbling with the simple elisp code.) Morale: Let the machines do the chores. -- [Erik Naggum] <enag@ifi.uio.no> Naggum Software, Oslo, Norway <erik@naggum.uu.no>
wirzenius@cc.helsinki.fi (Lars Wirzenius) (02/27/91)
In article <ENAG.91Feb26020137@holmenkollen.ifi.uio.no>, enag@ifi.uio.no (Erik Naggum) writes: [ A Unix shell script and a GNU Emacs lisp-routine that generate a table with cumulative counts from the beginning of the year deleted ] Ok, suppose you want to have the cumulative counts, but don't run either Unix nor GNU Emacs? You use the compiler: int cumulative_yday[] = { 0, /* days before Jan 1st */ 0+31, /* Feb 1st */ 0+31+28, /* March 1st */ 0+31+28+31, /* April 1st */ ... }; Or is there anything I miss? -- Lars Wirzenius wirzenius@cc.helsinki.fi
ts@cup.portal.com (Tim W Smith) (02/28/91)
< I can't believe this. At run-time, you do useful things, not table
< generation. You can easily do it pre-compile-time, once. You write a
< few shell commands to do that, or some simple-minded elisp code, and
< include the code as a comment:
[He then gives examples of including in comments in the source code
suggested shell or elisp commands that the user can use to generate
the table]
Well, I can't believe this, either! What about simply doing this:
#define JAN 0
#define FEB JAN+31
#define MAR FEB+28
#define APR MAR+31
#define MAY APR+30
#define JUN MAY+31
#define JUL JUN+30
#define AUG JUL+31
#define SEP AUG+31
#define OCT SEP+30
#define NOV OCT+31
#define DEC NOV+30
int days[] =
{
JAN, FEB, MAR, APR,
MAY, JUN, JUL, AUG,
SEP, OCT, NOV, DEC
};
When someone wishes to port this program to a different machine, they
don't have to have the shell or emacs or other tools to generate the
table.
< Morale: Let the machines do the chores.
But going out of our way to create these chores for the machines to do
seems to me to be counterproductive!
Tim Smith