FDAN039 appears to be incomplete

June 30, 2017

This suggestion is a change to the following rule in the SEND 3.0 (FDA).xml rule set:

<val:Regex ID="SD1011" PublisherID="FDAN039" Message="Invalid ISO 8601 value for %Variable% variable" Description="Value of Duration, Elapsed Time, and Interval variables (--DUR, --ELTM, --EVLINT) must conform to the ISO 8601 international standard." Category="Format" Type="Error" Variable="%Variables[*DUR,*ELTM,*EVLINT,*PAI,TDSTOFF]%" Test="(-?P((([0-9]+(\.[0-9]+)?Y)?([0-9]+(\.[0-9]+)?M)?([0-9]+(\.[0-9]+)?D)?(T([0-9]+(\.[0-9]+)?H)?([0-9]+(\.[0-9]+)?M)?([0-9]+S)?)?)|[0-9]+(\.[0-9]+)?W))|((((([0-9][0-9][0-9][0-9])((-(([0][1-9])|([1][0-2])))((-(([0][1-9])|([1-2][0-9])|([3][0-1])))(T((([0-1][0-9])|([2][0-3]))((:([0-5][0-9]))(((:([0-5][0-9]))((\.[0-9]+)?))?)?)?((((\+|-)(([0-1][0-9])|([2][0-3])):[0-5][0-9])|(Z)))?))?)?)?))/((([0-9][0-9][0-9][0-9])((-(([0][1-9])|([1][0-2])))((-(([0][1-9])|([1-2][0-9])|([3][0-1])))(T((([0-1][0-9])|([2][0-3]))((:([0-5][0-9]))(((:([0-5][0-9]))((\.[0-9]+)?))?)?)?((((\+|-)(([0-1][0-9])|([2][0-3])):[0-5][0-9])|(Z)))?))?)?)?)))|(((([0-9][0-9][0-9][0-9])((-(([0][1-9])|([1][0-2])))((-(([0][1-9])|([1-2][0-9])|([3][0-1])))(T((([0-1][0-9])|([2][0-3]))((:([0-5][0-9]))(((:([0-5][0-9]))((\.[0-9]+)?))?)?)?((((\+|-)(([0-1][0-9])|([2][0-3])):[0-5][0-9])|(Z)))?))?)?)?))/(((\+|-)?P(((([0-9]([0-9]+)?)Y)?(([0-9]([0-9]+)?)M)?(([0-9]([0-9]+)?)D)?)(T((([0-9]([0-9]+)?)H)?(([0-9]([0-9]+)?)M)?(([0-9]([0-9]+)?)((\.[0-9]+)?)S)?)?)?|((([0-9]([0-9]+)?)W))))))|((((\+|-)?P(((([0-9]([0-9]+)?)Y)?(([0-9]([0-9]+)?)M)?(([0-9]([0-9]+)?)D)?)(T((([0-9]([0-9]+)?)H)?(([0-9]([0-9]+)?)M)?(([0-9]([0-9]+)?)((\.[0-9]+)?)S)?)?)?|((([0-9]([0-9]+)?)W)))))/((([0-9][0-9][0-9][0-9])((-(([0][1-9])|([1][0-2])))((-(([0][1-9])|([1-2][0-9])|([3][0-1])))(T((([0-1][0-9])|([2][0-3]))((:([0-5][0-9]))(((:([0-5][0-9]))((\.[0-9]+)?))?)?)?((((\+|-)(([0-1][0-9])|([2][0-3])):[0-5][0-9])|(Z)))?))?)?)?))))"/>

The numeric value associated with week is not permitted to have a decimal portion. I believe this was not intended. Also the definition of durations starting with a P that are used together with date/time fields to create an interval are specified with different limitations compared to one that has no date/time field. These later ones only permit decimal values with the seconds field and not the other fields.  The following is a correction to these.

Here is my proposed regex for the P-intervals:

 (\+|-)?
 P(
  (
   (
    ([0-9]+(\.[0-9]+)?Y)?
    ([0-9]+(\.[0-9]+)?M)?
    ([0-9]+(\.[0-9]+)?D)?
   )
   (
    T
    ([0-9]+(\.[0-9]+)?H)?
    ([0-9]+(\.[0-9]+)?M)?
    ([0-9]+(\.[0-9]+)?S)?
   )?
  )
  |
  ([0-9]+(\.[0-9]+)?)W
 )

The date-time specification appears to be correct, but doesn't permit the obscure use of "-" for an unknown element. It also permits the use of time-zones which is not described in the SENDIG.

 ([0-9][0-9][0-9][0-9])         %four digit year
 (
  (-(([0][1-9])|([1][0-2])))       %optional month 01 through 12
  (
   (-(([0][1-9])|([1-2][0-9])|([3][0-1])))  %optional day: 01 through 31
   (
    T(          %optional Time
     (([0-1][0-9])|([2][0-3]))   %00 through 23 for hour
     (
      (:([0-5][0-9]))     %:00 through :59 for min
      (
       (
        (:([0-5][0-9]))   %:00 through :59 for sec
        ((\.[0-9]+)?)   %decimal second.
       )?
      )?
     )?
     (
      (
       ((\+|-)      %timezone offset in hours and minutes or Z
        (
         ([0-1][0-9])
         |
         ([2][0-3])
        )
        :[0-5][0-9]
       )
       |
       (Z)
      )
     )?
    )
   )?
  )?
 )?

I see that structure that you have been using is as listed here.  Note: The SEND IG does not describe the use of a date-time element combined with a duration element.  It might be more accurate to list the first two approaches of duration or date-time / date-time.

(duration)|(((date-time)/(date-time))|((date-time)/(duration))|((duration)/(date-time)))

Taking these regular expressions I listed earlier and placing them into a copy of the previous line, results in what I believe would be a better regex for these intervals:

(\\+|-)?P((((([0-9]+(\\.[0-9]+)?)Y)?(([0-9]+(\\.[0-9]+)?)M)?(([0-9]+(\\.[0-9]+)?)D)?)(T(([0-9]+(\\.[0-9]+)?)H)?(([0-9]+(\\.[0-9]+)?)M)?(([0-9]+(\\.[0-9]+)?)S)?)?)|([0-9]+(\\.[0-9]+)?)W)|((([0-9][0-9][0-9][0-9])((-(([0][1-9])|([1][0-2])))((-(([0][1-9])|([1-2][0-9])|([3][0-1])))(T((([0-1][0-9])|([2][0-3]))((:([0-5][0-9]))(((:([0-5][0-9]))((\.[0-9]+)?))?)?)?((((\+|-)(([0-1][0-9])|([2][0-3])):[0-5][0-9])|(Z)))?))?)?)?/([0-9][0-9][0-9][0-9])((-(([0][1-9])|([1][0-2])))((-(([0][1-9])|([1-2][0-9])|([3][0-1])))(T((([0-1][0-9])|([2][0-3]))((:([0-5][0-9]))(((:([0-5][0-9]))((\.[0-9]+)?))?)?)?((((\+|-)(([0-1][0-9])|([2][0-3])):[0-5][0-9])|(Z)))?))?)?)?)|(([0-9][0-9][0-9][0-9])((-(([0][1-9])|([1][0-2])))((-(([0][1-9])|([1-2][0-9])|([3][0-1])))(T((([0-1][0-9])|([2][0-3]))((:([0-5][0-9]))(((:([0-5][0-9]))((\.[0-9]+)?))?)?)?((((\+|-)(([0-1][0-9])|([2][0-3])):[0-5][0-9])|(Z)))?))?)?)?/(\\+|-)?P((((([0-9]+(\\.[0-9]+)?)Y)?(([0-9]+(\\.[0-9]+)?)M)?(([0-9]+(\\.[0-9]+)?)D)?)(T(([0-9]+(\\.[0-9]+)?)H)?(([0-9]+(\\.[0-9]+)?)M)?(([0-9]+(\\.[0-9]+)?)S)?)?)|([0-9]+(\\.[0-9]+)?)W))|((\\+|-)?P((((([0-9]+(\\.[0-9]+)?)Y)?(([0-9]+(\\.[0-9]+)?)M)?(([0-9]+(\\.[0-9]+)?)D)?)(T(([0-9]+(\\.[0-9]+)?)H)?(([0-9]+(\\.[0-9]+)?)M)?(([0-9]+(\\.[0-9]+)?)S)?)?)|([0-9]+(\\.[0-9]+)?)W)/([0-9][0-9][0-9][0-9])((-(([0][1-9])|([1][0-2])))((-(([0][1-9])|([1-2][0-9])|([3][0-1])))(T((([0-1][0-9])|([2][0-3]))((:([0-5][0-9]))(((:([0-5][0-9]))((\.[0-9]+)?))?)?)?((((\+|-)(([0-1][0-9])|([2][0-3])):[0-5][0-9])|(Z)))?))?)?)?))