第六章 Caché 变量大全 $HOROLOG 变量

第六章 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)的谈判,但我确实向委员会成员解释了我选择的逻辑……

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yaoxin521123

谢谢您的支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值