Time and date validator

sbron 2009-06-14 - The new clock scan in Tcl 8.5 is too lenient to be used to check if a string contains a valid time and date. The following proc attempts to do a better job. It returns 1 for a valid time/date and 0 if it is bogus.

Examples:

  • "5:13:52" (%T) => 1
  • "1/2/2003" (%D) => 1
  • "jun 14, 2009" (%b%d,%Y) => 1
  • "feb 29, 2009" (%b%d,%Y) => 0
  • "febr 14, 2009" (%b%d,%Y) => 0
 proc timevalidate {format str} {
     # Start with a simple check: If the string cannot be parsed against
     # the specified format at all it's definitely wrong
     if {[catch {clock scan $str -format $format} time]} {return 0}

     # Create a table for translating the supported clock format specifiers
     # to scan format specifications
     set map {%a %3s %A %s %b %3s %B %s %d %2d %D %2d/%2d/%4d
        %e %2d %g %2d %G %4d %h %s %H %2d %I %2d %j %3d
        %J %d %k %2d %l %2d %m %2d %M %2d %N %2d %p %2s
        %P %2s %s %d %S %2d %t \t %T %2d:%2d:%2d %u %1d
        %V %2d %w %1d %W %2d %y %2d %Y %4d %z %4d %Z %s
     }

     # Build the scan format string out of the clock format string
     set scanfmt [string map $map $format]

     # Recreate the time string from the seconds value
     set tmp [clock format $time -format $format]

     # Scan both versions of the string representation
     set list1 [scan $str $scanfmt]
     set list2 [scan $tmp $scanfmt]

     # Compare all elements as numbers and strings
     foreach n1 $list1 n2 $list2 {
        if {$n1 != $n2 && ![string equal -nocase $n1 $n2]} {return 0}
     }

     # Declare the time string valid since all elements matched
     return 1
 }

EMJ 2017-01-13 : Changed the map for %Y from %2d to %4d - might there be others like this?