;+ ; NAME: ; TimeSplit ; PURPOSE: ; Convert times from string to numerical ; CATEGORY: ; gen/idl/toolbox/time ; CALLING SEQUENCE: FUNCTION TimeSplit, TSS, T0, $ template = template , $ format = format , $ fmtspec = fmtspec ; INPUTS: ; TS array; type: string ; times in string form ; T0 array[1]; type: time structure ; time origin ; OPTIONAL INPUTS: ; format=format ; scalar; type: sting; default: none ; string template specifying the time format, e.g. 'YEAR/MN/DD hh:mm:ss.mss' ; Valid components are: ; YEAR for 4-digit year ; YY for 2-digit year (converted using TimeFixYear) ; DOY for the day of year ; MON for 3-char month ('jan') ; MN for 2-digit month (01-12) ; DD for the day of the month ; hh for the hour of the day ; mm for the minutes ; ss for the seconds ; mss for the milliseconds ; OUTPUTS: ; T array; type: time structure ; output times with numerical values for the ; seperate components of the time array ; If an error occurs then T = -1 is returned. ; The function IsTime(T) can be used to check for an ; error condition. ; OPTIONAL OUTPUTS: ; fmtspec=fmtspec ; scalar; type: string ; if format NOT set: format string used to interpret ; the input strings. ; if format SET: specfmt is same as input format ; INCLUDE: @compile_opt.pro ; On error, return to caller ; CALLS: ; InitVar, TimeSet, TimeGet, IsTime, TimeUnit, TagArray, SyncDims ; TimeFixYear, TimeOp ; RESTRICTIONS: ; The first element of the TS array is used to analyze the exact string format. ; This format is used to decompose all string elements in their constituent parts. ; Hence, if TS is a string array, all entries must have exactly the same format!!! ; PROCEDURE: ; The string times in TS do not have to be complete. ; Missing parts are taken from the time origin T0 ; Four types of strings can be entered: ; 1999:300:00:00:00.000 ; 1999/11/20 00:00:00.000 (YMD format) ; SAT JAN 10 00:00:00 1991 (SYS format) ; 19-NOV-1999 23:48:11.00 (VMS format) ; 03-23-2000 23:48:11 (SMEI format) ; 2003_023_234811000 (L1A format) ; 2003-10-11T23:48:11.000 (ISO-8601 format) ; MODIFICATION HISTORY: ; AUG-1998, Paul Hick (UCSD/CASS) ; NOV-1999, Paul Hick (UCSD/CASS) ; Added VMS format, fairly substantial rewrite ; APR-2000, Paul Hick (UCSD/CASS) ; Added SMEI format '03-23-2000 23:48:11' ; MAR-2003, Paul Hick (UCSD/CASS) ; Added processing of strings like 2003_175_123456789 ; OCT-2003, Paul Hick (UCSD/CASS) ; Added processing of strings like 2003_10_02_123456789 ; NOV-2003, Paul Hick (UCSD/CASS) ; Added keyword 'template' ; JUN-2005, Paul Hick (UCSD/CASS) ; Rename keyword 'template' to 'format'. ; SEP-2007, Paul Hick (UCSD/CASS) ; Added some code to handle ISO-8601 compliant times ; OCT-2007, Paul Hick (UCSD/CASS; pphick@ucsd.edu) ; Added output format spec keyword 'fmtspec' ;- InitVar, T0, !TimeZero IF IsType(template,/defined) THEN format = template CASE size(TSS,/n_dim) NE 0 OF 0: TS = TSS 1: TS = reform(TSS, n_elements(TSS)) ENDCASE TS0 = strtrim( strcompress(TS[0]), 2) ; First time in array is used to analyze format CASE IsType(format, /string) OF 0: BEGIN A = byte(TS0) SCOR = [where(A EQ (byte('_'))[0],nSCR),n_elements(A)] DASH = where(A EQ (byte('-'))[0],nDSH) SLSH = where(A EQ (byte('/'))[0],nSLS) COLS = where(A EQ (byte(':'))[0],nCOL) COL1 = strpos(TS0,':') COL2 = strpos(TS0,':',COL1+1) NODOT= strpos(TS0,'.') EQ -1 N = strlen(TS0) ; A system time is identified by looking for alphabetical characters ; Currently two formats are identified: ; "SAT APR 13 14:30:15 1991" (SYS format) ; "19-NOV-1999 23:48:11.00" (VMS format) ; The distinction is made by looking for a pair of dashes A = byte(strupcase(TS0)) ; Check for uppercase alphabetical character ; Finds alphabetical months, and T in ISO-8601 IF (where((byte('A'))[0] LE A AND A LE (byte('Z'))[0]))[0] NE -1 THEN BEGIN IF nDSH EQ 2 THEN BEGIN ; Two dashes: '19-NOV-1999 23:48:11.00' (VMS) ; or ; '1999-09-19T23:48:11.00' (ISO-8601) ; Split the first time only. We only want to know the length of the first ; field: an ISO-8601 time starts with a 4-digit year, a VMS time with a ; 2-digit day of the month. TS0 = TagArray(TS[0], ['-',' ',':','.'], /split, /nonull) iso8601 = strlen(TS0[0]) EQ 4 CASE iso8601 OF 0: BEGIN ; VMS TS = TagArray(TS, ['-',' ',':','.'], /split, /nonull) TT = TimeSet(yr=fix(TS[2,*]),month=TS[1,*],day=fix(TS[0,*])) fmtspec = 'DD-MON-YYYY' END 1: BEGIN ; ISO-8601 TS = TagArray(TS, ['-',':','.','T'], /split, /nonull) TT = TimeSet(yr=fix(TS[0,*]),month=fix(TS[1,*]),day=fix(TS[2,*])) fmtspec = 'YYYY-MN-DD' END ENDCASE n = (size(TS))[1] IF n GE 4 THEN BEGIN TS = TS[3:*,*] fmtspec += ([' ','T'])[iso8601] ENDIF ELSE $ TS = -1 ENDIF ELSE BEGIN ; 'SAT JAN 10 00:00:00 1991' (SYS format) TS = TagArray(TS,[' ',':'],/split, /nonull) TT = TimeSet(yr=fix(TS[6,*]),month=TS[1,*],day=fix(TS[2,*])) TS = TS[3:5,*] ; Time of day fmtspec = 'DOW MON DD hh:mm:ss YYYY' ENDELSE tod_sep = ':' ENDIF ELSE IF nSLS EQ 2 THEN BEGIN ; '1999/11/20 00:00:00.000' (YMD format) or TS = TagArray(TS,['/',' ',',',':','.'], /split, /nonull) TT = TimeSet(yr=fix(TS[0,*]),month=fix(TS[1,*]),day=fix(TS[2,*])) fmtspec = 'YYYY/MN/DD' n = (size(TS))[1] IF n GE 4 THEN BEGIN TS = TS[3:*,*] fmtspec += ' ' ENDIF ELSE $ TS = -1 tod_sep = ':' ENDIF ELSE IF nSLS EQ 1 THEN BEGIN ; '11/20 00:00:00.000' (YMD format) or TS = TagArray(TS,['/',' ',',',':','.'], /split, /nonull) TT = TimeSet(yr=TimeGet(T0,TimeUnit(/year)),month=fix(TS[1,*]),day=fix(TS[2,*])) fmtspec = 'MN/DD' n = (size(TS))[1] IF n GE 3 THEN BEGIN TS = TS[2:*,*] fmtspec += ' ' ENDIF ELSE $ TS = -1 tod_sep = ':' ENDIF ELSE IF nCOL EQ 4 THEN BEGIN ; '1999:300:00:00:00.000' TS = TagArray(TS,[':',' ','.'], /split, /nonull) TT = TimeSet(yr=fix(TS[0,*]),doy=fix(TS[1,*])) fmtspec = 'YYYY:DOY' n = (size(TS))[1] IF n GE 3 THEN BEGIN TS = TS[2:*,*] fmtspec += ':' ENDIF ELSE $ TS = -1 tod_sep = ':' ENDIF ELSE IF nCOL EQ 3 THEN BEGIN ; ' 300:00:00:00.000' TS = TagArray(TS,[':',' ','.'], /split, /nonull) TT = TimeSet(yr=TimeGet(T0,TimeUnit(/year)),doy=fix(TS[0,*])) fmtspec = 'DOY' n = (size(TS))[1] IF n GE 2 THEN BEGIN TS = TS[1:*,*] fmtspec += ':' ENDIF ELSE $ TS = -1 tod_sep = ':' ENDIF ELSE IF COL1 EQ 4 AND (COL2 EQ 8 OR (N EQ 8 AND NODOT)) then begin ; COL1=4 and COL2=8: ydoy format YEAR:DOY:..... ; extract Y and DOY ; COL1=4, N=8 and no dots: ydoy format YEAR:DOY ; extract Y and DOY TS = TagArray(TS,[':',' ','.'], /split, /nonull) TT = TimeSet(yr=fix(TS[0,*]),doy=fix(TS[1,*])) fmtspec = 'YYYY:DOY' n = (size(TS))[1] IF n GE 3 THEN BEGIN TS = TS[2:*,*] fmtspec += ':' ENDIF ELSE $ TS = -1 tod_sep = '' ENDIF ELSE IF COL1 EQ 3 THEN BEGIN ; COL1=3: ydoy format with year missing year: DOY:.... ; extract DOY ; N=3 and no dots: ydoy format (only day of year) DOY ; extract DOY TS = TagArray(TS,[':',' ','.'], /split, /nonull) TT = TimeSet(yr=TimeGet(T0,TimeUnit(/year)),doy=fix(TS[0,*])) fmtspec = 'DOY' n =(size(TS))[1] IF n GE 2 THEN BEGIN TS = TS[1:*,*] fmtspec += ':' ENDIF ELSE $ TS = -1 tod_sep = '' ENDIF ELSE IF nDSH EQ 2 THEN BEGIN ; Two dashes: '03-23-2000 23:48:11' (SMEI) ; Format used in the B'ham CCD image files TS0 = TagArray(TS[0], ['-',' ',':','.'], /split, /nonull) iso8601 = strlen(TS0[0]) EQ 4 CASE iso8601 OF 0: BEGIN TS = TagArray(TS,['-',' ',':','.'], /split, /nonull) TT = TimeSet(yr=fix(TS[2,*]),month=fix(TS[0,*]),day=fix(TS[1,*])) fmtspec = 'MN-DD-YYYY' END 1: BEGIN TS = TagArray(TS,['-',' ',':','.'], /split, /nonull) TT = TimeSet(yr=fix(TS[0,*]),month=fix(TS[1,*]),day=fix(TS[2,*])) fmtspec = 'YYYY-MN-DD' END ENDCASE n = (size(TS))[1] IF n GE 4 THEN BEGIN TS = TS[3:*,*] fmtspec += ([' ','T'])[iso8601] ENDIF ELSE $ TS = -1 tod_sep = ':' ENDIF ELSE IF nSCR GT 0 THEN BEGIN TS = TagArray(TS,'_', /split, /nonull) CASE SCOR[1]-SCOR[0]-1 OF 2: BEGIN ; Three underscores: '2000_01_23_234811000' n = (size(TS))[1] CASE n EQ 2 OF 0: BEGIN TT = TimeSet(yr=fix(TS[0,*]),month=fix(TS[1,*]), day=fix(TS[2,*])) fmtspec = 'YYYY_MN_DD' END 1: BEGIN TT = TimeSet(yr=fix(TS[0,*]),month=fix(TS[1,*]), day=1) fmtspec = 'YYYY_MN' END ENDCASE CASE n EQ 4 OF 0: TS = -1 1: BEGIN ; Time of day TS = reform(TS[3,*]) n = where(strlen(TS) GT 6) & IF n[0] NE -1 THEN TS[n] = strmid(TS[n],0,6)+'.'+strmid(TS[n],6) n = where(strlen(TS) GT 4) & IF n[0] NE -1 THEN TS[n] = strmid(TS[n],0,4)+':'+strmid(TS[n],4) n = where(strlen(TS) GT 2) & IF n[0] NE -1 THEN TS[n] = strmid(TS[n],0,2)+':'+strmid(TS[n],2) TS = TagArray(TS,[':','.'], /split, /nonull) fmtspec += '_' END ENDCASE END 3: BEGIN ; Two underscores: '2000_023_234811000' TT = TimeSet(yr=fix(TS[0,*]),doy=fix(TS[1,*])) fmtspec = 'YYYY_DOY' n = (size(TS))[1] CASE n EQ 3 OF 0: TS = -1 1: BEGIN ; Time of day TS = reform(TS[2,*]) n = where(strlen(TS) GT 6) & IF n[0] NE -1 then TS[n] = strmid(TS[n],0,6)+'.'+strmid(TS[n],6) n = where(strlen(TS) GT 4) & IF n[0] NE -1 then TS[n] = strmid(TS[n],0,4)+':'+strmid(TS[n],4) n = where(strlen(TS) GT 2) & IF n[0] NE -1 then TS[n] = strmid(TS[n],0,2)+':'+strmid(TS[n],2) TS = TagArray(TS,[':','.'], /split, /nonull) fmtspec += '_' END ENDCASE END ENDCASE tod_sep = '' ENDIF ELSE BEGIN ; Only time of day specified ???? TS = TagArray(TS,[':',' ','.'], /split, /nonull) TT = TimeSet(yr=TimeGet(T0,TimeUnit(/year)),doy= TimeGet(T0,TimeUnit(/days))) fmtspec = '' tod_sep = ':' ENDELSE ; At this point the date has been processed. Now set the time of day TTH = TimeGet(T0,TimeUnit(/hour ),/scalar) TTM = TimeGet(T0,TimeUnit(/minute),/scalar) TTS = TimeGet(T0,TimeUnit(/sec ),/scalar) TTMS = TimeGet(T0,TimeUnit(/msec ),/scalar); Time of day = Time of day of origin IF TS[0] NE -1 THEN BEGIN ; TS should always be an array with the number of time ; tags (h,m,s,ms) as first dimension n = (size(TS))[1] IF strpos(fmtspec,'hh') EQ -1 THEN BEGIN fmtspec += 'hh'+(['',tod_sep+'mm'])[n GE 2]+(['',tod_sep+'ss'])[n GE 3] IF n GE 4 THEN $ fmtspec += '.'+string(replicate((byte('f'))[0],strlen(TS[3]))) ENDIF IF NODOT THEN BEGIN A = 0 & TTH = fix(TS[0,*]) A = A+1 & IF A LT n THEN TTM = fix(TS[A,*]) A = A+1 & IF A LT n THEN TTS = fix(TS[A,*]) A = A+1 & IF A LT n THEN TTMS = fix(TS[A,*])*10^(3-strlen(TS[A,*])) ENDIF ELSE BEGIN A = n A = A-1 & IF A GE 0 THEN TTMS = fix(TS[A,*])*10^(3-strlen(TS[A,*])) A = A-1 & IF A GE 0 THEN TTS = fix(TS[A,*]) A = A-1 & IF A GE 0 THEN TTM = fix(TS[A,*]) A = A-1 & IF A GE 0 THEN TTH = fix(TS[A,*]) ENDELSE ENDIF TT = TimeOp(/add,TT, TimeSet(/diff, hour=TTH,minute=TTM,sec=TTS,msec=TTMS) ) SyncDims, TT, size=size(TSS) ; Impose structure of input array TSS END 1: BEGIN fmtspec = format cformat = strlowcase(format) A = strpos(cformat, 'year') ; Check for 4-digit year if A eq -1 then A = strpos(cformat, 'yyyy') ; Check for 4-digit year CASE A EQ -1 OF 0: BEGIN yr = fix(strmid(TS,A,4)) strput, cformat, ' ', A END 1: BEGIN A = strpos(cformat, 'yy') ; Check for 2-digit year CASE A EQ -1 OF 0: BEGIN yr = TimeFixYear(fix(strmid(TS,A,2))) strput, cformat, ' ', A END 1: yr = TimeGet(T0, TimeUnit(/year)) ENDCASE END ENDCASE date_present = 1 A = strpos(cformat, 'doy') ; Check for day of year CASE A EQ -1 OF 0: BEGIN TT = TimeSet(yr=yr, doy=fix(strmid(TS,A,3))) strput, cformat, ' ', A END 1: BEGIN A = strpos(cformat,'mon') ; Check for month as string ('jan') CASE A EQ -1 OF 0: BEGIN month = strmid(TS,A,3) strput, cformat, ' ', A END 1: BEGIN A = strpos(cformat,'mn') ; Check for month as number (1-12) CASE A EQ -1 OF 0: BEGIN month = fix(strmid(TS,A,2)) strput, cformat, ' ', A END ;1: message, 'invalid month entry in format: '+format ;1: date_present = 0 1: BEGIN CASE IsType(yr,/defined) OF 0: date_present = 0 1: month = 1 ENDCASE END ENDCASE END ENDCASE IF date_present THEN BEGIN A = strpos(cformat,'dd') CASE A EQ -1 OF 0: BEGIN TT = TimeSet(yr=yr, month=month, day=fix(strmid(TS,A,2))) strput, cformat, ' ', A END ;1: message, 'invalid day of month entry in format: '+format 1: BEGIN CASE IsType(yr,/defined) OF 0: date_present = 0 1: TT = TimeSet(yr=yr, month=month, day=1) ENDCASE END ENDCASE ENDIF END ENDCASE A = strpos(cformat, 'hh') CASE A EQ -1 OF 0: BEGIN TTH = fix(strmid(TS,A,2)) strput, cformat, ' ', A END 1: TTH = TimeGet(T0,TimeUnit(/hour),/scalar) ENDCASE A = strpos(cformat, 'mm') CASE A EQ -1 OF 0: BEGIN TTM = fix(strmid(TS,A,2)) strput, cformat, ' ', A END 1: TTM = TimeGet(T0,TimeUnit(/minute),/scalar) ENDCASE A = strpos(cformat, 'ss') CASE A EQ -1 OF 0: BEGIN TTS = fix(strmid(TS,A,2)) strput, cformat, ' ', A END 1: TTS = TimeGet(T0,TimeUnit(/sec),/scalar) ENDCASE A = strpos(cformat, 'fff') IF A EQ -1 THEN A = strpos(cformat,'mss') CASE A EQ -1 OF 0: BEGIN TTMS = fix(strmid(TS,A,3)) strput, cformat, ' ', A END 1: TTMS = TimeGet(T0,TimeUnit(/msec),/scalar) ENDCASE CASE date_present OF 0: TT = TimeSet(/diff, hour=TTH,minute=TTM,sec=TTS,msec=TTMS) 1: TT = TimeOp(/add,TT, TimeSet(/diff, hour=TTH,minute=TTM,sec=TTS,msec=TTMS) ) ENDCASE SyncDims, TT, size=size(TSS) ; Impose structure of input array TSS END ENDCASE RETURN, TT & END