第六章 Caché 变量大全 $HOROLOG 变量
包含当前进程的本地日期和时间。
大纲
$HOROLOG
$H
描述
$HOROLOG
包含当前进程的日期和时间。它可以包含以下值:
- 当前的本地日期和时间。
- 当前的本地日期和时间,已针对其他时区偏移进行了调整。
- 用户指定的非递增日期。时间仍然是当前当地时间。
$HOROLOG
包含一个字符串,该字符串由两个整数值组成,并用逗号分隔。这两个整数表示Caché存储格式的当前本地日期和时间。这些整数是计数器,而不是用户可读的日期和时间。 $HOROLOG
以以下格式返回当前日期和时间:
ddddd,sssss
第一个整数ddddd
是当前日期,表示为自1840年12月31日以来的天数,其中第1天是1841年1月1日。由于Caché使用从任意起始点开始的计数器表示日期,因此Caché不受影响到2000年边界。此日期整数的最大值为2980013,它对应于9999年12月31日。
第二个整数sssss
是当前时间,表示为从当天午夜开始的秒数。系统将时间字段从0递增到86399秒。当它在午夜达到86399时,系统会将时间字段重置为0,并将日期字段增加1。$HOROLOG
会截断小数秒;它仅代表整秒的时间。
可以通过调用Horolog()
方法来获得相同的当前日期和时间信息,如下所示:
DHC-APP>WRITE $SYSTEM.SYS.Horolog()
65742,81790
分割日期与时间
要获取$HOROLOG
的日期部分或时间部分,可以使用$PIECE
函数,指定逗号作为分隔符:
/// d ##class(PHA.TEST.SpecialVariables).HOROLOG()
ClassMethod HOROLOG()
{
SET dateint=$PIECE($HOROLOG,",",1)
SET timeint=$PIECE($HOROLOG,",",2)
WRITE !,"Date and time: ",$HOROLOG
WRITE !,"Date only: ",dateint
WRITE !,"Time only: ",timeint
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).HOROLOG()
Date and time: 65760,57634
Date only: 65760
Time only: 57634
要只获取$HOROLOG
值的日期部分,还可以使用以下编程技巧:
/// d ##class(PHA.TEST.SpecialVariables).HOROLOG1()
ClassMethod HOROLOG1()
{
SET dateint=+$HOROLOG
WRITE !,"Date and time: ",$HOROLOG
WRITE !,"Date only: ",dateint
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).HOROLOG1()
Date and time: 65760,57687
Date only: 65760
加号(+
)使Caché将$HOROLOG
字符串解析为数字。当Caché遇到非数字字符(逗号
)时,它将截断字符串的其余部分并返回数字部分。这是字符串的日期整数部分。
日期和时间函数比较
比较了返回当前日期和时间的各种方法,如下所示:
-
$HOROLOG
以Caché存储格式包含经过变量调整的本地日期和时间。根据$ZTIMEZONE
特殊变量的当前值确定本地时区,然后针对本地时区(例如,夏令时)进行调整。它仅返回整秒;小数秒被截断。 -
$NOW
返回当前进程的本地日期和时间。$NOW
以Caché存储格式返回日期和时间。它包括小数秒;小数位数是当前操作系统支持的最大精度。-
$NOW()
根据$ZTIMEZONE
特殊变量的值确定本地时区。本地时间未针对本地时间变量进行调整,例如夏令时。因此,它可能与本地时钟时间不对应。 -
$NOW(tzmins)
返回与指定的tzmins时区参数相对应的时间和日期。$ZTIMEZONE
的值将被忽略。
-
-
$ZTIMESTAMP
包含Caché存储格式的UTC(世界标准时间)日期和时间,以秒为单位。小数秒以三位精度(在Windows系统上)或六位精度(在UNIX®系统上)表示。
日期和时间转换
可以使用$ZDATE
函数将$HOROLOG
的日期部分转换为用户可读的外部格式。可以使用$ZTIME
函数将$HOROLOG
的时间部分转换为外部用户可读形式。可以使用$ZDATETIME
函数转换日期和时间。使用$HOROLOG
时,在这些函数中设置时间值的精度总是返回零(以小数秒为单位)。
可以使用$ZDATEH
函数将用户可读的日期转换为$HOROLOG
的日期部分。可以使用$ZTIMEH
函数将用户可读的时间转换为$HOROLOG
的时间部分。可以使用$ZDATETIMEH
函数将日期和时间都转换为$HOROLOG
值。
设定日期和时间
可以使用%SYSTEM.Process
类的FixedDate()
方法将$HOROLOG
设置为当前进程的用户指定日期。 $HOROLOG
不能使用SET
命令修改。尝试这样做会导致<SYNTAX>
错误。
/// d ##class(PHA.TEST.SpecialVariables).HOROLOG2()
ClassMethod HOROLOG2()
{
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"
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).HOROLOG2()
10/19/1874 16:07:51.000000000 $HOROLOG changed date
01/16/2021 16:07:51.767063000 $NOW() no date change
01/16/2021 16:07:51.767000000 $ZTS UTC-to-local no date change
01/16/2021 16:07:51.000000000 $HOROLOG current date
请注意,FixedDate()
更改$HOROLOG
值,但不更改$NOW
或$ZTIMESTAMP
值。
时区
默认情况下,$HOROLOG
包含本地时区的日期和时间。该时区默认值由操作系统提供,Caché使用该操作系统来设置$ZTIMEZONE
默认值。
更改$ZTIMEZONE
将影响当前进程的$HOROLOG
值。它更改了$HOROLOG
的时间部分,并且此时间更改也可以更改$HOROLOG
的日期部分。 $ZTIMEZONE
是格林威治子午线的固定时区偏移量;不能适应当地的季节性变化,例如夏令时。
夏令时
$HOROLOG
根据基础操作系统提供的算法调整季节性时变。在应用了$ZTIMEZONE
值之后,Caché使用操作系统本地时间来调整$HOROLOG
(如果需要)以适应季节时变,例如夏时制。
可以使用IsDST()
方法确定当前日期或指定日期和时间的夏令时是否有效。下面的示例返回当前日期和时间的夏时制(DST
)状态。因为此状态可能在程序运行时改变,所以本示例对其进行了两次检查:
/// d ##class(PHA.TEST.SpecialVariables).HOROLOG3()
ClassMethod HOROLOG3()
{
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"}
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).HOROLOG3()
01/16/2021 16:11:39 DST not in effect
季节性时变的应用可能基于(至少)三个考虑因素而有所不同:
- 操作系统:在一个时区中,给定日期的
$HOROLOG
在不同计算机上可能有所不同。这是因为不同的操作系统使用不同的算法来应用时间变量。由于管理夏令时(和其他时变)的开始日期和结束日期的政策已更改,因此较旧的操作系统可能无法反映当前的做法,并且/或者使用较旧的$HOROLOG
值的计算可能会使用当前的开始日期和结束日期进行调整,而不是当时生效的那些。 - 政府政策随时间而变化:自1916年(欧洲大部分地区)和1918年(美国)首次采用以来,季节性时差发生了许多变化。夏令时已在许多地方被政府政策采用,拒绝和重新采用。夏令时的季节性开始和结束日期也已更改了很多次。在美国,1966年,1974-75年,1987年和2007年发生了国家政策的最新变化。由于地方立法行动的缘故,国家政策的通过或豁免也已发生。例如,亚利桑那州不遵守夏令时。
- 地理位置:夏令时为夏季时间; DST开始时本地时钟向前移动(“ Spring Spring”),DST结束时本地时钟向后移动(“ Fall back”)。因此,在北半球和南半球,同一时区中的夏令时的日历开始日期和结束日期通常相反。赤道国家以及亚洲和非洲的大部分地区都没有实行夏令时。
本地时变阈值
$HOROLOG
通过咨询系统时钟来计算从午夜起的秒数。因此,如果在超过当地时差阈值(例如,夏时制的开始或结束)时系统时钟自动复位,则$HOROLOG
的时间值也会突然向前或向后移动适当的秒数。出于这个原因,如果两个$HOROLOG
时间值之间的时间间隔包含本地时变阈值,则两个$HOROLOG
时间值的比较可能会产生意外结果。
$NOW
不会针对当地时间变化进行调整。如果两个日期之间的时间段包含本地时变阈值,则在比较日期和时间值时最好使用它。
1840年以前的日期
$HOROLOG
不能直接用于表示1840年至9999年范围之外的日期。但是,可以使用CachéSQL Julian日期功能来表示远远超出此范围的历史日期。朱利安日期可以将日期表示为无符号整数,从公元前4711年(BCE)开始计数。朱利安日期没有时间部分。
可以使用TO_CHAR
SQL函数或%SYSTEM.SQL
类的Tochar()
方法将Caché $HOROLOG
日期转换为Caché Julian日期。可以使用TO_DATE
SQL函数或%SYSTEM.SQL
类的ToDate()
方法将Caché Julian日期转换为Caché $HOROLOG
日期。
下面的示例采用当前$HOROLOG
日期并将其转换为Julian日期。$HOROLOG
前的+
强制Caché将其视为一个数字,从而在逗号处截断,从而消除时间整数:
/// d ##class(PHA.TEST.SpecialVariables).HOROLOG4()
ClassMethod HOROLOG4()
{
WRITE !,"Horolog date = ",+$H
SET x=$SYSTEM.SQL.TOCHAR(+$HOROLOG,"J")
WRITE !,"Julian date = ",x
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).HOROLOG4()
Horolog date = 65760
Julian date = 2459231
下面的示例采用 Julian 日期,并将其转换为Caché $HOROLOG
日期:
/// d ##class(PHA.TEST.SpecialVariables).HOROLOG5()
ClassMethod HOROLOG5()
{
SET x=$SYSTEM.SQL.TODATE(2455030,"J")
WRITE !,"$HOROLOG date = ",x," = ", $ZDATE(x,3)
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).HOROLOG5()
$HOROLOG date = 61559 = 2009-07-17
请注意,小于1721100的朱利安日期值不能转换。生成<ILLEGAL VALUE>
错误。
示例
以下示例显示$HOROLOG
的当前内容。
DHC-APP>WRITE $HOROLOG
65760,58825
下面的示例使用$ZDATE
将$HOROLOG
中的日期字段转换为日期格式。
DHC-APP> WRITE $ZDATE($PIECE($HOROLOG,",",3))
12/31/1840
下面的示例将$HOROLOG
的时间部分转换为12个小时(上午或下午)时钟的小时:分钟:秒形式的时间。
/// d ##class(PHA.TEST.SpecialVariables).HOROLOG6()
ClassMethod HOROLOG6()
{
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
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).HOROLOG6()
4:21:59 pm
1840年12月31日的起源
在“只要问!”在马里兰州银泉市M技术协会出版的1993年9月号“M计算”的专栏中,James M.Poitras解释了$HOROLOG
起始日期的选择:
从1969年初开始,我们的小组在马萨诸塞州总医院(MGH)创建了化学实验室应用程序,这是MGH MUMPS中具有全球数据存储功能的第一个软件包,并且具有当今许多语言的功能……
当我们开始编程时,没有任何类型的实用程序。我们必须全部编写它们:时间,日期,验证数据库,全局计数,打印例程等。我最终编写了其中大多数的初始版本。
当我决定约会例程的规格时,我记得读过最古老的(最古老的之一?)。美国公民,内战老兵,当时121岁。由于我希望能够以儒略类型的形式表示日期,以便可以容易地计算年龄,并且能够表示所选数字范围内的任何出生日期,所以我决定将起始日期定在19世纪40年代初是“安全的”。因为我的算法在每四年是闰年的时候最合乎逻辑,所以第一年被认为是1841年。零点是1840年12月30日……
这就是1840年12月31日或1841年1月1日的起源。我没有参加争取民主变革运动(M Development Committee)的谈判,但我确实向委员会成员解释了我选择的逻辑……