- XLFDT ;ISC-SF/STAFF - Date/Time Functions ;03/27/2003 14:09 [ 07/29/2004 9:01 AM ]
- ;;8.0;KERNEL;**71,120,166,168,179,280**;Jul 10, 1995
- ;VA FileMan uses 2400 as midnight, many other system use 0000.
- ;This is true for $H and HL7, so a conversion has to adjust
- ;the day when converting Midnight.
- ;i.e. 3001225.24 is the same as HL7 '200012260000' and $H '58434,0'
- ;The range of accepted $H dates: "2,0" to "99999,85399".
- ;The range of accepted FM dates: 1410102 to 4141015 (any valid time).
- ;The range of accepted HL7 dates: 18410102 to 21141015 (any valid time).
- ;It is expected that input values are valid dates.
- ;
- HTFM(%H,%F) ;$H to FM, %F=1 for date only
- N X,%,%T,%Y,%M,%D S:'$D(%F) %F=0
- I $$HR(%H) Q -1 ;Check Range
- I '%F,%H[",0" S %H=(%H-1)_",86400"
- D YMD S:%T&('%F) X=X_%T
- Q X
- ;
- H2F(%H) ;Internal to this routine use
- N X,%,%T,%Y,%M,%D
- D YMD S:%T X=X_%T
- Q X
- ;
- YMD ;21608 = 28 feb 1900, 94657 = 28 feb 2100, 141 $H base year
- S %=(%H>21608)+(%H>94657)+%H-.1,%Y=%\365.25+141,%=%#365.25\1
- S %D=%+306#(%Y#4=0+365)#153#61#31+1,%M=%-%D\29+1
- S X=%Y_"00"+%M_"00"+%D,%=$P(%H,",",2)
- S %T=%#60/100+(%#3600\60)/100+(%\3600)/100 S:'%T %T=".0"
- Q
- ;
- FMTH(X,%F) ;FM to $H, %F=1 for date only
- N %Y,%H,%A S:'$D(%F) %F=0
- I $$FR(X) Q -1 ;$H range of 1 - 99999
- I '%F,X[".24" S %A=1
- D H S:%F %H=+%H I $D(%A) S %H=(%H+1)_",0"
- Q %H
- ;
- F2H(X) ;Internal to this routine use
- N %Y,%H,%A
- D H
- Q %H
- ;
- H ;Build %H from FM
- N %,%L,%M,%D,%T I X<1410101 S %H=0,%Y=-1 Q
- S %Y=$E(X,1,3),%M=$E(X,4,5),%D=$E(X,6,7)
- S %T=$E(X_0,9,10)*60+$E(X_"000",11,12)*60+$E(X_"00000",13,14)
- ;%L = (# leap years) - (# leap years before base)
- S %L=%Y+1700 S:%M<3 %L=%L-1 S %L=(%L\4)-(%L\100)+(%L\400)-446
- S %H=$P("^31^59^90^120^151^181^212^243^273^304^334","^",%M)+%D
- S %=('%M)!('%D),%Y=%Y-141,%H=(%H+(%Y*365)+%L+%)_","_%T,%Y=$S(%:-1,1:%H+4#7)
- Q
- ;
- HTE(%H,%F) ;$H to external
- Q:$$HR(%H) %H ;Range Check
- N Y,%T,%R
- S %F=$G(%F,1) S Y=$$HTFM(%H,0) G T2
- ;
- FMTE(Y,%F) ;FM to external
- Q:(Y<1000000)!(Y>9991231) Y ;Range Check
- N %T,%R S %F=$G(%F,1)
- ;Both HTE and FMTE come here.
- T2 S %T="."_$E($P(Y,".",2)_"000000",1,7)
- D FMT^XLFDT1 Q %R
- ;
- FR(%V) ;Check FM in valid range
- Q (%V<1410102)!(%V>4141015.235959)
- HR(%V) ;Check $H in valid range
- Q (%V<2)!(%V>99999)
- ;
- FMTHL7(%P1) ;Convert FM date/time to HL7 format
- N %T Q:'$L(%P1) "" S %P1=+%P1 ;Make sure a cononic number
- I $$FR(%P1) Q -1 ;Check range
- S %T=$P(%P1,".",2),%P1=$P(%P1,".")
- I %T=24 S %P1=$$FMADD($P(%P1,"."),1),%T="0000"
- S:%P1>1 %P1=%P1+17000000
- I $L(%T) S %T=$S($L(%T)>4:$E(%T_"00",1,6),1:$E(%T_"0000",1,4))
- I $L(%T) S %P1=%P1_%T_$$TZ()
- Q %P1
- ;
- HL7TFM(%P1,%P2,%P3) ;Convert HL7 D/T to FM.
- ;%P1 is the value to convert
- ;%P2 is if output should be local or UCT time (L,U)
- ;%P3 is 1 if the input just a time value?
- N %TZ,%LTZ,%SN,%U,%H,%M,%T Q:'$L(%P1) ""
- S %T=$E(%P1_"0000",1,8)
- S %P2=$G(%P2),%P3=+$G(%P3),%TZ="",%LTZ=$$TZ()
- I '%P3 Q:(%T<18410102)!(%T>21141015) -1 ;Date Range Check
- F %SN="+","-" I %P1[%SN D Q ;Find the timezone
- . S %TZ=$P(%P1,%SN,2),%P1=$P(%P1,%SN) I %TZ'?4N S %TZ="" Q
- . S %TZ=%SN_%TZ
- . Q
- ;FM only supports time to seconds
- S %P1=$P(%P1,".")
- ;See it just a Time value
- I %P3 S %P1="20000104"_%P1 ;Add a date
- Q:($L(%P1)#2)!(%P1'?4.14N) -1 ;Length check
- I $L(%P1)<8 S %P1=$E(%P1_"00000000",1,8) ;Fill out to 8 digits
- I %TZ="" D
- . S:%P2["L" %P2="" ;If no TZ, assume local, don't need L.
- . S:%P2["U" %TZ=%LTZ ;give the local tz
- ;
- S %P1=$S($L(%P1)>8:$E(%P1,1,8)-17000000_"."_$E(%P1,9,14),1:%P1-17000000)
- ;%P1 is now in FM format
- I %P1[".",+$P(%P1,".",2)=0 S %P1=$$FMADD(+%P1,-1)_".24"
- ;If HL7 tz and local tz are the same
- I %P2["L",%TZ=%LTZ S %P2=""
- I (%P2["U")!(%P2["L"),%P1["." D ;Build UCT from data
- . S %=$TR(%TZ,"+-","-+") ;Reverse the sign
- . S %H=$E(%,1,3),%M=$E(%,1)_$E(%,4,5)
- . S %P1=$$FMADD(%P1,,%H,%M) Q
- ;
- I %P2["L",%P1["." D ;Build local from UCT
- . S %=$$TZ(),%H=$E(%,1,3),%M=$E(%,1)_$E(%,4,5)
- . S %P1=$$FMADD(%P1,,%H,%M) Q
- Q +$S(%P3:"."_$P(%P1,".",2),1:%P1)
- ;
- DOW(X,Y) ;Day of Week
- N %Y,%M,%D,%H,%T D H I $G(Y) Q %Y
- Q $P("Sun^Mon^Tues^Wednes^Thurs^Fri^Satur","^",%Y+1)_"day"
- ;
- FMDIFF(X1,X2,X3) ;FM diff in two dates. if X3=1 in days, if X3=2 in seconds.
- N %H,%Y,X
- S X1=$G(X1),X2=$G(X2),X3=$G(X3,1)
- S:$$FR(X1) X1=0 S:$$FR(X2) X2=0 ;Check range, Use 0 for bad values
- S X=X1 D H S X1=+%H,X1(1)=$P(%H,",",2),X=X2 D H
- ;Both FMDIFF and HDIFF come here.
- D2 S X=(X1-%H) S:X3>1 X=X*86400+(X1(1)-$P(%H,",",2))
- I X3=3 S %=X,X="" S:%'<86400 X=(%\86400) S:%#86400 X=X_" "_(%#86400\3600)_":"_$E(%#3600\60+100,2,3)_":"_$E(%#60+100,2,3)
- Q X
- ;
- HDIFF(X1,X2,X3) ;$H diff in two dates, X3 same as FMDIFF.
- N X,%H,%T
- S:$$HR(X1) X1="1,1" S:$$HR(X2) X2="1,1" ;Check range, use "1,1" for bad values
- S X3=$G(X3,1)
- S X1(1)=$P(X1,",",2),X1=+X1,%H=X2
- G D2
- ;
- HADD(X,D,H,M,S) ;Add to $H date
- N %H,%T
- Q:$$HR(X) -1 ;Check Range
- S %H=+X,%T=$P(X,",",2) D A2 Q %H_","_%T
- ;
- A2 S %H=%H+$G(D),%T=%T+($G(H)*3600)+($G(M)*60)+$G(S) ;add days and seconds
- ;S:%T'<86400 %H=%H+(%T\86400),%T=%T#86400 S:%T<0 %H=%H+(%T\86400)-1,%T=%T#86400
- S %H=%H+(%T\86400) I %T<0,(%T#86400'=0) S %H=%H-1 ;Adj for sec>day
- S %T=%T#86400
- Q
- ;
- FMADD(X,D,H,M,S) ;Add to FM date
- N %H,%T,%P
- Q:$$FR(X) -1 ;Check Range
- S %P=X[".",%H=$$F2H(X),%T=$P(%H,",",2) D A2
- I %P,%T=0 S %H=%H-1,%T=86400
- Q $$H2F(%H_","_%T)
- ;
- NOW() ;Current Date/time in FM.
- Q $$HTFM($H)
- ;
- DT() ;Current Date in FM.
- Q $$HTFM($H,1)\1
- ;
- SCH(SCH,LTM,FF) ;Find the next D/T given a schedule, start time.
- Q $$DECODE^XLFDT2
- ;
- WITHIN(XLSCH,XLD) ;See if D/T is within schedule
- G WITHIN^XLFDT4
- ;
- SEC(%) ;Convert $H to seconds.
- I %?7.N.".".N S %=$$FMTH(%) ;Check for FM date
- Q 86400*%+$P(%,",",2)
- ;
- %H(%) ;Covert from seconds to $H
- Q (%\86400)_","_(%#86400)
- ;
- TZ() ;Return current Time Zone from Mailman parameter file
- N %T,%S
- S %T=$P($G(^XMB(4.4,+$P($G(^XMB(1,1,0)),"^",2),0)),"^",3),%S=$S(%T["-":"-",1:"+"),%T=$TR(%T,"-+")
- Q %S_$E(100+%T,2,3)_$S(%T[".5":"30",1:"00")
- XLFDT ;ISC-SF/STAFF - Date/Time Functions ;03/27/2003 14:09 [ 07/29/2004 9:01 AM ]
- +1 ;;8.0;KERNEL;**71,120,166,168,179,280**;Jul 10, 1995
- +2 ;VA FileMan uses 2400 as midnight, many other system use 0000.
- +3 ;This is true for $H and HL7, so a conversion has to adjust
- +4 ;the day when converting Midnight.
- +5 ;i.e. 3001225.24 is the same as HL7 '200012260000' and $H '58434,0'
- +6 ;The range of accepted $H dates: "2,0" to "99999,85399".
- +7 ;The range of accepted FM dates: 1410102 to 4141015 (any valid time).
- +8 ;The range of accepted HL7 dates: 18410102 to 21141015 (any valid time).
- +9 ;It is expected that input values are valid dates.
- +10 ;
- HTFM(%H,%F) ;$H to FM, %F=1 for date only
- +1 NEW X,%,%T,%Y,%M,%D
- IF '$DATA(%F)
- SET %F=0
- +2 ;Check Range
- IF $$HR(%H)
- QUIT -1
- +3 IF '%F
- IF %H[",0"
- SET %H=(%H-1)_",86400"
- +4 DO YMD
- IF %T&('%F)
- SET X=X_%T
- +5 QUIT X
- +6 ;
- H2F(%H) ;Internal to this routine use
- +1 NEW X,%,%T,%Y,%M,%D
- +2 DO YMD
- IF %T
- SET X=X_%T
- +3 QUIT X
- +4 ;
- YMD ;21608 = 28 feb 1900, 94657 = 28 feb 2100, 141 $H base year
- +1 SET %=(%H>21608)+(%H>94657)+%H-.1
- SET %Y=%\365.25+141
- SET %=%#365.25\1
- +2 SET %D=%+306#(%Y#4=0+365)#153#61#31+1
- SET %M=%-%D\29+1
- +3 SET X=%Y_"00"+%M_"00"+%D
- SET %=$PIECE(%H,",",2)
- +4 SET %T=%#60/100+(%#3600\60)/100+(%\3600)/100
- IF '%T
- SET %T=".0"
- +5 QUIT
- +6 ;
- FMTH(X,%F) ;FM to $H, %F=1 for date only
- +1 NEW %Y,%H,%A
- IF '$DATA(%F)
- SET %F=0
- +2 ;$H range of 1 - 99999
- IF $$FR(X)
- QUIT -1
- +3 IF '%F
- IF X[".24"
- SET %A=1
- +4 DO H
- IF %F
- SET %H=+%H
- IF $DATA(%A)
- SET %H=(%H+1)_",0"
- +5 QUIT %H
- +6 ;
- F2H(X) ;Internal to this routine use
- +1 NEW %Y,%H,%A
- +2 DO H
- +3 QUIT %H
- +4 ;
- H ;Build %H from FM
- +1 NEW %,%L,%M,%D,%T
- IF X<1410101
- SET %H=0
- SET %Y=-1
- QUIT
- +2 SET %Y=$EXTRACT(X,1,3)
- SET %M=$EXTRACT(X,4,5)
- SET %D=$EXTRACT(X,6,7)
- +3 SET %T=$EXTRACT(X_0,9,10)*60+$EXTRACT(X_"000",11,12)*60+$EXTRACT(X_"00000",13,14)
- +4 ;%L = (# leap years) - (# leap years before base)
- +5 SET %L=%Y+1700
- IF %M<3
- SET %L=%L-1
- SET %L=(%L\4)-(%L\100)+(%L\400)-446
- +6 SET %H=$PIECE("^31^59^90^120^151^181^212^243^273^304^334","^",%M)+%D
- +7 SET %=('%M)!('%D)
- SET %Y=%Y-141
- SET %H=(%H+(%Y*365)+%L+%)_","_%T
- SET %Y=$SELECT(%:-1,1:%H+4#7)
- +8 QUIT
- +9 ;
- HTE(%H,%F) ;$H to external
- +1 ;Range Check
- IF $$HR(%H)
- QUIT %H
- +2 NEW Y,%T,%R
- +3 SET %F=$GET(%F,1)
- SET Y=$$HTFM(%H,0)
- GOTO T2
- +4 ;
- FMTE(Y,%F) ;FM to external
- +1 ;Range Check
- IF (Y<1000000)!(Y>9991231)
- QUIT Y
- +2 NEW %T,%R
- SET %F=$GET(%F,1)
- +3 ;Both HTE and FMTE come here.
- T2 SET %T="."_$EXTRACT($PIECE(Y,".",2)_"000000",1,7)
- +1 DO FMT^XLFDT1
- QUIT %R
- +2 ;
- FR(%V) ;Check FM in valid range
- +1 QUIT (%V<1410102)!(%V>4141015.235959)
- HR(%V) ;Check $H in valid range
- +1 QUIT (%V<2)!(%V>99999)
- +2 ;
- FMTHL7(%P1) ;Convert FM date/time to HL7 format
- +1 ;Make sure a cononic number
- NEW %T
- IF '$LENGTH(%P1)
- QUIT ""
- SET %P1=+%P1
- +2 ;Check range
- IF $$FR(%P1)
- QUIT -1
- +3 SET %T=$PIECE(%P1,".",2)
- SET %P1=$PIECE(%P1,".")
- +4 IF %T=24
- SET %P1=$$FMADD($PIECE(%P1,"."),1)
- SET %T="0000"
- +5 IF %P1>1
- SET %P1=%P1+17000000
- +6 IF $LENGTH(%T)
- SET %T=$SELECT($LENGTH(%T)>4:$EXTRACT(%T_"00",1,6),1:$EXTRACT(%T_"0000",1,4))
- +7 IF $LENGTH(%T)
- SET %P1=%P1_%T_$$TZ()
- +8 QUIT %P1
- +9 ;
- HL7TFM(%P1,%P2,%P3) ;Convert HL7 D/T to FM.
- +1 ;%P1 is the value to convert
- +2 ;%P2 is if output should be local or UCT time (L,U)
- +3 ;%P3 is 1 if the input just a time value?
- +4 NEW %TZ,%LTZ,%SN,%U,%H,%M,%T
- IF '$LENGTH(%P1)
- QUIT ""
- +5 SET %T=$EXTRACT(%P1_"0000",1,8)
- +6 SET %P2=$GET(%P2)
- SET %P3=+$GET(%P3)
- SET %TZ=""
- SET %LTZ=$$TZ()
- +7 ;Date Range Check
- IF '%P3
- IF (%T<18410102)!(%T>21141015)
- QUIT -1
- +8 ;Find the timezone
- FOR %SN="+","-"
- IF %P1[%SN
- Begin DoDot:1
- +9 SET %TZ=$PIECE(%P1,%SN,2)
- SET %P1=$PIECE(%P1,%SN)
- IF %TZ'?4N
- SET %TZ=""
- QUIT
- +10 SET %TZ=%SN_%TZ
- +11 QUIT
- End DoDot:1
- QUIT
- +12 ;FM only supports time to seconds
- +13 SET %P1=$PIECE(%P1,".")
- +14 ;See it just a Time value
- +15 ;Add a date
- IF %P3
- SET %P1="20000104"_%P1
- +16 ;Length check
- IF ($LENGTH(%P1)#2)!(%P1'?4.14N)
- QUIT -1
- +17 ;Fill out to 8 digits
- IF $LENGTH(%P1)<8
- SET %P1=$EXTRACT(%P1_"00000000",1,8)
- +18 IF %TZ=""
- Begin DoDot:1
- +19 ;If no TZ, assume local, don't need L.
- IF %P2["L"
- SET %P2=""
- +20 ;give the local tz
- IF %P2["U"
- SET %TZ=%LTZ
- End DoDot:1
- +21 ;
- +22 SET %P1=$SELECT($LENGTH(%P1)>8:$EXTRACT(%P1,1,8)-17000000_"."_$EXTRACT(%P1,9,14),1:%P1-17000000)
- +23 ;%P1 is now in FM format
- +24 IF %P1["."
- IF +$PIECE(%P1,".",2)=0
- SET %P1=$$FMADD(+%P1,-1)_".24"
- +25 ;If HL7 tz and local tz are the same
- +26 IF %P2["L"
- IF %TZ=%LTZ
- SET %P2=""
- +27 ;Build UCT from data
- IF (%P2["U")!(%P2["L")
- IF %P1["."
- Begin DoDot:1
- +28 ;Reverse the sign
- SET %=$TRANSLATE(%TZ,"+-","-+")
- +29 SET %H=$EXTRACT(%,1,3)
- SET %M=$EXTRACT(%,1)_$EXTRACT(%,4,5)
- +30 SET %P1=$$FMADD(%P1,,%H,%M)
- QUIT
- End DoDot:1
- +31 ;
- +32 ;Build local from UCT
- IF %P2["L"
- IF %P1["."
- Begin DoDot:1
- +33 SET %=$$TZ()
- SET %H=$EXTRACT(%,1,3)
- SET %M=$EXTRACT(%,1)_$EXTRACT(%,4,5)
- +34 SET %P1=$$FMADD(%P1,,%H,%M)
- QUIT
- End DoDot:1
- +35 QUIT +$SELECT(%P3:"."_$PIECE(%P1,".",2),1:%P1)
- +36 ;
- DOW(X,Y) ;Day of Week
- +1 NEW %Y,%M,%D,%H,%T
- DO H
- IF $GET(Y)
- QUIT %Y
- +2 QUIT $PIECE("Sun^Mon^Tues^Wednes^Thurs^Fri^Satur","^",%Y+1)_"day"
- +3 ;
- FMDIFF(X1,X2,X3) ;FM diff in two dates. if X3=1 in days, if X3=2 in seconds.
- +1 NEW %H,%Y,X
- +2 SET X1=$GET(X1)
- SET X2=$GET(X2)
- SET X3=$GET(X3,1)
- +3 ;Check range, Use 0 for bad values
- IF $$FR(X1)
- SET X1=0
- IF $$FR(X2)
- SET X2=0
- +4 SET X=X1
- DO H
- SET X1=+%H
- SET X1(1)=$PIECE(%H,",",2)
- SET X=X2
- DO H
- +5 ;Both FMDIFF and HDIFF come here.
- D2 SET X=(X1-%H)
- IF X3>1
- SET X=X*86400+(X1(1)-$PIECE(%H,",",2))
- +1 IF X3=3
- SET %=X
- SET X=""
- IF %'<86400
- SET X=(%\86400)
- IF %#86400
- SET X=X_" "_(%#86400\3600)_":"_$EXTRACT(%#3600\60+100,2,3)_":"_$EXTRACT(%#60+100,2,3)
- +2 QUIT X
- +3 ;
- HDIFF(X1,X2,X3) ;$H diff in two dates, X3 same as FMDIFF.
- +1 NEW X,%H,%T
- +2 ;Check range, use "1,1" for bad values
- IF $$HR(X1)
- SET X1="1,1"
- IF $$HR(X2)
- SET X2="1,1"
- +3 SET X3=$GET(X3,1)
- +4 SET X1(1)=$PIECE(X1,",",2)
- SET X1=+X1
- SET %H=X2
- +5 GOTO D2
- +6 ;
- HADD(X,D,H,M,S) ;Add to $H date
- +1 NEW %H,%T
- +2 ;Check Range
- IF $$HR(X)
- QUIT -1
- +3 SET %H=+X
- SET %T=$PIECE(X,",",2)
- DO A2
- QUIT %H_","_%T
- +4 ;
- A2 ;add days and seconds
- SET %H=%H+$GET(D)
- SET %T=%T+($GET(H)*3600)+($GET(M)*60)+$GET(S)
- +1 ;S:%T'<86400 %H=%H+(%T\86400),%T=%T#86400 S:%T<0 %H=%H+(%T\86400)-1,%T=%T#86400
- +2 ;Adj for sec>day
- SET %H=%H+(%T\86400)
- IF %T<0
- IF (%T#86400'=0)
- SET %H=%H-1
- +3 SET %T=%T#86400
- +4 QUIT
- +5 ;
- FMADD(X,D,H,M,S) ;Add to FM date
- +1 NEW %H,%T,%P
- +2 ;Check Range
- IF $$FR(X)
- QUIT -1
- +3 SET %P=X["."
- SET %H=$$F2H(X)
- SET %T=$PIECE(%H,",",2)
- DO A2
- +4 IF %P
- IF %T=0
- SET %H=%H-1
- SET %T=86400
- +5 QUIT $$H2F(%H_","_%T)
- +6 ;
- NOW() ;Current Date/time in FM.
- +1 QUIT $$HTFM($HOROLOG)
- +2 ;
- DT() ;Current Date in FM.
- +1 QUIT $$HTFM($HOROLOG,1)\1
- +2 ;
- SCH(SCH,LTM,FF) ;Find the next D/T given a schedule, start time.
- +1 QUIT $$DECODE^XLFDT2
- +2 ;
- WITHIN(XLSCH,XLD) ;See if D/T is within schedule
- +1 GOTO WITHIN^XLFDT4
- +2 ;
- SEC(%) ;Convert $H to seconds.
- +1 ;Check for FM date
- IF %?7.N.".".N
- SET %=$$FMTH(%)
- +2 QUIT 86400*%+$PIECE(%,",",2)
- +3 ;
- %H(%) ;Covert from seconds to $H
- +1 QUIT (%\86400)_","_(%#86400)
- +2 ;
- TZ() ;Return current Time Zone from Mailman parameter file
- +1 NEW %T,%S
- +2 SET %T=$PIECE($GET(^XMB(4.4,+$PIECE($GET(^XMB(1,1,0)),"^",2),0)),"^",3)
- SET %S=$SELECT(%T["-":"-",1:"+")
- SET %T=$TRANSLATE(%T,"-+")
- +3 QUIT %S_$EXTRACT(100+%T,2,3)_$SELECT(%T[".5":"30",1:"00")