Created
June 11, 2015 13:52
-
-
Save wags/295853c8f7c44bda04a2 to your computer and use it in GitHub Desktop.
Various date & time methods not handled by OCONV, eg.ISO8601, RFC1123
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function DATE.UTILITY(method,arguments) | |
* DTV: Various date & time methods not handled by OCONV, eg.ISO8601, RFC1123 | |
*// Stuart Boydell 2003-02-24 | |
*// | |
*// Change E.DEFAULT.TZ for target server time zone locale. | |
*// | |
*// see http://www.timeanddate.com for more information about times and time zones | |
*// | |
*// Catalog this globally. | |
*// Call as either function ! i-type subr() with method and arguments. | |
*// Methods and arguments are enumerated in the Mainline subroutine. | |
*// No method, default datetime() string is returned | |
*// No arguments, results for "now" are returned. | |
*// Use of Epoch time - seconds since 1970-01-01T00:00Z | |
*// Use of iso8601 date time formats (used extensively with xml, html & sql) | |
*// general format is: YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+10:00) | |
*// | |
*// Usage 1: program | |
*// PROGRAM SOME.PROGRAM | |
*// DEFFUN DATE.UTIL(method,arguments) CALLING '*DATE.UTILITY' | |
*// ... | |
*// MY.METHOD = 'GetISODateTime' | |
*// MY.ARGUMENTS = ORD.DATE:@AM:ORD.TIME | |
*// ISO.DATE.TIME = DATE.UTIL(MY.METHOD,MY.ARGUMENTS) | |
*// | |
*// Usage 2: I-type from a file with MY.DATE/TIME.FIELD attributes. | |
*// 0001 I | |
*// 0002 subr('*DATE.UTILITY','GetISODateTime',MY.DATE.FIELD:@AM:MY.TIME.FIELD) | |
*// ... | |
*// | |
*// see Methods below for further information. | |
*-------------------------------------------- | |
DefineEquates: | |
*-------------------------------------------- | |
equ E.THIS.PROG to 'DATE.UTILITY', | |
E.VERSION to '1.0' | |
*// set this to your local server time as a default/fallback position | |
equ E.DEFAULT.TZ to 'EET-10EETDT-11,M10.5.0,M3.5.0' | |
*// various time constants | |
equ E.SECS.PER.MIN to 60, | |
E.SECS.PER.HOUR to 3600, | |
E.SECS.PER.DAY to 86400, | |
E.SECS.PER.YEAR to 31556926, ;*// tropical year seconds (approx 365.25 days) | |
E.EPOCH.SECS to system(99),;*// seconds from 1970-01-01T00:00Z | |
E.EPOCH.OFFSET to 732 ;*// iconv('01-Jan-1970','d') | |
*// numeric ordinal suffix ; eg 1st 2nd 3rd 4th ... | |
equ E.NUM.SUFFIX to 'st':@am:'nd':@am:'rd':@am:'th' | |
*// codes, characters, conversions and such | |
equ E.ISODATE.CONV to 'D-YMD[4,2,2]', | |
E.ISOTIME.CONV to 'MT', | |
E.RFCDATE.CONV to 'D WBDMBYL[", "]', | |
E.RFCTIME.CONV to 'MTS', | |
E.TZ.ENVSTR to 'TZ', ;*// time zone environment string lead-in | |
E.ISOTIME.SEP to 'T', | |
E.ISOZONE.SEP to 'Z', | |
E.PLUS to '+', | |
E.MINUS to '-', | |
E.POINT to '.', | |
E.TMP.ID to @tty:'tz.vbs' | |
*// timeZoneArray | |
*// 1=tz desc, 2=tz offset, 3=dls desc, 4=dls offset | |
*// 5=start month, 6=week, 7=day, 8=time | |
*// 9=stop month, 10=week, 11=day, 12=time | |
equ E.GTZO.DESC to timeZoneArray<1>, | |
E.GTZO.OFFSET to timeZoneArray<2>, | |
E.GTZO.DLS.DESC to timeZoneArray<3>, | |
E.GTZO.DLS.OFFSET to timeZoneArray<4>, | |
E.GTZO.START.MONTH to timeZoneArray<5>, | |
E.GTZO.START.WEEK to timeZoneArray<6>, | |
E.GTZO.START.DAY to timeZoneArray<7>, | |
E.GTZO.START.TIME to timeZoneArray<8>, | |
E.GTZO.STOP.MONTH to timeZoneArray<9>, | |
E.GTZO.STOP.WEEK to timeZoneArray<10>, | |
E.GTZO.STOP.DAY to timeZoneArray<11>, | |
E.GTZO.STOP.TIME to timeZoneArray<12> | |
*-------------------------------------------- | |
Mainline: | |
*-------------------------------------------- | |
returnValue = oconv('','c') ;*// set RV to '' and status() function to false | |
*// handle passed method parameter | |
begin case | |
case method = 'GetDateFormat' | |
*// args: null | |
*// return: true/false | |
gosub GetDateFormat: | |
case method = 'GetElapsedPeriod' | |
*// args: start date @am stop date | |
*// return: elapsed years am months am days | |
gosub GetElapsedPeriod: | |
case method = 'GetElapsedTime' | |
*// args: [start date @vm] start time @am [stop date @vm] stop time | |
*// return: difference in seconds | |
gosub GetElapsedTime: | |
case method = 'GetElapsedTime.toString' | |
*// args: [start date @vm] start time @am [stop date @vm] stop time | |
*// return: oconv'd time (hh:mm:ss) | |
gosub GetElapsedTime: | |
returnValue = oconv(returnValue,E.ISOTIME.CONV) | |
if status() then returnValue = '' | |
case method = 'GetEpochTime' | |
*// args: [date][@am time][@am timeZoneString] | |
*// return: epoch time - seconds from epoch | |
gosub GetEpochTime: | |
case method = 'GetISODateTime' ! method = 'getISODateTime.toString' | |
*// args: [date],[time],[timezone] | |
*// return ISO Date Time string yyyy-mm-ddThh:mm:ssZ | |
gosub GetISODateTime: | |
case method = 'GetISOWeekOfYear' | |
*// args: [date] | |
*// return ISO8601 week of year | |
gosub GetISOWeekOfYear: | |
case method = 'GetRFCDateTime' | |
*// args: [date],[time] | |
*// return rfc1123 Date Time string: Sun, 06 Nov 1994 08:49:37 GMT | |
gosub GetRFCDateTime: | |
case method = 'GetNumberSuffix' | |
*// args: number | |
*// return: numeric ordinal suffix ('st,nd,rd,th') | |
gosub GetNumberSuffix: | |
case method = 'GetTimeZoneString' | |
*// args: null | |
*// return users current TZ string | |
gosub GetTimeZoneString: | |
case method = 'GetTimeZoneStringFromArray' | |
*// args: TimeZoneArray (eg timeZoneArray) | |
*// return users current TZ string | |
gosub GetTimeZoneStringFromArray: | |
case method = 'ParseEpochTime' | |
*// args: [UTCSeconds][@am timeZoneString] | |
*// return: date:@am:time [local at the time zone] | |
gosub ParseEpochTime: | |
case method = 'ParseEpochTime.toString' | |
*// args: a value being seconds from epoch | |
*// return: iso date time | |
gosub ParseEpochTime: | |
arguments = returnValue | |
gosub GetISODateTime: | |
case method = 'ParseISODateTime' | |
*// args: ISO formatted date string eg 1997-07-16T19:20+10:00 | |
*// return epoch time - seconds from 1/1/70 UTC | |
gosub ParseISODateTime: | |
case method = 'ParseISODateTime.local' | |
*// args: ISO formatted date string eg 1997-07-16T19:20+10:00 | |
*// return (user local) date:@am:time | |
gosub ParseISODateTime: | |
if validTime then | |
arguments = returnValue | |
gosub ParseEpochTime: | |
end | |
case method = 'ParseRFCDateTime' | |
*// args: rfc1123 Date Time string: Sun, 06 Nov 1994 08:49:37 GMT | |
*// return Epoch time - seconds from epoch | |
gosub ParseRFCDateTime: | |
case method = 'ParseRFCDateTime.local' | |
*// args: rfc1123 Date Time string: Sun, 06 Nov 1994 08:49:37 GMT | |
*// return (user local) date:@am:time | |
gosub ParseRFCDateTime: | |
arguments = returnValue | |
gosub ParseEpochTime: | |
case method = 'ParseTimeZoneString' | |
*// args: [time zone string] | |
*// return Time Zone Object | |
gosub ParseTimeZoneString: | |
case method = 'SetDateEuropean' | |
*// deprecated - used in legacy calls - use setDateFormat | |
*// args: null | |
*// return: null | |
arguments = 'ON' | |
gosub SetDateFormat: | |
case method = 'SetDateFormat' | |
*// args: set [ON/OFF][D new date format] | |
*// return: null | |
gosub SetDateFormat: | |
case @true | |
*// default case, return time date string | |
*// return: timedate eg "15:39:12 22 APR 2003" | |
returnValue = timedate() | |
end case | |
return(returnValue) | |
stop | |
*-------------------------------------------- | |
GetDateFormat: *// International = true, US = false | |
*-------------------------------------------- | |
getDateFormatCmd = 'DATE.FORMAT INFORM' | |
execute getDateFormatCmd capturing cap returning returnValue | |
return(@null) | |
*-------------------------------------------- | |
GetElapsedPeriod: | |
*-------------------------------------------- | |
periodStart = arguments<1> | |
periodEnd = arguments<2> | |
if (periodEnd >= periodStart) then | |
totalYears = oconv(periodEnd,'dy') - oconv(periodStart,'dy') | |
totalMonths = oconv(periodEnd,'dm') - oconv(periodStart,'dm') | |
totalDays = oconv(periodEnd,'dd') - oconv(periodStart,'dd') | |
if (totalDays < 0) then | |
totalDays += oconv(iconv('1 ':oconv(periodEnd,'d mby'),'d') -1,'dd') | |
totalMonths -= 1 | |
end | |
if (totalMonths < 0) then | |
totalMonths += 12 | |
totalYears -= 1 | |
end | |
returnValue = totalYears : @am : totalMonths : @am : totalDays | |
end | |
return(@null) | |
*-------------------------------------------- | |
GetElapsedTime: *// find elapsed time from 2 second counts | |
*-------------------------------------------- | |
startTime = arguments<1> | |
stopTime = arguments<2> | |
begin case | |
case dcount(startTime,@vm) = 2 & dcount(stopTime,@vm) = 2 ;*// dates & times provided | |
arguments = raise(startTime<1>) | |
gosub GetEpochTime: ;*// get start as secs from epoch | |
startTime = returnValue | |
arguments = raise(stopTime<1>) | |
gosub GetEpochTime: ;*// get stop as secs from epoch | |
returnValue -= startTime | |
case not(num(startTime) & num(stopTime)) ;*// bad data | |
case (startTime - stopTime) > E.SECS.PER.DAY | |
case stopTime < startTime | |
*// calculate up to same time over a midnight boundry | |
*// ie start=23:00, end=03:00 : total => (27:00 - 23:00) => 05:00 | |
returnValue = stopTime + E.SECS.PER.DAY - startTime | |
case @true | |
returnValue = (stopTime - startTime) | |
end case | |
return(@null) | |
*-------------------------------------------- | |
GetEpochTime: *// return seconds from 1/1/70 UTC | |
*-------------------------------------------- | |
internalDate = arguments<1> | |
internalTime = arguments<2> | |
timeZoneString = arguments<3> | |
if internalDate = '' then internalDate = date() | |
if internalTime = '' then internalTime = time() | |
if timeZoneString = '' then | |
*// get default | |
gosub GetTimeZoneString: | |
timeZoneString = returnValue | |
end | |
arguments = timeZoneString | |
gosub ParseTimeZoneString: | |
arguments = internalDate | |
gosub GetTimeZoneOffset: | |
returnValue += (internalDate - E.EPOCH.OFFSET) * E.SECS.PER.DAY | |
returnValue += internalTime | |
return(@null) | |
*-------------------------------------------- | |
GetISODateTime: *// return date in ISO format yyyy-mm-ddThh:mm:ssZhh:mm | |
*-------------------------------------------- | |
internalDate = arguments<1> | |
internalTime = arguments<2> | |
if unassigned(timeZoneString) then timeZoneString = arguments<3> | |
if internalDate = '' then internalDate = date() | |
if internalTime = '' then internalTime = time() | |
if timeZoneString = '' then | |
*// get default | |
gosub GetTimeZoneString: | |
timeZoneString = returnValue | |
end | |
isoDate = oconv(internalDate,E.ISODATE.CONV) | |
if not(status()) then | |
isoTime = oconv(internalTime,E.RFCTIME.CONV) | |
if not(status()) then | |
if len(timeZoneString) then | |
arguments = timeZoneString | |
gosub ParseTimeZoneString: | |
end | |
arguments = internalDate | |
gosub GetTimeZoneOffset: | |
arguments = returnValue | |
gosub GetISOZone: | |
if not(status()) then | |
returnValue = isoDate : E.ISOTIME.SEP : isoTime : returnValue | |
end | |
end | |
end | |
return(@null) | |
*-------------------------------------------- | |
GetISOWeekOfYear: | |
*-------------------------------------------- | |
internalDate = arguments<1> | |
if internalDate = '' then internalDate = date() | |
dayOfWeek = oconv(internalDate, 'dw') | |
if status() then ;*// test for bad conversion | |
weekNumber = '-1' | |
end else | |
thisThursday = internalDate - dayOfWeek + 4 ;* calculate date for that Thursday | |
dayOfYear = oconv(thisThursday,'dj') | |
weekNumber = int((dayOfYear + 6) / 7) ;*// ta WOL | |
end | |
returnValue = weekNumber | |
return(@null) | |
*-------------------------------------------- | |
GetISOZone: *// return ISO time zone offset | |
*-------------------------------------------- | |
localOffsetSecs = arguments | |
isoZone = oconv(abs(localOffsetSecs),E.ISOTIME.CONV) | |
begin case | |
case status() ;*// invalid oconv 15-Apr-2003 return default offset for melbourne | |
returnValue = '+10:00' | |
case abs(localOffsetSecs) >= E.SECS.PER.DAY ;*// invalid offset value 15-Apr-2003 return default offset for melbourne | |
returnValue = '+10:00' | |
case localOffsetSecs < 0 | |
returnValue = E.PLUS:isoZone | |
case localOffsetSecs > 0 | |
returnValue = E.MINUS:isoZone | |
case localOffsetSecs = 0 | |
returnValue = E.ISOZONE.SEP:isoZone | |
case @true | |
returnValue = '+10:00' | |
end case | |
return(@null) | |
*-------------------------------------------- | |
GetRFCDateTime: *// return Date Time string: Sun, 06 Nov 1994 08:49:37 GMT | |
*-------------------------------------------- | |
gosub GetEpochTime: | |
*// get time and date at GMT | |
internalDate = int(returnValue/E.SECS.PER.DAY) + E.EPOCH.OFFSET - (returnValue < 0) | |
internalTime = mod(returnValue,E.SECS.PER.DAY) + (E.SECS.PER.DAY * (returnValue < 0)) | |
rfcDate = oconv(internalDate,E.RFCDATE.CONV) | |
if not(status()) then | |
rfcTime = oconv(internalTime,E.RFCTIME.CONV) | |
if not(status()) then | |
returnValue = rfcDate : ' ': rfcTime : ' GMT' | |
end | |
end | |
return(@null) | |
*-------------------------------------------- | |
GetNumberSuffix: *// get numerical ordinal suffix | |
*-------------------------------------------- | |
number = arguments<1> | |
if len(number) then | |
lastChar = number[1] ;*// right(number,1) | |
lastTeen = number[2] ;*// right(number,2) | |
begin case | |
case lastTeen >= 11 & lastTeen <= 20 | |
returnValue = number:(E.NUM.SUFFIX)<4> | |
case lastChar > 0 & lastChar <= 3 | |
returnValue = number:(E.NUM.SUFFIX)<lastChar> | |
case @true | |
returnValue = number:(E.NUM.SUFFIX)<4> | |
end case | |
end | |
return(@null) | |
*-------------------------------------------- | |
GetTimeZoneOffset: *// get time zone offset | |
*-------------------------------------------- | |
*// Args in: internal date | |
*// timeZoneArray required for accurate offset. | |
if unassigned(timeZoneArray) then timeZoneArray = '' | |
checkDLSFlag = num(arguments<1>) ;*// date passed in | |
checkDLSFlag = checkDLSFlag * (E.GTZO.OFFSET # E.GTZO.DLS.OFFSET) | |
checkDLSFlag = checkDLSFlag * len(E.GTZO.START.MONTH) | |
checkDLSFlag = checkDLSFlag * len(E.GTZO.START.WEEK) | |
checkDLSFlag = checkDLSFlag * len(E.GTZO.START.DAY) | |
checkDLSFlag = checkDLSFlag * len(E.GTZO.STOP.MONTH) | |
checkDLSFlag = checkDLSFlag * len(E.GTZO.STOP.WEEK) | |
checkDLSFlag = checkDLSFlag * len(E.GTZO.STOP.DAY) | |
if checkDLSFlag then | |
*// find the dls start date for this year | |
tzInternalDate = arguments<1> | |
tzYear = oconv(tzInternalDate,'d4y') | |
tzStartMonth = E.GTZO.START.MONTH | |
tzStartWeek = E.GTZO.START.WEEK | |
tzStartDay = E.GTZO.START.DAY | |
tzStartDate = iconv(tzStartMonth:'/':tzYear,'dmy') ;*// finds the first | |
tzStartOffset = tzStartDay - mod(tzStartDate,7) | |
if tzStartOffset < 1 then tzStartOffset += 7 | |
tzStartDate += tzStartOffset | |
tzStartDate += tzStartWeek * 7 | |
loop until oconv(tzStartDate,'dm') = tzStartMonth do tzStartDate -= 7 repeat | |
*// find the dls stop date for this year | |
tzStopMonth = E.GTZO.STOP.MONTH | |
tzStopWeek = E.GTZO.STOP.WEEK | |
tzStopDay = E.GTZO.STOP.DAY | |
tzStopDate = iconv(tzStopMonth:'/':tzYear,'dmy') ;*// finds the first | |
tzStopOffset = tzStopDay - mod(tzStopDate,7) | |
if tzStopOffset < 1 then tzStopOffset += 7 | |
tzStopDate += tzStopOffset | |
tzStopDate += tzStopWeek * 7 | |
loop until oconv(tzStopDate,'dm') = tzStopMonth do tzStopDate -= 7 repeat | |
*// return the appropriate time offset for the date. | |
begin case | |
case tzStartDate < tzStopDate & tzInternalDate > tzStartDate & tzInternalDate < tzStopDate ;*// northern hemisphere dls | |
timeZoneOffset = E.GTZO.DLS.OFFSET | |
case tzStartDate > tzStopDate & (tzInternalDate < tzStopDate ! tzInternalDate > tzStartDate) ;*// southern hemisphere dls | |
timeZoneOffset = E.GTZO.DLS.OFFSET | |
case @true | |
timeZoneOffset = E.GTZO.OFFSET | |
end case | |
returnValue = timeZoneOffset | |
end else | |
if abs(E.GTZO.OFFSET) > 0 then | |
timeZoneOffset = E.GTZO.OFFSET | |
returnValue = timeZoneOffset | |
end else | |
returnValue = 0 ;*// return as UTC | |
end | |
end | |
return(@null) | |
*-------------------------------------------- | |
GetTimeZoneString: *// return current unix TZ setting - unix | |
*-------------------------------------------- | |
if system(91) then ;*// WIN NT needs registry reader | |
*// http://msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_timezone.asp | |
*// return unix tz string like: EET-10EETDT-11,M10.5.0/2,M3.5.0/2 | |
open '&SAVEDLISTS&' to f.temp then | |
script = 'Set wbemObjectSet = GetObject("winmgmts:").InstancesOf("Win32_TimeZone")' | |
script<-1> = 'For Each wbemObject In wbemObjectSet : With wbemObject' | |
script<-1> = 'StdOffset = 0 - .Bias + .StandardBias' | |
script<-1> = 'SS = mid("+-",1-(StdOffset <0),1)' | |
script<-1> = 'DltOffset = 0 - .Bias + .DaylightBias' | |
script<-1> = 'DS = mid("+-",1-(DltOffset <0),1)' | |
script<-1> = 'WScript.stdOut.writeline _' | |
script<-1> = '"STD" & SS & formatdatetime(timeserial(0,StdOffset,0),4) & _' | |
script<-1> = '"DLT" & DS & formatdatetime(timeserial(0,DltOffset,0),4) & _' | |
script<-1> = '",M" & .DaylightMonth & "." & .DaylightDay & _' | |
script<-1> = '"." & .DaylightDayOfWeek & "/" & .DaylightHour & _' | |
script<-1> = '",M" & .StandardMonth & "." & .StandardDay & _' | |
script<-1> = '"." & .StandardDayOfWeek & "/" & .StandardHour' | |
script<-1> = 'End With : Next : Set wbemObjectSet = Nothing' | |
write script on f.temp,E.TMP.ID then | |
execute 'dos /c cscript //B //T:1 ^&SAVEDLISTS^&/':E.TMP.ID capturing cap | |
returnValue = cap<1> | |
end else | |
returnValue = E.DEFAULT.TZ | |
end | |
delete f.temp,E.TMP.ID | |
end else | |
returnValue = E.DEFAULT.TZ | |
end | |
end else | |
execute 'ENVIRONMENT' capturing envStrings | |
envVars = fields(envStrings,'=',1) | |
locate E.TZ.ENVSTR in envVars setting tzPos then | |
returnValue = field(envStrings<tzPos>,'=',2) | |
end else | |
returnValue = E.DEFAULT.TZ | |
end | |
end | |
return(@null) | |
*-------------------------------------------- | |
GetTimeZoneStringFromArray: *// return current unix TZ setting - unix | |
*-------------------------------------------- | |
timeZoneArray = arguments | |
if E.GTZO.DESC then | |
returnValue = E.GTZO.DESC | |
if E.GTZO.OFFSET then | |
z = int(E.GTZO.OFFSET/E.SECS.PER.HOUR) | |
if z > 0 then returnValue := E.PLUS | |
returnValue := z | |
if mod(E.GTZO.OFFSET,E.SECS.PER.HOUR) then returnValue := (':':mod(abs(E.GTZO.OFFSET),E.SECS.PER.HOUR)/E.SECS.PER.MIN) | |
end else | |
returnValue := '0' | |
end | |
if E.GTZO.DLS.DESC then | |
returnValue := E.GTZO.DLS.DESC | |
if E.GTZO.DLS.OFFSET then | |
z = int(E.GTZO.DLS.OFFSET/E.SECS.PER.HOUR) | |
if z > 0 then returnValue := E.PLUS | |
returnValue:= z | |
if mod(E.GTZO.DLS.OFFSET,E.SECS.PER.HOUR) then returnValue := ':':mod(abs(E.GTZO.DLS.OFFSET),E.SECS.PER.HOUR)/E.SECS.PER.MIN | |
end else | |
returnValue := '0' | |
end | |
returnValue := ',M':E.GTZO.START.MONTH | |
returnValue := '.':E.GTZO.START.WEEK | |
returnValue := '.':E.GTZO.START.DAY:'/2' | |
returnValue := ',M':E.GTZO.STOP.MONTH | |
returnValue := '.':E.GTZO.STOP.WEEK | |
returnValue := '.':E.GTZO.STOP.DAY:'/2' | |
end | |
end | |
return(@null) | |
*-------------------------------------------- | |
ParseEpochTime: *// return local UV seconds from 1970-01-01T00:00Z | |
*-------------------------------------------- | |
if num(arguments<1>) then | |
timeToParse = arguments<1> | |
timeZoneString = arguments<2> | |
*// convert to local time | |
if timeToParse = '' then timeToParse = E.EPOCH.SECS | |
if timeZoneString = '' then | |
*// get default | |
gosub GetTimeZoneString: | |
timeZoneString = returnValue | |
end | |
arguments = timeZoneString | |
gosub ParseTimeZoneString: | |
arguments = int(timeToParse/E.SECS.PER.DAY) + E.EPOCH.OFFSET - (timeToParse < 0) ;*// internal date - is DLS applicable? | |
gosub GetTimeZoneOffset: | |
timeToParse -= returnValue | |
*// get time and date at UTC | |
internalDate = int(timeToParse/E.SECS.PER.DAY) + E.EPOCH.OFFSET - (timeToParse < 0) | |
internalTime = mod(timeToParse,E.SECS.PER.DAY) + (E.SECS.PER.DAY * (timeToParse < 0)) | |
returnValue = internalDate:@am:internalTime | |
end | |
return(@null) | |
*-------------------------------------------- | |
ParseISODateTime: *// return Epoch | |
*-------------------------------------------- | |
* sample of possible formats for ISO date/time | |
* ISO 8601:2000, The full iso8601 date/time spec as at 2000 may be downloaded here: | |
* http://www.iso.ch/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=26780 | |
* Year: | |
* YYYY (eg 1997) | |
* Year and month: | |
* YYYY-MM (eg 1997-07) | |
* Complete date: | |
* YYYY-MM-DD (eg 1997-07-16) | |
* Complete date plus hours and minutes: | |
* YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00) | |
* Complete date plus hours, minutes and seconds: | |
* YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00) | |
* Complete date plus hours, minutes, seconds and a decimal fraction of a second | |
* YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00) | |
isoString = upcase(arguments<1>) | |
if len(isoString) then | |
isoDateString = field(isoString,E.ISOTIME.SEP,1) | |
isoTimeZoneString = field(isoString,E.ISOTIME.SEP,2) | |
internalTime = 0 | |
timeOffset = 0 | |
validTime = @true | |
internalDate = iconv(isoDateString,E.ISODATE.CONV) | |
begin case | |
case status() ;*// date not parsed | |
validTime = @false | |
case index(isoTimeZoneString,E.PLUS,1) | |
internalTime = iconv(field(isoTimeZoneString,E.PLUS,1),E.ISOTIME.CONV) | |
if status() then validTime = @false | |
timeOffset = -1 * iconv(field(isoTimeZoneString,E.PLUS,2),E.ISOTIME.CONV) | |
if status() then validTime = @false | |
case index(isoTimeZoneString,E.MINUS,1) | |
internalTime = iconv(field(isoTimeZoneString,E.MINUS,1),E.ISOTIME.CONV) | |
if status() then validTime = @false | |
timeOffset = iconv(field(isoTimeZoneString,E.MINUS,2),E.ISOTIME.CONV) | |
if status() then validTime = @false | |
case index(isoTimeZoneString,E.ISOZONE.SEP,1) | |
internalTime = iconv(field(isoTimeZoneString,E.ISOZONE.SEP,1),E.ISOTIME.CONV) | |
if status() then validTime = @false | |
case len(isoTimeZoneString) | |
internalTime = iconv(field(isoTimeZoneString,E.ISOZONE.SEP,1),E.ISOTIME.CONV) | |
if status() then validTime = @false | |
end case | |
if validTime then | |
internalDate = (internalDate - E.EPOCH.OFFSET) * E.SECS.PER.DAY | |
internalTime = internalTime + timeOffset | |
returnValue = internalDate + internalTime | |
end | |
end else | |
validTime = @false | |
end | |
return(@null) | |
*-------------------------------------------- | |
ParseRFCDateTime: *// return Epoch | |
*-------------------------------------------- | |
* RFC date time string: Sun, 06 Nov 1994 08:49:37 GMT | |
timeToParse = arguments<1> | |
if timeToParse then | |
datePart = iconv(field(timeToParse,' ',2,3),'D') | |
if not(status()) then | |
timePart = iconv(field(timeToParse,' ',5),'MT') | |
if not(status()) then | |
returnValue = datePart * E.SECS.PER.DAY + timePart | |
end | |
end | |
end | |
return(@null) | |
*-------------------------------------------- | |
ParseTimeZoneString: *// parse unix TZ env string | |
*-------------------------------------------- | |
tzString = arguments<1> | |
returnValue = '' | |
timeZoneArray = '' | |
*// 1=tz desc, 2=tz offset, 3=dls desc, 4=dls offset | |
*// 5=start month, 6=week, 7=day, 8=time | |
*// 9=stop month, 10=week, 11=day, 12=time | |
if len(tzString) then | |
*// get standard and dls offsets (and descriptors) | |
tzPart = field(tzString,',',1) | |
maxCharacter = len(tzPart) | |
for charPos = 1 to maxCharacter | |
character = tzPart[charPos,1] | |
lastDOChar = timeZoneArray[1] | |
begin case | |
case character = ':' | |
timeZoneArray := character | |
case not(alpha(character) ! num(character)) | |
timeZoneArray<-1> = character | |
case alpha(lastDOChar) & num(character) | |
timeZoneArray<-1> = character | |
case num(lastDOChar) & alpha(character) | |
timeZoneArray<-1> = character | |
case @true | |
timeZoneArray := character | |
end case | |
next charPos | |
if len(E.GTZO.OFFSET) then | |
*// convert offset to seconds | |
utcOffset = '' | |
utcOffsetTime = E.GTZO.OFFSET | |
if utcOffsetTime[1,1] = E.PLUS ! utcOffsetTime[1,1] = E.MINUS then | |
*// first char is +/- | |
utcOffset = utcOffsetTime[1,1] | |
utcOffsetTime = utcOffsetTime[2,99] | |
end | |
utcOffsetSecs = field(utcOffsetTime,':',1) * E.SECS.PER.HOUR | |
utcOffsetSecs += field(utcOffsetTime,':',2) * E.SECS.PER.MIN | |
utcOffsetSecs += field(utcOffsetTime,':',3) | |
E.GTZO.OFFSET = utcOffset:utcOffsetSecs | |
end | |
if len(E.GTZO.DLS.OFFSET) then | |
*// convert offset to seconds | |
utcOffset = '' | |
utcOffsetTime = E.GTZO.DLS.OFFSET | |
if utcOffsetTime[1,1] = E.PLUS ! utcOffsetTime[1,1] = E.MINUS then | |
*// first char is +/- | |
utcOffset = utcOffsetTime[1,1] | |
utcOffsetTime = utcOffsetTime[2,99] | |
end | |
utcOffsetSecs = field(utcOffsetTime,':',1) * E.SECS.PER.HOUR | |
utcOffsetSecs += field(utcOffsetTime,':',2) * E.SECS.PER.MIN | |
utcOffsetSecs += field(utcOffsetTime,':',3) | |
E.GTZO.DLS.OFFSET = utcOffset:utcOffsetSecs | |
end else | |
if utcOffsetSecs then ;*// use standard time as default - hour | |
*!! E.GTZO.DLS.OFFSET = utcOffset:(utcOffsetSecs - E.SECS.PER.HOUR) | |
end | |
end | |
if dcount(timeZoneArray,@am) > 4 then | |
ndo = '' | |
for i=1 to 4; ndo<i> = timeZoneArray<i>; next i | |
timeZoneArray = ndo | |
end | |
*// get summer time start params | |
tzPart = field(tzString,',',2) | |
if len(tzPart) then | |
E.GTZO.START.MONTH = '' | |
maxCharacter = len(field(tzPart,'/',1)) ;*// assume 2am start/stop | |
for charPos = 1 to maxCharacter | |
character = tzPart[charPos,1] | |
begin case | |
case character = 'M' | |
case character = 'J' ;*!!! julian date - shouldn't happen | |
case character = '.' | |
timeZoneArray := @am | |
case @true | |
timeZoneArray := character | |
end case | |
next charPos | |
E.GTZO.START.TIME = 7200 ;*// assume 2am | |
if dcount(timeZoneArray,@am) > 8 then | |
ndo = '' | |
for i=1 to 8; ndo<i> = timeZoneArray<i>; next i | |
timeZoneArray = ndo | |
end | |
end else | |
*// standard default - northern hemisphere | |
*!! E.GTZO.START.MONTH = 4 | |
*!! E.GTZO.START.WEEK = 1 | |
*!! E.GTZO.START.DAY = 0 | |
*!! E.GTZO.START.TIME = '02:00' | |
end | |
*// get summer time stop params | |
tzPart = field(tzString,',',3) | |
if len(tzPart) then | |
E.GTZO.STOP.MONTH = '' | |
maxCharacter = len(field(tzPart,'/',1)) ;*// assume 2am start/stop | |
for charPos = 1 to maxCharacter | |
character = tzPart[charPos,1] | |
begin case | |
case character = 'M' | |
case character = 'J' ;*!!! julian date - shouldn't happen | |
case character = '.' | |
timeZoneArray := @am | |
case @true | |
timeZoneArray := character | |
end case | |
next charPos | |
E.GTZO.STOP.TIME = 7200 ;*// assume 2am | |
if dcount(timeZoneArray,@am) > 12 then | |
ndo = '' | |
for i=1 to 12; ndo<i> = timeZoneArray<i>; next i | |
timeZoneArray = ndo | |
end | |
end else | |
*// standard default - northern hemisphere | |
*!! E.GTZO.STOP.MONTH = 10 | |
*!! E.GTZO.STOP.WEEK = 5 | |
*!! E.GTZO.STOP.DAY = 0 | |
*!! E.GTZO.STOP.TIME = '02:00' | |
end | |
returnValue = timeZoneArray | |
end | |
return(@null) | |
*-------------------------------------------- | |
SetDateFormat: *// 'ON' = International, 'OFF' = US | |
*-------------------------------------------- | |
switch = upcase(trim(arguments<1,1>)) | |
begin case | |
case switch = 'OFF' | |
setDateFormatCmd = 'DATE.FORMAT OFF' | |
case switch[1,1] = 'D' ;*// change default date output format | |
setDateFormatCmd = 'DATE.FORMAT ':arguments<1,1> | |
case @true | |
setDateFormatCmd = 'DATE.FORMAT ON' | |
end case | |
execute setDateFormatCmd capturing cap | |
gosub GetDateFormat: ;*// return current date format | |
return(@null) | |
*-------------------------------------------- | |
ThatsAllFolks: end | |
*-------------------------------------------- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment