[an error occurred while processing this directive]

HP OpenVMS Systems

ask the wizard
Content starts here

Calendar (Date) Conversions? (Julian)

» close window

The Question is:

 
How do you convert Gregorian time to Julian time using DCL.
 


The Answer is :

 
  There are no less than three different date-related constructs
  confusingly all refered to as "Julian":
 
    o The Julian Day that is the number of days since Julian
      Day One began at 12:00 noon, January 1, 4713 BC, this
      was a construct of Joseph Scaliger and dates to the
      sixteenth century.  (This scheme was named for Julius
      Caesar Scaliger, Joseph Scaliger's father.)
 
    o The Julian Day that is the year and the number of days
      that have passed in the specified year.
 
    o The Julian Calendar, named for the Roman Emporer Julius
      Caesar (not Scaliger).  The Julian calendar eliminated
      the need for the month of Mercedonius, but was roughly
      11.5 minutes off sideral time.  The Julian calendar
      precedes the Gregorian Calendar.  (The Gregorian calendar
      is better by roughly 11.5 minutes per year, and also now
      the calendar that is in common use in many countries.)
 
  For details of time and time-keeping and some background on
  Scaliger's Julian , please see the OpenVMS FAQ.
 
  For a C tool that uses the number of days since the OpenVMS
  System base date 17-Nov-1858 -- this tool uses the first
  definition of Julian Day listed above -- and it works within
  a DCL command procedure, please see:
 
    http://www.openvms.compaq.com/freeware/srh_examples/dsbd.c
    http://www.openvms.compaq.com/freeware/srh_examples/dsbd.com
 
  The third meaning of Julian -- the calendar -- requires details
  on where the date was recorded, as various countries switched
  from the Julian Calendar to the Gregorian Calendar at different
  dates.  Spain and Spanish colonies (including the US state of
  Florida) followed 4-Oct-1582 with 15-Oct-1582.   Catholic German
  states adopted the calendar in 1583, while Protestant German states
  switched in 1699.  England and colonies (Canada, non-French, non-
  Spanish US) followed 2-Sep-1752 with 14-Sep-1752, Sweden in 1753,
  Alaska switched when the territory was purchased in 1867 (dropped
  10 days), Japan in 1873, China in 1912 (13 days), the Soviet Union
  in 1918 (13 days), Greece in 1923 (also 13 days).  Switzerland used
  both calendars in parallel between 1583 and 1812, before fully
  adopting the Gregorian Calendar.  The Russian Orthodox church and
  a few other organizations reportedly still use the Julian Calendar.
  Each conversion required removing a different number of days.
 
 
  A somewhat more complex (and DCL-only) solution -- for the second
  meaning of Julian above -- follows:
 
	--
 
1) JULIAN.COM - which converts the Gregorian date, in the format of
   DD-MMM-YYYY (1-JAN-1992) into a Julian date, in the format of
   YYYYddd (1992001).   The Julian date here is a 4 character year
   followed by a three character day of the year.
 
2) GREGORIAN.COM - which converts the Julian date into a Gregorian
   date, the reverse of JULIAN.COM.
 
3) DAY_OF_WEEK.COM - which takes a Gregorian date and tells which
   day of the week it fell on (Monday, Tuesday, etc).  This routine
   also provides a unique "factor" number which can be used in
   calculating the days between two dates.
 
4) DAYS_BETWEEN_DATES.COM - uses DAY_OF_WEEK.COM to calculate the
   number of days that occur between two Gregorian dates.  Thus
   to use this routine you must also have DAY_OF_WEEK.COM available
   as well.
 
These command procedures are intended to be starting points on how these
type of operations might be done.  Extensive error checking and validation
are not performed by these example procedures.  Dates in different formats
would have to have the algorithms modified slightly for proper execution,
as the command procedures currently only support the DD-MMM-YYYY Gregorian
date and the YYYYddd Julian Date.
 
 
------------------------------ JULIAN.COM -----------------------------------
 
$! JULIAN.COM
$! ----------
$! This example DCL Command Procedure takes a date in the format
$! of DD-MMM-YYYY (1-JAN-1991) and converts it into a "Julian" type
$! date of the style YYYYddd (1991001), where "ddd" is the number
$! of days since the beginning of the year.  If no input is provided
$! then the "Julian" date for TODAY is displayed.  It is unsupported
$! and provided as is, and is meant to serve as a general guide to
$! how the date could be transformed with DCL.
$!
$! To invoke this DCL Command Procedure you can enter the command
$!    $ @JULIAN 13-DEC-1991
$!    The Julian Date for 13-DEC-1991 is 1991347 .
$!
$! INPUTS:
$!	P1 - the input date.  If none is specified then the current
$!	     date is used.
$!	P2 - if it contains the string "SUPPRESS" the normal output
$!   	     of this command procedure will be suppressed.  Any errors
$!	     will be returned though.
$!
$! OUTPUTS:
$!	Text may be written to the screen, and two global symbols
$!	will be set up and used:
$!
$!   	JULIAN_DATE <> "" contains the Julian date as a text string
$!	JULIAN_DATE == "" indicates an error was encountered
$!	LEAP_YEAR == 0 indicates the input year was not a leap year
$!	LEAP_YEAR == 1 indicates the input year was a leap year
$!
$ if p1 .eqs. "" then p1 = f$element(0," ",f$time())
$ say := write sys$output
$ mon_text = "JAN/FEB/MAR/APR/MAY/JUN/JUL/AUG/SEP/OCT/NOV/DEC/"
$ mon_days = "31/28/31/30/31/30/31/31/30/31/30/31/"
$ leap_days= "31/29/31/30/31/30/31/31/30/31/30/31/"
$ day_temp = f$integer(f$element(0,"-",p1))
$ mon_temp = f$element(1,"-",p1)
$ if f$locate(mon_temp,mon_text) .eq. f$length(mon_text) then goto CONT4
$ year_temp = f$extract(0,4,f$element(2,"-",p1))
$!
$! Now we must consider leap year.  If the year is divisible by
$! 4 then it may be a leap year, unless it is a century year
$! in which case it must be divisible by 400 (the year 2000 is
$! a leap year, but the year 1900 was not).
$!
$ year = f$integer(year_temp)
$!
$! Now that we have the year as an integer we do another check.
$! The Gregorian calendar as we now it today was implemented by
$! Pope Gregory XIII who decreeded that Thursday, Oct 4, 1582
$! was the last day of the Julian calendar and the next day would
$! be Friday Oct 15, 1582.  The missing days were to correct the
$! centuries of uncorrected leap years that had slowly added up
$! and set the calendar off.  Under the current calendar implemetation
$! it would take about 3323 years finally be off a single day again.
$! But this also means that years before 1583 may not be accurately
$! represented by this algorithm.  Different countries also decided
$! to implement the Gregorian calendar at different times in history.
$! The Germans and Dutch did not change to the new calendar until
$! 1698.  The English shift took place in 1752, and in Russia it
$! was not adopted until 1918.
$!
$ leap_year == 0
$ if day_temp .le. 0 then goto ERROROUT
$ if day_temp .gt. 31 then goto ERROROUT
$ if year .lt. 1583 then goto ERROROUT	! Take care of calendar conversion time
$ if year .gt. 4905 then goto ERROROUT	! 1582+3323 = year 4905
$ if (year/4)*4 .ne. year then goto CONT2	! Leap years divisble by 4
$ if (year/100)*100 .ne. year then goto CONT1   ! Centuries divisible by 100
$ if (year/400)*400 .ne. year then goto CONT2	! Century leap year by 400
$CONT1:
$ leap_year == 1
$ mon_days = leap_days
$CONT2:
$ num = 0
$ julian_days = 0
$COUNT_DAYS:
$ if mon_temp .eqs. f$element(num,"/",mon_text) then goto CONT3
$ julian_days = julian_days + f$element(num,"/",mon_days)
$ num = num + 1
$ if num .gt. 11 then goto CONT4
$ goto COUNT_DAYS
$CONT3:
$ if day_temp .gt. f$integer(f$element(num,"/",mon_days)) then goto ERROROUT
$ julian_days = julian_days + day_temp
$!
$! The "Julian" date provided has the "ddd", day of year, formated
$! with leading zeros.  If this is not desired change the following
$! "!3ZL" to some other format, such as "!UL" which is currently
$! commented out.
$! text = f$fao("!UL ",julian_days)
$ text = f$fao("!3ZL ",julian_days)
$ julian_date == year_temp + text	! Make a Global Symbol
$ if p2 .eqs. "SUPPRESS" then exit
$ say "The Julian Date for ",p1," is ",julian_date,"."
$ exit
$ERROROUT:
$ say "The Date provided ",p1," is invalid or out of range."
$ julian_date == ""			! Make error condition
$ exit
 
------------------------------ GREGORIAN.COM --------------------------------
 
$! GREGORIAN.COM
$! -------------
$! This example DCL command procedure takes a "Julian" date of
$! the form "YYYYddd" (1991001) and converts it into a Gregorian
$! style date (1-JAN-1991).  Is is unsupported and meant to be
$! an example.  A more detailed explanation of some of the algorithm
$! appears in a "sister" DCL command procedure named JULIAN.COM,
$! that translates the Gregorian Date into a Julian Date.
$!
$! This command procedure can be invoked with:
$!	$ @GREGORIAN 1991001
$!      The Julian Date 1991001 is 1-JAN-1991
$!
$! INPUTS:
$!	P1 - the input Julian date, if none is specified you will be
$!	     prompted for one.
$!	P2 - if it contains the string "SUPPRESS" then the normal
$! 	     output of this command procedure will be suppressed.
$!	     Any errors will be returned though.
$!
$! OUTPUTS:
$!	Text may be written out to the screen, and two global
$!	symbols will be set up and used:
$!
$!	GREGORIAN_DATE <> "" contains the Gregorian date
$!	GREGORIAN_DATE == "" indicates an error was encountered
$!	LEAP_YEAR == 0  indicates the input year was not a leap year
$!	LEAP_YEAR == 1  indicates the input year was a leap year
$!
$ if p1 .eqs. "" then inquire p1 "Enter the Julian Date "
$ say := write sys$output
$ mon_text = "JAN/FEB/MAR/APR/MAY/JUN/JUL/AUG/SEP/OCT/NOV/DEC/"
$ mon_days = "31/28/31/30/31/30/31/31/30/31/30/31/"
$ leap_days= "31/29/31/30/31/30/31/31/30/31/30/31/"
$ year_text = f$extract(0,4,p1)
$ year      = f$integer(year_text)
$ days      = f$integer(f$extract(4,3,p1))
$ if year .lt. 1583 then goto ERROROUT			! validate ranges
$ if year .gt. 4905 then goto ERROROUT
$ if days .le. 0    then goto ERROROUT
$ if days .gt. 366  then goto ERROROUT
$ julian_days = days
$ days = 0
$ mon  = 0
$ leap_year == 0
$ if (year/4)*4 .ne. year then goto COUNT_J_DAYS	! take care leap years
$ if (year/100)*100 .ne. year then goto CONT1
$ if (year/400)*400 .ne. year then goto COUNT_J_DAYS
$CONT1:
$ leap_year == 1
$ mon_days = leap_days
$COUNT_J_DAYS:
$ days = days + f$element(mon,"/",mon_days)
$ if days .ge. julian_days then goto EXIT_COUNT_J
$ mon  = mon + 1
$ if mon .gt. 11 then goto ERROROUT
$ goto COUNT_J_DAYS
$EXIT_COUNT_J:
$ days = days - f$element(mon,"/",mon_days)
$ day  = julian_days - days
$ month_text = f$element(mon,"/",mon_text)
$ Gregorian_date == "''day'" + "-" + month_text + "-" + year_text
$ if p2 .eqs. "SUPPRESS" then exit
$ say "The Julian date ",p1," is Gregorian ",Gregorian_date
$ exit
$ERROROUT:
$ say "The input Julian date of ",p1," is invalid or out of range"
$ Gre gorian_date == ""
$ exit
 
------------------------------ DAY_OF_WEEK.COM ------------------------------
 
$! DAY_OF_WEEK.COM
$! ---------------
$! This command procedure takes an alternative method to calculate
$! the day of the week.  The easy method with VMS DCL would be to
$! simply use the lexical function
$!
$!	DAY_OF_WEEK = F$CVTIME(input_time,,"WEEKDAY")
$!
$! This routine is being used to test the FACTOR produced by the
$! following DCL command procedure before using it to calculate
$! the number of days between dates in DCL command procedure
$! DAYS_BETWEEN_DATES.COM.  It also gives a simple algorithm that
$! could be implemented in other programming languages.  It is
$! unsupported and provided as is.  Additional date validation
$! could be performed (but is not at this time).  If you do want
$! to valiate the date further look at the more extensive error
$! checking in JULIAN.COM.
$!
$! You can use this DCL command procedure as follows:
$!	$ @DAY_OF_WEEK 13-DEC-1991
$!      13-DEC-1991 is a Friday.
$!
$! INPUTS:
$!	P1 - if no date is specified then TODAYs date is used
$!	P2 - if it contains the string "SUPPRESS" then the normal
$!	     output of this command procedure will be suppressed.
$!	     Any errors will be printed though.
$!
$! OUTPUTS:
$!	Text may be written out to the screen, and two global symbols
$!	will be set up and used:
$!
$!	DAY_OF_WEEK <> "" then it will contain the text string indicating
$!	      	the day of the week (Saturday, Sunday, Monday, etc).
$!	DAY_OF_WEEK == "" indicates an error condition
$!	FACTOR <> 0 gives a unique number of days factor for this date
$!	FACTOR = 0  indicates an error condition
$!
$ if p1 .eqs. "" then p1 = f$element(0," ",f$time())
$ say := write sys$output
$ week_day = "Saturday/Sunday/Monday/Tuesday/Wednesday/Thursday/Friday/"
$ mon_text = "JAN/FEB/MAR/APR/MAY/JUN/JUL/AUG/SEP/OCT/NOV/DEC/"
$ day_temp = f$integer(f$element(0,"-",p1))
$ mon_temp = f$element(1,"-",p1)
$ year_temp = f$integer(f$extract(0,4,f$element(2,"-",p1)))
$ month_temp = 0
$ if year_temp .le. 1583 then goto ERROROUT
$ if year_temp .gt. 4905 then goto ERROROUT
$ if day_temp  .le.    0 then goto ERROROUT
$ if day_temp  .gt.   31 then goto ERROROUT
$ if f$locate(mon_temp,mon_text) .eq. f$length(mon_text) then goto ERROROUT
$COUNT_MONTHS:
$ if mon_temp .eqs. f$element(month_temp,"/",mon_text) then goto CONT1
$ month_temp = month_temp + 1
$ goto COUNT_MONTHS
$CONT1:
$ month_temp = month_temp + 1
$!
$! For January and February the equation is:
$! 	FACTOR = 365(YYYY) + DD + 31(MM-1) + INT((YYYY-1)/4) -
$!	         INT( 3/4 * (INT(((YYYY-1)/100)+1))
$!
$ if month_temp .ge. 3 then goto FIGURE2
$ FACTOR == 365 * year_temp + day_temp + 31 * (month_temp - 1) -
            + (year_temp -1)/4 - (((((year_temp-1)/100)+1)*3)/4)
$ GOTO CONT2
$!
$! For March through December the equation is:
$!	FACTOR = 365(YYYY) + DD + 31(MM-1) - INT(.4MM + 2.3) +
$!   	         INT(YYYY/4) - INT( 3/4 * (INT(YYYY/100) + 1))
$!
$FIGURE2:
$ FACTOR == 365 * year_temp + day_temp + 31 * (month_temp - 1) -
            - (4 * month_temp + 23)/10 -
            + year_temp/4 - ((((year_temp/100)+1)*3)/4)
$!
$! The day of the week can be found from the FACTOR for the date
$! 	Day_of_week = FACTOR + (INT (-FACTOR/7) * 7)
$! Where 0 is Saturday and 6 is Friday.
$!
$CONT2:
$ INDEX = FACTOR + (-FACTOR/7)*7
$ DAY_OF_WEEK == F$ELEMENT(INDEX,"/",week_day)
$ if p2 .eqs. "SUPPRESS" then exit
$ say p1," is a ",DAY_OF_WEEK
$ exit
$! The solar year is 365.242216 days; 365 days,  5 hours, 48 min, 46 seconds
$! The lunation is    29.530585 days;  29 days, 12 hours, 44 min, 2.8 seconds
$! Twelve Lunations  364.3671   days; 364 days,  8 hours, 48 min, 34 seconds
$ERROROUT:
$ say "The date ",p1," is invalid or out of range."
$ DAY_OF_WEEK == ""
$ FACTOR == 0
$ EXIT
$! Known dates to compare against:
$! 25-DEC-2000 is on a Monday
$! 25-DEC-1900 was on a Tuesday
$! 25-DEC-2063 is on a Tuesday (same calendar as 1900)
$! 25-DEC-1991 is on a Wednesday
$! 25-DEC-1800 was on a Thursday
$! 25-DEC-1998 is on a Friday
$! 25-DEC-2060 is on a Saturday
$! 25-DEC-1994 is on a Sunday
 
------------------------------ DAYS_BETWEEN_DATES.COM  ----------------------
 
$! DAYS_BETWEEN_DATES.COM
$! ----------------------
$! To calculate the day between two dates we calculate a FACTOR
$! for each date.  The difference of the FACTORs is the number
$! of days.  The Factor is given in another DCL command procedure
$! DAY_OF_WEEK.COM.
$!
$! INPUTS:
$!	P1 - input date, if not specified you will be prompted for it.
$! 	P2 - second input date, if not specified you will be prompted
$!	     for it.
$!	P3 - if it contains the string "SUPPRESS" then the normal
$!	     output of this command procedure will be suppressed.
$!	     Any errors will be printed.
$! OUTPUTS:
$!	Text may be written out to the screen, and a global symbol
$!	will be set up:
$!	DAYS_BETWEEN_DATES == -1 indicates and error condition
$!	DAYS_BETWEEN_DATES <> -1 contains the number of days between
$!		the input dates.
$!
$! Some dates to check on:
$! Between June 1, 1960 and October 31, 1976 are 5996 days
$! Between Oct 1, 1976 and Oct 31, 1976 are 30 days
$!
$ say := write sys$output
$ if p1 .eqs. "" then inquire p1 "Enter First Date  "
$ if p2 .eqs. "" then inquire p2 "Enter Second Date "
$ days_between_dates == -1
$ day1 = "''p1'"
$ @DAY_OF_WEEK 'p1 SUPPRESS
$ factor1 = factor
$ day2 = "''p2'"
$ @DAY_OF_WEEK 'p2 SUPPRESS
$ factor2 = factor
$ if factor1 .eq. 0 then exit
$ if factor2 .eq. 0 then exit
$ if factor1 .gt. factor2
$    then
$      days_between_dates == factor1 - factor2
$    else
$      days_between_dates == factor2 - factor1
$    endif
$ if p3 .eqs. "SUPPRESS" then exit
$ say "The days between ",day1," and ", day2," are ", days_between_dates," days"
$ exit
 

answer written or last revised on ( 7-MAR-2001 )

» close window