Caché ObjectScript Reference
$HOROLOG
[Back] [Next]
   
Server:docs1
Instance:LATEST
User:UnknownUser
 
-
Go to:
Search:    

Contains the local date and time for the current process.
Synopsis
$HOROLOG
$H
Description
$HOROLOG contains the date and time for the current process. It can contain the following values:
$HOROLOG contains a character string that consists of two integer values, separated by a comma. These two integers represent the current local date and time in Caché storage format. These integers are counters, not user-readable dates and times. $HOROLOG returns the current date and time in the following format:
ddddd,sssss
The first integer, ddddd, is the current date expressed as a count of the number of days since December 31, 1840, where day 1 is January 1, 1841. Because Caché represents dates using a counter from an arbitrary starting point, Caché is unaffected by the Year 2000 boundary. The maximum value for this date integer is 2980013, which corresponds to December 31, 9999.
The second integer, sssss, is the current time, expressed as a count of the number of seconds since midnight of the current day. The system increments the time field from 0 to 86399 seconds. When it reaches 86399 at midnight, the system resets the time field to 0 and increments the date field by 1. $HOROLOG truncates fractional seconds; it represents time in whole seconds only.
You can obtain the same current date and time information by invoking the Horolog() method, as follows:
   WRITE $SYSTEM.SYS.Horolog()
 
Refer to %SYSTEM.SYS in the InterSystems Class Reference for further details.
Separating Date and Time
To get just the date portion or just the time portion of $HOROLOG, you can use the $PIECE function, specifying the comma as the delimiter character:
   SET dateint=$PIECE($HOROLOG,",",1)
   SET timeint=$PIECE($HOROLOG,",",2)
   WRITE !,"Date and time: ",$HOROLOG
   WRITE !,"Date only: ",dateint
   WRITE !,"Time only: ",timeint
 
To get just the date portion of a $HOROLOG value, you can also use the following programming trick:
   SET dateint=+$HOROLOG
   WRITE !,"Date and time: ",$HOROLOG
   WRITE !,"Date only: ",dateint
 
The plus sign (+) causes Caché to parse the $HOROLOG string as a number. When Caché encounters a nonnumeric character (the comma), it truncates the rest of the string and returns the numeric portion. This is the date integer portion of the string.
Date and Time Functions Compared
The various ways to return the current date and time are compared, as follows:
Date and Time Conversions
You can use the $ZDATE function to convert the date portion of $HOROLOG into external, user-readable form. You can use the $ZTIME function to convert the time portion of $HOROLOG into external user-readable form. You can use the $ZDATETIME function to convert both the date and time. When using $HOROLOG, setting the precision for time values in these functions always returns zeros as fractional seconds.
You can use the $ZDATEH function to convert a user-readable date into the date portion of $HOROLOG. You can use the $ZTIMEH function to convert a user-readable time into the time portion of $HOROLOG. You can use the $ZDATETIMEH function to convert both the date and time to a $HOROLOG value.
Setting the Date and Time
$HOROLOG can be set to a user-specified date for the current process using the FixedDate() method of the %SYSTEM.Process class. $HOROLOG cannot be modified using the SET command. Attempting to do so results in a <SYNTAX> error.
   DO ##class(%SYSTEM.Process).FixedDate(12345)  // set $HOROLOG date
   WRITE !,$ZDATETIME($HOROLOG,1,1,9)," $HOROLOG changed date"
   WRITE !,$ZDATETIME($NOW(),1,1,9)," $NOW() no date change"
   WRITE !,$ZDATETIME($ZDATETIMEH($ZTIMESTAMP,-3),1,1,9)," $ZTS UTC-to-local",
           " no date change"
   DO ##class(%SYSTEM.Process).FixedDate(0)    // restore $HOROLOG
   WRITE !,$ZDATETIME($HOROLOG,1,1,9)," $HOROLOG current date"
 
Note that FixedDate() changes the $HOROLOG value, but not the $NOW or $ZTIMESTAMP value.
Time Zone
By default, $HOROLOG contains the date and time for the local time zone. This time zone default is supplied by the operating system, which Caché uses to set the $ZTIMEZONE default.
Changing $ZTIMEZONE affects the value of $HOROLOG for the current process. It changes the time portion of $HOROLOG, and this change of time can also change the date portion of $HOROLOG. $ZTIMEZONE is a fixed offset of time zones from the Greenwich meridian; it does not adjust for local seasonal time variants, such as Daylight Saving Time.
Daylight Saving Time
$HOROLOG adjusts for seasonal time variants based on the algorithm supplied by the underlying operating system. After applying the $ZTIMEZONE value, Caché uses the operating system local time to adjust $HOROLOG (if needed) for seasonal time variants, such as Daylight Saving Time.
You can determine if Daylight Saving Time is in effect for the current date, or for a specified date and time using the IsDST() method. The following example returns the Daylight Saving Time (DST) status for the current date and time. Because this status could change while the program is running, this example checks it twice:
CheckDST
  SET x=$SYSTEM.Util.IsDST()
  SET local=$ZDATETIME($HOROLOG)
  SET x2=$SYSTEM.Util.IsDST()
  GOTO:x'=x2 CheckDST
  IF x=1 {WRITE local," DST in effect"}
  ELSEIF x=0 {WRITE local," DST not in effect"}
  ELSE {WRITE local," DST setting cannot be determined"}
 
The application of seasonal time variants may differ based on (at least) three considerations:
Local Time Variant Thresholds
$HOROLOG calculates the number of seconds from midnight by consulting the system clock. Therefore, if the system clock is automatically reset when crossing a local time variant threshold, such as the beginning or end of Daylight Saving Time, the time value of $HOROLOG also shifts abruptly ahead or back by the appropriate number of seconds. For this reason, comparisons of two $HOROLOG time values may yield unanticipated results if the period between the two values includes a local time variant threshold.
$NOW does not adjust for local time variants. Its use may be preferable when comparing date and time values if the period between the two values includes a local time variant threshold.
Dates Before 1840
$HOROLOG cannot be directly used to represent dates outside of the range of years 1840 through 9999. However, you can represent historic dates far beyond this range using the Caché SQL Julian date feature. Julian dates can represent a date as an unsigned integer, counting from 4711 BC (BCE). Julian dates do not have a time-of-day component.
You can convert a Caché $HOROLOG date to a Caché Julian date using the TO_CHAR SQL function, or the TOCHAR() method of the %SYSTEM.SQL class. You can convert a Caché Julian date to a Caché $HOROLOG date using the TO_DATE SQL function, or the TODATE() method of the %SYSTEM.SQL class.
The following example takes the current $HOROLOG date and converts it to a Julian date. The + before $HOROLOG forces Caché to treat it as a number, and thus truncate at the comma, eliminating the time integer:
  WRITE !,"Horolog date = ",+$H
  SET x=$SYSTEM.SQL.TOCHAR(+$HOROLOG,"J")
  WRITE !,"Julian date = ",x
 
The following example takes a Julian date and converts it to a Caché $HOROLOG date:
  SET x=$SYSTEM.SQL.TODATE(2455030,"J")
  WRITE !,"$HOROLOG date = ",x," = ", $ZDATE(x,1)
 
Note that Julian date values smaller than 1721100 cannot be converted; an <ILLEGAL VALUE> error is generated.
For further information on Julian dates, refer to TO_DATE and TO_CHAR in the Caché SQL Reference.
For information on the starting date of $HOROLOG, see the section Historical Note.”
Examples
The following example displays the current contents of $HOROLOG.
   WRITE $HOROLOG
 
This returns a value formatted like this: 62210,49170
The following example uses $ZDATE to convert the date field in $HOROLOG to a date format.
   WRITE $ZDATE($PIECE($HOROLOG,",",1))
 
returns a value formatted like this: 04/29/2011
The following example converts the time portion of $HOROLOG to a time in the form of hours:minutes:seconds on a 12-hour (a.m. or p.m.) clock.
CLOCKTIME    
  NEW
  SET Time=$PIECE($HOROLOG,",",2)
  SET Sec=Time#60
  SET Totmin=Time\60
  SET Min=Totmin#60
  SET Milhour=Totmin\60
  IF Milhour=12 { SET Hour=12,Meridian=" pm" }
  ELSEIF Milhour>12 { SET Hour=Milhour-12,Meridian=" pm" }
  ELSE { SET Hour=Milhour,Meridian=" am" }
  WRITE !,Hour,":",Min,":",Sec,Meridian
  QUIT
 
Historical Note
In the “Just Ask!” column of the September 1993 issue of “M Computing”, a publication of the M Technology Association, Silver Spring, MD 20903, James M. Poitras explained the choice of starting date for $HOROLOG:
    "Starting in early 1969, our group created the Chemistry Lab
     application at Massachusetts General Hospital (MGH), which was
     the first package in the MGH MUMPS with Global Data Storage and
     many of the features of the language today..."

    "When we started programming, there were no utility programs of
     any type. We had to write them all: time, date, verify database,
     global tally, print routine, etc. I ended up writing initial
     versions of most of these.

    "When I decided on specifications for the date routine, I
     remembered reading of the oldest (one of the oldest?)
     U.S. citizen, a Civil War veteran, who was 121 years old at the
     time. Since I wanted to be able to represent dates in a
     Julian-type form so that age could be easily calculated and to be
     able to represent any birth date in the numeric range selected, I
     decided that a starting date in the early 1840s would be 'safe'.
     Since my algorithm worked most logically when every fourth year
     was a leap year, the first year was taken as 1841. The zero point
     was then December 30, 1840...

    "That's the origin of December 31, 1840 or January 1, 1841. I
      wasn't party to the MDC (M Development Committee) negotiations,
      but I did explain the logic of my choice to members of the
      Committee." 
See Also