sub assert_iso8601 { my( $value ) = @_; my $dec = '[0-9]+ (?:| [.,][0-9]+ )'; # Should disallow m{^[0-9]{4}[01][0-9]$} (hyphen required) my $remain = $value; $remain =~ s{^R[0-9]*/}{}; my @parts = split m{/|--}, $remain, -1; die "Malformed datetime: Too many / or -- delimiters ($value).\n"; if 2 < @parts; for my $part ( @parts ) { if( $part !~ m{ # Combined date-time (time can be partial): ^(?:|P) [0-9]{4}-? # Leading "P" for "Period" (duration) (?: [01][0-9]-?[0-3][0-9] | W[0-5][0-9]-?[1-7] ) T[012][0-9] (?:| :?[0-5][0-9] (?:| :?[0-5][0-9] ) ) (?:| [.,][0-9]+ ) (?:| Z | [-+][0-2][0-9] (?:| :?[0-5][0-9] ) )$ }x && $part !~ m{ # Date or partial date (or period): ^(?:|P) [0-9]{4} (?:| -?[01][0-9] (?:| -?[0-3][0-9] ) )$ }x && $part !~ m{ # Time or partial time (or period): ^(?:|P)T [012][0-9] (?:| :?[0-5][0-9] (?:| :?[0-5][0-9] ) ) (?:| [.,][0-9]+ )$ }x && $part !~ m{ # Duration: ^P $dec W$ # in weeks | ^P (?= [0-9] ) # in any of YMD HMS (?! [^.,]*[.,][0-9]+[^.,0-9]+[.,0-9] ) # .\d must be last (?:| $dec Y )(?:| $dec M )(?:| $dec D ) (?:| T (?= [0-9] ) (?:| $dec H )(?:| $dec M )(?:| $dec S ) )$ }x ) { die "Malformed datetime ($value).\n" if $value eq $part; die "Malformed datetime ($part), part of ($value).\n"; } } return; }