[comp.lang.c] Julian date routines needed

grantk@manta.NOSC.MIL (Kelly J. Grant) (02/16/91)

Howdy networld

About 100,000 years ago I had some Julian date routines (in dBASE) to
convert YY/MM/DD into a format suitable for math, and also to convert
back to normal dates.  We called these JULTOCAL and CALTOJUL.  I now
have a need for these algorithms for a UNIX program.  Would any of 
you kind souls have these routines lying around in your book of tricks
[right next to your hanoi.c file maybe :-)]

I did grab the recent posted code to translate YY/MM/DD HH:MM:SS into
UNIX time format.  This code could be used, but I think a Julian routine
would be more elegant for my application.  Flame if you must, but that 
is my opinion.

Muchos gracias in advance

Kelly
-- 
Kelly Grant        grantk@manta.nosc.mil   (619) 225-2508
Computer Sciences Corp          ^^^^^^^^ Important: manta.UUCP won't get to me
4045 Hancock Street      "If you are given lemons.....see if you can trade for
San Diego, CA 92110       chocolate" - me

ex1neil@cybaswan.UUCP (Neil Woods) (02/19/91)

In article <1753@manta.NOSC.MIL> grantk@manta.NOSC.MIL (Kelly J. Grant) writes:
>Howdy networld
>
>About 100,000 years ago I had some Julian date routines (in dBASE) to
>convert YY/MM/DD into a format suitable for math, and also to convert
>back to normal dates.  We called these JULTOCAL and CALTOJUL.  I now
>have a need for these algorithms for a UNIX program.  Would any of 
>you kind souls have these routines lying around in your book of tricks
>[right next to your hanoi.c file maybe :-)]

The following should do the trick:

------------(Cut Here)------------

#include <stdio.h>

/* returns Julian day number --given a string of the form xx/yy/zz.
** To calculate the day of the week use the return value % 7.
*/

long 
julian_day (date_str)
  char *date_str;
{
  long jdn;
  int month, day, year;

  sscanf (date_str, "%d/%d/%d", &month, &day, &year);

  if (year < 100)
    year += 1900;          /* assume 20th century */
  if (year < 1000)
    year += 2000;          /* assume 21st */
  jdn = (long) year * 367 + month * 275 / 9
  - (year + (month > 2)) * 7 / 4
  - ((year - (month < 3)) / 100 + 1) * 3 / 4 + day + 1721029L;

  return (jdn);
}

/* converts from a given Julian day number to a formatted string of the form
** xx/yy/zz and places it in date_string. Returns the century (e.g. 19).
*/

int 
julian_date (jdn, date_string)
  long jdn;
  char *date_string;
{
  long year, month, day, temp_var;
  int century;

  temp_var = jdn - 1721119L;
  year = (4 * temp_var - 1) / 146097L;
  temp_var = 4 * temp_var - 1 - 146097L * year;
  day = temp_var / 4;
  temp_var = (4 * day + 3) / 1461;
  day = 4 * day + 3 - 1461 * temp_var;
  day = (day + 4) / 4;
  month = (5 * day - 3) / 153;
  day = 5 * day - 3 - 153 * month;
  day = (day + 5) / 5;
  year = 100 * year + temp_var;
  if (month < 10)
    month += 3;
  else
    {
      month -= 9;
      year++;
    }

  century = (int)year / 100;
  year = year - (century * 100);

  sprintf (date_string, "%02ld/%02ld/%02ld", month, day, year);

  return ((int) century);
}

/* Return the difference between two dates in days as a signed long */

long 
diff_date (date1, date2)
  char *date1, *date2;
{
  return (julian_day (date2) - julian_day (date1));
}

int
main (argc, argv)
  int argc;
  char *argv[];
{
  if (argc != 3)
    {
      fprintf (stderr, "Usage: diffdate first_date second_date\n");
      fprintf (stderr, "Where each date is of the form mm/dd/yy\n");
      return 1;
    }
   printf ("Difference in days = %ld\n", diff_date (argv[1], argv[2]));
   return 0;
}


>Muchos gracias in advance
>
>Kelly

Your Welcome.

	Neil.

-- 
Neil Woods.                 | JANET: ex1neil@uk.ac.swan.pyr
University College Swansea, | UUCP : ...!mcvax!ukc!swan.pyr!ex1neil
Wales, UK.                  | ARPA : ex1neil%pyr.swan.ac.uk@nfsnet-relay.ac.uk

ebergman@isis.cs.du.edu (Eric Bergman-Terrell) (02/19/91)

See the Dec. 90 issue of Computer Language magazine.

Terrell

grantk@manta.NOSC.MIL (Kelly J. Grant) (02/20/91)

In article <1753@manta.NOSC.MIL>, grantk@manta.NOSC.MIL (Kelly J. Grant) writes:
> Howdy networld
> 
> About 100,000 years ago I had some Julian date routines (in dBASE) to
> convert YY/MM/DD into a format suitable for math, and also to convert
> back to normal dates.  We called these JULTOCAL and CALTOJUL.  I now
> have a need for these algorithms for a UNIX program.  Would any of 
> you kind souls have these routines lying around in your book of tricks
> [right next to your hanoi.c file maybe :-)]

The network is truly a wonderful place.  I received many routines, and 
pointers to the article in December 90 Computer Languages magazine.  
I don't have an easy way to get the article, but several sources mentioned
it. 

Please don't send any furthur information, I already have all I can handle.
It certainly is a wonderful feeling knowing I can count on the network to
help solve my problems.

Thanks again

Kelly
-- 
Kelly Grant        grantk@manta.nosc.mil   (619) 225-2508
Computer Sciences Corp          ^^^^^^^^ Important: manta.UUCP won't get to me
4045 Hancock Street      "If you are given lemons.....see if you can trade for
San Diego, CA 92110       chocolate" - me

garry@ceco.ceco.com (Garry Garrett) (02/21/91)

In article <1780@manta.NOSC.MIL>, grantk@manta.NOSC.MIL (Kelly J. Grant) writes:
> In article <1753@manta.NOSC.MIL>, grantk@manta.NOSC.MIL (Kelly J. Grant) writes:
> > Howdy networld
> > 
> > About 100,000 years ago I had some Julian date routines (in dBASE) to
> > convert YY/MM/DD into a format suitable for math, and also to convert
> > back to normal dates.  We called these JULTOCAL and CALTOJUL.  I now
> > have a need for these algorithms for a UNIX program.  Would any of 
> > you kind souls have these routines lying around in your book of tricks
> > [right next to your hanoi.c file maybe :-)]
> 
> Kelly Grant        grantk@manta.nosc.mil   (619) 225-2508


	There is an easy way to do this.  Let UNIX do all the work FOR you.

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

main()
{
	struct tm *tmptr;
	size_t	  sec70;

	tmptr = (struct tm *) malloc(sizeof(struct tm));
	/* ... */
	sscanf(datestr,"%d/%d/%d",&tmptr->tm_year,&tmptr->tm_mon,&tmptr->tm->mday);
	/* my UNIX system doesn't seem to mind that the rest of the */
	/* fields of tmptr are not filled out.  I think that malloc */
	/* on my system fills the memory with 0's.  Not true on all */
	/* systems though.					    */
	sec70 = mktime(tmptr);
	tmptr = localtime(sec70);
	/* tmptr->tm_yday now contains the julian day */
}

Generally speaking, on a unix system, if you can convert the time that you
are given, in whatever format you are given to either structure tm (defined
in time.h) or into the number of seconds elapsed since jan 1, 1970 at 00:00:00,
then you can do anything you want to with it.  Unix is very good about that,
but other C compilers do not always have all functions that are available  
on Unix.  Prime is one of those systems.  That's why I would like to find 
the code to mktime() and strftime() (as described in K&R, 2nd edition, p255)
so that I can manipulate various reprentations of time.  

Garry Garrett
garry@ceco.ceco.com
...!uunet!ceco.ceco.com!garry

jlg@lanl.gov (Jim Giles) (02/22/91)

From article <408@ceco.ceco.com>, by garry@ceco.ceco.com (Garry Garrett):
> [...]
> 	There is an easy way to do this.  Let UNIX do all the work FOR you.
> [...]
> Generally speaking, on a unix system, if you can convert the time that you
> are given, in whatever format you are given to either structure tm (defined
> in time.h) or into the number of seconds elapsed since jan 1, 1970 at 00:00:00,
> then you can do anything you want to with it.  [...]

You should be advised however that UNIX leaves dates before 1 Jan.
1970 completely undefined.  Further, on a 32 bit machine, the value
becomes undefined for dates after (about) 3 Jan. 2038 (the seconds
since epoch becomes negative then).  So, if your need for the Julian
Day Number is for something other than current events, the use of
built-in UNIX system features won't work.  The first chapter of the
'Numerical Recipes' book contains algorithms that work for all dates
since 4017 (I think) B.C..  It can easily be extended to be accurate
for all dates (I have a version which only overflows at year 40,000
(AD or BC)).

J. Giles