Question
· Aug 24, 2020

How do I do time comparison on IRIS 2020.1 using the W3C format?

I am trying to compare times on an IRIS instance. The times are in the W3C format (https://www.w3.org/TR/NOTE-datetime). Are there any in-built helper functions in IRIS to support time comparisons in this format or will I need to parse it using functions such as $zdateh and $ztimeh to do the comparisons?

Discussion (6)1
Log in or sign up to continue

ISO 8601 time format is either yyyy-mm-ddZhh:mm:ss (UTC time) or yyyy-mm-ddThh:mm:ss+TZ (local time)
where TZ is the time zone.

If both times are UTC time, then just compare.
If the times are local times and both times are in the same TZ then just compare
in elsecase either convert both times to UTC or one of the times to the TZ of the another time.
Then just compare.

The compare function is just a $select(), nothing more:

t1, t2 are the times, then

if $select(t1]t2:"t1 later", t1=t2:"equal", 1:"t1 is earlier")

or more general:

set result=$select(t1]t2:1, t1=t2:0, 1:-1)
if result>0 write "t1 is later then t2"
if result>=0 write "t1 is later or equal to t2"
...

@Vic Sun @Julius Kavay Thanks! I wanted to stay away from using Ens classes because by namespace may not map from ENSLIB. I did the following for conversion and used DATEDIFF for comparison:

ClassMethod ConvertW3CToTimestampUTC(pDateTime As %String) As %TimeStamp
{
    Set date = $Piece(pDateTime, "T", 1)
    Set time = $Piece(pDateTime, "T", 2)
    
    // Validation
    Set containsPlus = ($Find(time, "+") > 0)
    Set containsMinus = ($Find(time, "-") > 0)
    Set containsZ = ($Find(time, "Z") > 0)
    If ((containsPlus + containsZ + containsMinus) > 1) {
        $$$ThrowStatus($$$ERROR($$$GeneralError, "Invalid time format. Cannot contain multiple timezone offset formats"))
    }
    If ((containsPlus + containsZ + containsMinus) = 0) {
        $$$ThrowStatus($$$ERROR($$$GeneralError, "Invalid time format. Missing timezone offset"))
    }
    
    Set parsedTime = ""
    Set dateAdd = ""
    
    // Obtain UTC time
    If containsZ {
        Set parsedTime = $Extract(time, 1, *-1)
    } Else {
        Set operator = $Case(containsPlus, 1: "+", : "-")
        
        Set absTime = $Piece(time, operator, 1)
        Set offset = $Piece(time, operator, 2)
        Set $ListBuild(offsetHours, offsetMinutes) = $ListFromString(offset, ":")
        Set offsetHours = "-"_operator_offsetHours
        Set offsetMinutes = "-"_operator_offsetMinutes
        Set $ListBuild(hours, minutes, seconds) = $ListFromString(absTime, ":")
        
        Set computedMinutes = minutes + offsetMinutes
        Set netMinutes = computedMinutes#60
        Set hoursAdd = $Case((computedMinutes < 0), 1: -1, : $Case((computedMinutes >= 60), 1: 1, : 0))
        Set computedHours = (hours + offsetHours + hoursAdd)
        Set netHours = computedHours#24
        Set dateAdd = $Case((computedHours < 0), 1: -1, : $Case((computedHours >= 24), 1: 1, : 0))
        
        // Add padding of 0's if needed
        If ($Length(netHours) = 1) {
            Set netHours = "0"_netHours
        }
        If ($Length(netMinutes) = 1) {
            Set netMinutes = "0"_netMinutes
        }
        
        Set parsedTime = netHours_":"_netMinutes_":"_seconds
    }
    Set dateTime = date_" "_parsedTime
    If (dateAdd '= "") {
        // Adjust date
        Set dateTime = $System.SQL.DATEADD("day", dateAdd, dateTime)
    }
    Return dateTime
}

First, I think, you should check the above method...
You use the date variable two times

set date = $piece(...)
return date_" "...


I'm pretty shure, if the time in Vienna (Europe) is 00:30:00 then the coresponding UTC time is 23:30:00 previous day (standard time). But you never change the date variable!
As a timestamp:
2020-08-31T00:30:00+01:00 (Vienna, 31. August)
2020-08-30Z23:30:00 (UTC,  30.August)

Second (but this is just my very privete view), checking time(stamp) format should be done BEFORE calling the ConvertW3CToTimestampUTC() method and not in the method itself.

The holy trinity of programming is:
1) accept data (data input)
2) check the data
3) if the data is OK use it, else back to input (or return an error)

If you accpet data without checking, it means, every time, you intend to use those data, you have to check them again and again (as above), wich is not very efficient.

@Julius Kavay Thanks for catching that! I had only tested with UTC time when I posted that. Have updated the code in the previous comment to account for roll over of hours/days.

Regarding your second point, I agree that validation should be done before processing the data. I have moved validation to the beginning of the method. Currently I don't have a use case for having validation be in its own method but if I do later, it would be easy to refactor it out from this method.