Commit cfe8b815 authored by Dave Morriss's avatar Dave Morriss

Added 'parse_8601_duration'

A script to parse an ISO8601 duration expression
parent 7a88a143
#!/usr/bin/perl
#===============================================================================
#
# FILE: parse_8601_duration
#
# USAGE: ./parse_8601_duration [duration_expression...]
#
# DESCRIPTION: Parses an ISO_801 time duration to extract the relevant
# fields. Note that it is fairly simplistic and does not
# validate the duration expression very rigorously. For example
# 'P0YT' is invalid yet is accepted by the parser. However,
# 'P0Y2H' is rejected.
#
# OPTIONS: ---
# REQUIREMENTS: ---
# BUGS: ---
# NOTES: This format can represent a number of months but contains no
# means whereby these months can be resolved to days.
# There's also some controversy about whether fields other than
# seconds can be fractional. 'P0.5Y' seems like a good way to
# represent half a year (though how many days it represents is
# open to question). This script does not allow this.
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
# VERSION: 1.0
# CREATED: 04/07/2013 17:20:09
# REVISION: 05/07/2013 15:55:25
#
#===============================================================================
use 5.010;
use strict;
use warnings;
my $duration;
my @labels = (qw{Years Months Days Hours Minutes Seconds});
my @fields;
my %iso_duration;
#
# Regular expressions for an integer and a decimal fraction
#
my $int = qr{\d+};
my $frac = qr{[0-9]+(?:\.[0-9]+)?};
#
# Regular expression for the ISO 8601 duration. Uses Perl's extensions where
# (?:) is a non-capturing sub-expression and (?x) is the same as //x in the
# simpler form. Only the 'P' is mandatory. The other numeric elements all
# need their designators.
#
my $re = qr{(?x) # Enable embedded whitespace and comments
^P # Assume the string begins with P
(?:($int)Y)? # Years
(?:($int)M)? # Months
(?:($int)D)? # Days
(?:T # The 'T' must exist if there's a time element
(?:($int)H)? # Hours
(?:($int)M)? # Minutes
(?:($frac)S)? # Seconds
)? # The time element's optional
$}; # Assume there's nothing after the duration string
#
# Loop through the arguments
#
while ( $duration = shift ) {
print "$duration\n";
if ( @fields = ( $duration =~ $re ) ) {
#
# Force all undefined fields to be zero
#
@fields = map { ( defined($_) ? $_ : 0 ) } @fields;
#
# Build a duration hash (just to show how to do it in a cool Perly way)
#
@iso_duration{@labels} = @fields;
#
# Display the fields in the right order
#
for ( my $i = 0; $i <= $#fields; $i++ ) {
printf "%-7s: %6.2f\n", $labels[$i], $fields[$i];
}
}
else {
#
# The expression didn't match the regex
#
print "Invalid duration: $duration\n";
}
print "\n";
}
exit;
# vim: syntax=perl:ts=8:sw=4:et:ai:tw=78:fo=tcrqn21:fdm=marker
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment