DIUTC ;O-OIFO/ALA/LG - UTC Timezone API ;Dec 16, 2015  10:00 AM
 ;;22.2;VA FileMan;**2,21**;Jan 05, 2016;Build 4
 ;;Per VA Directive 6402, this routine should not be modified.
 ;
UTC(DTM,TMZ,INST,CNTRY,EXT) ;PEP - Return UTC value
 ;
 ; Input Parameters - DATE/TIME (DTM) is (*REQUIRED*) all other parameters are (Optional)
 ;
 ;   DTM   - Standard Date/Time; FileMan Internal and External; FileMan-specific e.g. NOW, T+1@12A
 ;   TMZ   - TimeZone ? Either Full Name (e.g., EASTERN; EASTERN EUPOREAN; ESTONIA; YUKON)
 ;           or Pointer to the WORLD TIMEZONE (#1.71) file.
 ;           Note: Time Zone Abbreviation (e.g. EST) can be ambiguous so is not used
 ;   INST  - Pointer to Institution (#4) file
 ;   CNTRY - Country Name or Pointer to the COUNTRY CODE (#779.004) file.
 ;           If Country Name is passed in, it must match the name in the HL7 COUNTRY file  
 ;   EXT   - Extended return value
 ;           Null=Default returns GMT with offset (internal FM format)
 ;           1 returns GMT with offset (internal FM format) with additional external values (multi-part)
 ;
 ; Output 
 ;   returns GMT with offset (internal FM format), if EXT=1 returns additional external values
 ;
 ;
 N %DT,XX,H,M,X,Y
 N CODE,DTME,GMT,GMTE,GMTO,INSTE,OFF,TMFRM,TMZE,CNTRYE,TMZEXC
 ;
 ; get values for all possible parameters
 F XX="DTM","TMZ","INST","CNTRY","EXT" S @XX=$G(@XX)
 ;
 I DTM="" Q -1_"^Date/Time parameter is missing."
 I '$P(DTM,".",2) Q -1_"^Date/Time parameter missing time."  ;p21
 I INST]"",(TMZ]""!(CNTRY]"")) Q -1_"^Institution parameter cannot include Country or Timezone parameter."
 I TMZ]"",CNTRY="" Q -1_"^Timezone parameter must include Country parameter."
 I CNTRY]"",TMZ="" Q -1_"^Country parameter must include Timezone parameter."
 I EXT'="",(EXT'=1) Q -1_"^Extended parameter must be NULL or a 1 for extended output."
 ;
 S %DT="RSTX",X=DTM D ^%DT
 I Y<0 Q Y_"^Invalid Date/Time"
 S DTM=$E(Y_"00000",1,14)
 S Y=DTM D DD^%DT S DTME=Y ; External Date/Time
 ;
 ; Find offset if timezone and country parameteres are passed
 I TMZ]"" D  ;
 . I +TMZ'=TMZ S TMZ=$$FIND1^DIC(1.71,"","X",TMZ,"","","ERROR")
 . S TMZE=$$GET1^DIQ(1.71,TMZ_",",.01,"E")
 I CNTRY]"" D  ;
 . I +CNTRY'=CNTRY S CNTRY=$$FIND1^DIC(779.004,"","MX",CNTRY,"D","","ERROR")
 ;
 ; If no timezone param, no country param, look for institution param
 ; If the institution param exists get values:
 ; institution (external), timezone (internal/external), country (internal), timezone exception (internal)
 ; If no institution param, try to get data from default instituion stored in DUZ(2)
 I TMZ="",CNTRY="" N MSG D  I $D(MSG) Q -1_MSG
 . I INST D  Q  ; if Institution is passed get data from Institution file #4
 . . S INSTE=$$GET1^DIQ(4,INST_",",.01,"E")
 . . S TMZ=$$GET1^DIQ(4,INST_",",800,"I")
 . . S TMZE=$$GET1^DIQ(4,INST_",",800,"E")
 . . S CNTRY=$$GET1^DIQ(4,INST_",",801,"I")
 . . S TMZEXC=$$GET1^DIQ(4,INST_",",802,"I")
 . . I 'TMZ!'CNTRY S MSG="^Cannot determine Country and Timezone from the Institution."
 . ; if Institution not passed try default Institution in DUZ(2)
 . I +$G(DUZ(2))=0 S MSG="^Cannot determine User location." Q  ; quit if DUZ(2) not defined with message
 . S INSTE=$$GET1^DIQ(4,+DUZ(2)_",",.01,"E")
 . S TMZ=$$GET1^DIQ(4,+DUZ(2)_",",800,"I")
 . S TMZE=$$GET1^DIQ(4,+DUZ(2)_",",800,"E")
 . S CNTRY=$$GET1^DIQ(4,+DUZ(2)_",",801,"I")
 . S TMZEXC=$$GET1^DIQ(4,+DUZ(2)_",",802,"I")
 . I 'TMZ!'CNTRY S MSG="^Cannot determine Country and Timezone from User location."
 ;
 ; uppercase the external value for Country from Description field (#2) in file (#779.004)
 I CNTRY S CNTRYE=$$UP^XLFSTR($$GET1^DIQ(779.004,CNTRY_",",2,"E"))
 ;
 I 'TMZ Q -1_"^Invalid Timezone."
 I 'CNTRY Q -1_"^Invalid Country."
 I '$D(^DIT(1.71,"AB",CNTRY,TMZ)) Q -1_"^Mismatch of Country and Timezone."
 ;
 D CHECKDST ; check for daylight savings, standard, or summer timeframe
 D GMT ; convert input time to Greenwich Mean Time based on Offset
 ;
 ; Quit with GMT+Offset only (internal value)
 I 'EXT Q GMT_GMTO
 ;
 ; Quit with "Extended" output
 Q GMT_GMTO_U_GMTE_" (UTC"_OFF_")"_U_OFF_U_$G(TMZE)_U_$G(CNTRYE)_U_$G(CODE)_U_$G(TMFRM)_U_$G(INSTE)
 ;
 ;GMT+OFFSET ^ GMT+OFFSET EXT ^ OFFSET ^ TIMEZONE EXT ^ COUTRY EXT ^ TIMEZONE ABBREV ^ TIMEFRAME EXT (DAYLIGHT,STANDARD,SUMMER) ^ INSTITUTION EXT
 ;
GMT ; calculate GMT time
 ;
 I '$D(OFF) Q  ; quit if we don't have the Offset
 ;
 S H=$E(OFF,2,3),M=$E(OFF,4,5) ; get hour and minutes from GMT offset
 S H=$TR($E(OFF),"-+","+-")_H
 S M=$TR($E(OFF),"-+","+-")_M
 S GMT=$$FMADD^XLFDT(DTM,,H,M,) ; GMT internal Date/Time value
 S GMT=$E(GMT_"00000",1,14)
 S Y=GMT D DD^%DT S GMTE=Y ; GMT External Date/Time value
 S GMTO=OFF,M=$E(GMTO,4,5)
 S GMTO=$E(GMTO,1,3)*60+M/5+500
 ;(+/-hours x 60 + minutes) / 5 = value    then   500 +/- value = offset
 ;
 ; massage offset for output
 S OFF=$E(OFF,1,3)_":"_$E(OFF,4,5)
 Q
 ;
CHECKDST ;
 ; Check if this timezone changes to daylight (or summer) time or not
 ; (TDST=1, DOES NOT CHANGE, TDST=0, does change)
 ;
 N TDST,SIEN,DIEN,CIEN,DSIEN,YEAR,YIEN,STAN,SDTM,EDTM,DST,DSAV,SAME
 ;
 S TDST=1
 S SIEN=$O(^DIT(1.71,TMZ,1,"B","SST",""))
 S DIEN=$O(^DIT(1.71,TMZ,1,"B","DST",""))
 I 'DIEN S DIEN=$O(^DIT(1.71,TMZ,1,"B","SUM",""))
 I DIEN S CIEN=$O(^DIT(1.71,TMZ,1,DIEN,1,"B",CNTRY,""))
 I $G(CIEN) S TDST=0,DST=1
 I '$G(CIEN) S TDST=1
 ; If the timezone does not change, then DST would be zero for standard time (SST)
 I $G(TDST) S DST=0
 ; retrieve the offset for daylight savings (DST=1) OR standard (DST=0)
 S STAN=^DIT(1.71,TMZ,1,SIEN,0) I DIEN'="" S DSAV=^DIT(1.71,TMZ,1,DIEN,0)
 I 'TDST D
 . S DSIEN=$O(^DIT(1.72,"B",CNTRY,""))
 . I 'DSIEN Q  ; quit if country timeframes not found in world daylight savings file #1.72
 . S SAME=$P(^DIT(1.72,DSIEN,0),"^",3)
 . I SAME'="" S DSIEN=$O(^DIT(1.72,"B",SAME,""))
 ;
 ; using the year from the date, determine the start and end date/time of world daylight savings from file #1.72
 I $G(DSIEN) D
 . S YEAR=$P($$FMTE^XLFDT(DTM\1,5),"/",3)
 . S YIEN=$O(^DIT(1.72,DSIEN,1,"B",YEAR,""))
 . I YIEN'="" S SDTM=$P(^DIT(1.72,DSIEN,1,YIEN,0),"^",2),EDTM=$P(^(0),"^",3)
 . I YIEN="" Q  ; quit if year data not found
 . ; if DST=1, daylight savings in affect, DST=0, standard time in affect
 . I DTM<SDTM!(DTM'<EDTM) S DST=0
 . I DTM'<SDTM,DTM<EDTM S DST=1
 ;
 I $G(TMZEXC)=0 S DST=0 ; Timezone Exception from Institution file #4
 ;
 I 'DST S OFF=$P(STAN,"^",2),CODE=$P(STAN,"^",3),TMFRM=$P(STAN,U)
 I DST S OFF=$P(DSAV,"^",2),CODE=$P(DSAV,"^",3),TMFRM=$P(DSAV,U)
 S TMFRM=$S(TMFRM="SST":"STANDARD",TMFRM="DST":"DAYLIGHT SAVINGS",TMFRM="SUM":"SUMMER",1:"") ; set Timeframe
 Q
 
--- Routine Detail   --- with STRUCTURED ROUTINE LISTING ---[H[J[2J[HDIUTC   6730     printed  Sep 23, 2025@20:30:48                                                                                                                                                                                                       Page 2
DIUTC     ;O-OIFO/ALA/LG - UTC Timezone API ;Dec 16, 2015  10:00 AM
 +1       ;;22.2;VA FileMan;**2,21**;Jan 05, 2016;Build 4
 +2       ;;Per VA Directive 6402, this routine should not be modified.
 +3       ;
UTC(DTM,TMZ,INST,CNTRY,EXT) ;PEP - Return UTC value
 +1       ;
 +2       ; Input Parameters - DATE/TIME (DTM) is (*REQUIRED*) all other parameters are (Optional)
 +3       ;
 +4       ;   DTM   - Standard Date/Time; FileMan Internal and External; FileMan-specific e.g. NOW, T+1@12A
 +5       ;   TMZ   - TimeZone ? Either Full Name (e.g., EASTERN; EASTERN EUPOREAN; ESTONIA; YUKON)
 +6       ;           or Pointer to the WORLD TIMEZONE (#1.71) file.
 +7       ;           Note: Time Zone Abbreviation (e.g. EST) can be ambiguous so is not used
 +8       ;   INST  - Pointer to Institution (#4) file
 +9       ;   CNTRY - Country Name or Pointer to the COUNTRY CODE (#779.004) file.
 +10      ;           If Country Name is passed in, it must match the name in the HL7 COUNTRY file  
 +11      ;   EXT   - Extended return value
 +12      ;           Null=Default returns GMT with offset (internal FM format)
 +13      ;           1 returns GMT with offset (internal FM format) with additional external values (multi-part)
 +14      ;
 +15      ; Output 
 +16      ;   returns GMT with offset (internal FM format), if EXT=1 returns additional external values
 +17      ;
 +18      ;
 +19       NEW %DT,XX,H,M,X,Y
 +20       NEW CODE,DTME,GMT,GMTE,GMTO,INSTE,OFF,TMFRM,TMZE,CNTRYE,TMZEXC
 +21      ;
 +22      ; get values for all possible parameters
 +23       FOR XX="DTM","TMZ","INST","CNTRY","EXT"
               SET @XX=$GET(@XX)
 +24      ;
 +25       IF DTM=""
               QUIT -1_"^Date/Time parameter is missing."
 +26      ;p21
           IF '$PIECE(DTM,".",2)
               QUIT -1_"^Date/Time parameter missing time."
 +27       IF INST]""
               IF (TMZ]""!(CNTRY]""))
                   QUIT -1_"^Institution parameter cannot include Country or Timezone parameter."
 +28       IF TMZ]""
               IF CNTRY=""
                   QUIT -1_"^Timezone parameter must include Country parameter."
 +29       IF CNTRY]""
               IF TMZ=""
                   QUIT -1_"^Country parameter must include Timezone parameter."
 +30       IF EXT'=""
               IF (EXT'=1)
                   QUIT -1_"^Extended parameter must be NULL or a 1 for extended output."
 +31      ;
 +32       SET %DT="RSTX"
           SET X=DTM
           DO ^%DT
 +33       IF Y<0
               QUIT Y_"^Invalid Date/Time"
 +34       SET DTM=$EXTRACT(Y_"00000",1,14)
 +35      ; External Date/Time
           SET Y=DTM
           DO DD^%DT
           SET DTME=Y
 +36      ;
 +37      ; Find offset if timezone and country parameteres are passed
 +38      ;
           IF TMZ]""
               Begin DoDot:1
 +39               IF +TMZ'=TMZ
                       SET TMZ=$$FIND1^DIC(1.71,"","X",TMZ,"","","ERROR")
 +40               SET TMZE=$$GET1^DIQ(1.71,TMZ_",",.01,"E")
               End DoDot:1
 +41      ;
           IF CNTRY]""
               Begin DoDot:1
 +42               IF +CNTRY'=CNTRY
                       SET CNTRY=$$FIND1^DIC(779.004,"","MX",CNTRY,"D","","ERROR")
               End DoDot:1
 +43      ;
 +44      ; If no timezone param, no country param, look for institution param
 +45      ; If the institution param exists get values:
 +46      ; institution (external), timezone (internal/external), country (internal), timezone exception (internal)
 +47      ; If no institution param, try to get data from default instituion stored in DUZ(2)
 +48       IF TMZ=""
               IF CNTRY=""
                   NEW MSG
                   Begin DoDot:1
 +49      ; if Institution is passed get data from Institution file #4
                       IF INST
                           Begin DoDot:2
 +50                           SET INSTE=$$GET1^DIQ(4,INST_",",.01,"E")
 +51                           SET TMZ=$$GET1^DIQ(4,INST_",",800,"I")
 +52                           SET TMZE=$$GET1^DIQ(4,INST_",",800,"E")
 +53                           SET CNTRY=$$GET1^DIQ(4,INST_",",801,"I")
 +54                           SET TMZEXC=$$GET1^DIQ(4,INST_",",802,"I")
 +55                           IF 'TMZ!'CNTRY
                                   SET MSG="^Cannot determine Country and Timezone from the Institution."
                           End DoDot:2
                           QUIT 
 +56      ; if Institution not passed try default Institution in DUZ(2)
 +57      ; quit if DUZ(2) not defined with message
                       IF +$GET(DUZ(2))=0
                           SET MSG="^Cannot determine User location."
                           QUIT 
 +58                   SET INSTE=$$GET1^DIQ(4,+DUZ(2)_",",.01,"E")
 +59                   SET TMZ=$$GET1^DIQ(4,+DUZ(2)_",",800,"I")
 +60                   SET TMZE=$$GET1^DIQ(4,+DUZ(2)_",",800,"E")
 +61                   SET CNTRY=$$GET1^DIQ(4,+DUZ(2)_",",801,"I")
 +62                   SET TMZEXC=$$GET1^DIQ(4,+DUZ(2)_",",802,"I")
 +63                   IF 'TMZ!'CNTRY
                           SET MSG="^Cannot determine Country and Timezone from User location."
                   End DoDot:1
                   IF $DATA(MSG)
                       QUIT -1_MSG
 +64      ;
 +65      ; uppercase the external value for Country from Description field (#2) in file (#779.004)
 +66       IF CNTRY
               SET CNTRYE=$$UP^XLFSTR($$GET1^DIQ(779.004,CNTRY_",",2,"E"))
 +67      ;
 +68       IF 'TMZ
               QUIT -1_"^Invalid Timezone."
 +69       IF 'CNTRY
               QUIT -1_"^Invalid Country."
 +70       IF '$DATA(^DIT(1.71,"AB",CNTRY,TMZ))
               QUIT -1_"^Mismatch of Country and Timezone."
 +71      ;
 +72      ; check for daylight savings, standard, or summer timeframe
           DO CHECKDST
 +73      ; convert input time to Greenwich Mean Time based on Offset
           DO GMT
 +74      ;
 +75      ; Quit with GMT+Offset only (internal value)
 +76       IF 'EXT
               QUIT GMT_GMTO
 +77      ;
 +78      ; Quit with "Extended" output
 +79       QUIT GMT_GMTO_U_GMTE_" (UTC"_OFF_")"_U_OFF_U_$GET(TMZE)_U_$GET(CNTRYE)_U_$GET(CODE)_U_$GET(TMFRM)_U_$GET(INSTE)
 +80      ;
 +81      ;GMT+OFFSET ^ GMT+OFFSET EXT ^ OFFSET ^ TIMEZONE EXT ^ COUTRY EXT ^ TIMEZONE ABBREV ^ TIMEFRAME EXT (DAYLIGHT,STANDARD,SUMMER) ^ INSTITUTION EXT
 +82      ;
GMT       ; calculate GMT time
 +1       ;
 +2       ; quit if we don't have the Offset
           IF '$DATA(OFF)
               QUIT 
 +3       ;
 +4       ; get hour and minutes from GMT offset
           SET H=$EXTRACT(OFF,2,3)
           SET M=$EXTRACT(OFF,4,5)
 +5        SET H=$TRANSLATE($EXTRACT(OFF),"-+","+-")_H
 +6        SET M=$TRANSLATE($EXTRACT(OFF),"-+","+-")_M
 +7       ; GMT internal Date/Time value
           SET GMT=$$FMADD^XLFDT(DTM,,H,M,)
 +8        SET GMT=$EXTRACT(GMT_"00000",1,14)
 +9       ; GMT External Date/Time value
           SET Y=GMT
           DO DD^%DT
           SET GMTE=Y
 +10       SET GMTO=OFF
           SET M=$EXTRACT(GMTO,4,5)
 +11       SET GMTO=$EXTRACT(GMTO,1,3)*60+M/5+500
 +12      ;(+/-hours x 60 + minutes) / 5 = value    then   500 +/- value = offset
 +13      ;
 +14      ; massage offset for output
 +15       SET OFF=$EXTRACT(OFF,1,3)_":"_$EXTRACT(OFF,4,5)
 +16       QUIT 
 +17      ;
CHECKDST  ;
 +1       ; Check if this timezone changes to daylight (or summer) time or not
 +2       ; (TDST=1, DOES NOT CHANGE, TDST=0, does change)
 +3       ;
 +4        NEW TDST,SIEN,DIEN,CIEN,DSIEN,YEAR,YIEN,STAN,SDTM,EDTM,DST,DSAV,SAME
 +5       ;
 +6        SET TDST=1
 +7        SET SIEN=$ORDER(^DIT(1.71,TMZ,1,"B","SST",""))
 +8        SET DIEN=$ORDER(^DIT(1.71,TMZ,1,"B","DST",""))
 +9        IF 'DIEN
               SET DIEN=$ORDER(^DIT(1.71,TMZ,1,"B","SUM",""))
 +10       IF DIEN
               SET CIEN=$ORDER(^DIT(1.71,TMZ,1,DIEN,1,"B",CNTRY,""))
 +11       IF $GET(CIEN)
               SET TDST=0
               SET DST=1
 +12       IF '$GET(CIEN)
               SET TDST=1
 +13      ; If the timezone does not change, then DST would be zero for standard time (SST)
 +14       IF $GET(TDST)
               SET DST=0
 +15      ; retrieve the offset for daylight savings (DST=1) OR standard (DST=0)
 +16       SET STAN=^DIT(1.71,TMZ,1,SIEN,0)
           IF DIEN'=""
               SET DSAV=^DIT(1.71,TMZ,1,DIEN,0)
 +17       IF 'TDST
               Begin DoDot:1
 +18               SET DSIEN=$ORDER(^DIT(1.72,"B",CNTRY,""))
 +19      ; quit if country timeframes not found in world daylight savings file #1.72
                   IF 'DSIEN
                       QUIT 
 +20               SET SAME=$PIECE(^DIT(1.72,DSIEN,0),"^",3)
 +21               IF SAME'=""
                       SET DSIEN=$ORDER(^DIT(1.72,"B",SAME,""))
               End DoDot:1
 +22      ;
 +23      ; using the year from the date, determine the start and end date/time of world daylight savings from file #1.72
 +24       IF $GET(DSIEN)
               Begin DoDot:1
 +25               SET YEAR=$PIECE($$FMTE^XLFDT(DTM\1,5),"/",3)
 +26               SET YIEN=$ORDER(^DIT(1.72,DSIEN,1,"B",YEAR,""))
 +27               IF YIEN'=""
                       SET SDTM=$PIECE(^DIT(1.72,DSIEN,1,YIEN,0),"^",2)
                       SET EDTM=$PIECE(^(0),"^",3)
 +28      ; quit if year data not found
                   IF YIEN=""
                       QUIT 
 +29      ; if DST=1, daylight savings in affect, DST=0, standard time in affect
 +30               IF DTM<SDTM!(DTM'<EDTM)
                       SET DST=0
 +31               IF DTM'<SDTM
                       IF DTM<EDTM
                           SET DST=1
               End DoDot:1
 +32      ;
 +33      ; Timezone Exception from Institution file #4
           IF $GET(TMZEXC)=0
               SET DST=0
 +34      ;
 +35       IF 'DST
               SET OFF=$PIECE(STAN,"^",2)
               SET CODE=$PIECE(STAN,"^",3)
               SET TMFRM=$PIECE(STAN,U)
 +36       IF DST
               SET OFF=$PIECE(DSAV,"^",2)
               SET CODE=$PIECE(DSAV,"^",3)
               SET TMFRM=$PIECE(DSAV,U)
 +37      ; set Timeframe
           SET TMFRM=$SELECT(TMFRM="SST":"STANDARD",TMFRM="DST":"DAYLIGHT SAVINGS",TMFRM="SUM":"SUMMER",1:"")
 +38       QUIT