DateUtility
From Pickwiki
HomePage>>SourceCode>>BasicSource>>DateUtility
This is a toolbox of date/time zone conversion utilities, not supplied by ICONV/OCONV.
All in one convenient place!
Methods
- GetDateFormat - return: true if International format (dd/mm/yy) is set.
- GetElapsedPeriod - return: elapsed years @am months @am days
- GetElapsedTime - return: difference in seconds
- GetElapsedTime.toString - return: oconv'd time (hh:mm:ss)
- GetEpochTime - return: epoch time - seconds from 1970-01-01 UTC
- GetISODateTime - return: ISO Date Time string yyyy-mm-ddThh:mm:ssZ
- GetISOWeekOfYear - return: ISO8601 week of year
- GetRFCDateTime - return: RFC1123 Date Time string: Sun, 06 Nov 1994 08:49:37 GMT
- GetNumberSuffix - return: numeric ordinal suffix ('st,nd,rd,th')
- GetTimeZoneString - return: users current TZ string
- ParseEpochTime - return: date:@am:time [local at the time zone]
- ParseEpochTime.toString - return: iso date time
- ParseISODateTime - return: epoch time - seconds from 1970-01-01 UTC
- ParseISODateTime.local - return: (user local) date:@am:time
- ParseRFCDateTime - return: Epoch time - seconds from 1970-01-01 UTC
- ParseRFCDateTime.local - return: (user local) date:@am:time
- SetDateFormat - Set the date format ON to International (dd/mm/yy)
Background
- The main goal of this project was to provide a tool to convert to and from ISO8601. This is the date/time format used as standard in such things as XML documents. The nature of ISO8601, means that time zone must be taken into consideration. So, this turned into a bunch of methods which will also assist in Time Zone handling.
- Overkill? Well possibly for most applications. However, regard placing orders on foreign countries and setting local delivery dates & times or easily finding the east coast time of an XML document stamped with west coast time (amongst others uses). We found we had several places we needed these types of time & date conversion, so it grew.
- If you don't see something useful, please feel free to comment and add to it.
- The program is designed as a function requiring a method and input arguments and returns a result value, and sets status() if conversion fails. It means it can be easily called from basic or an I-type subr() statement. See the comments in the code for examples and details of methods and the arguments required for each method.
- Remember to tweak the E.DEFAULT.TZ equate constant, or read it in from a parameter file.
Glossary
- Epoch - meaning the Unix epoch - (milli)seconds from 1970-01-01T00:00Z.
- GMT - Greenwich Mean Time, unadjusted time at Greenwich, London UK.
- ISO - International Standards Organisation - they set, er, international standards.
- ISO8601 - Set of standards for representing local dates and time relative to UTC.
- RFC - Request For Comment. The set of documents which make up the standards which the internet is built around.
- RFC1123 - preferred as an Internet standard date format (HTTP).
- TZ - Unix environment variable used to carry time zone info. On a Windows system this must be derived from the registry.
- UTC - Universal Coordinated Time - International standard for time measurement (something close to GMT).
- Z - Zulu, shorthand for the time at zero meridian or UTC.
The Code
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 *--------------------------------------------
- Also, see Ray Wurlod's article, Date Conversion Demystified
HomePage>>SourceCode>>BasicSource>>DateUtility