File Coverage

blib/lib/Image/EXIF/DateTime/Parser.pm
Criterion Covered Total %
statement 30 30 100.0
branch 5 6 83.3
condition 1 3 33.3
subroutine 7 7 100.0
pod 2 2 100.0
total 45 48 93.7


line stmt bran cond sub pod time code
1             # Copyright 2009 Marcin Owsiany
2             # See the README file for license information
3             package Image::EXIF::DateTime::Parser;
4 1     1   33038 use strict;
  1         3  
  1         33  
5 1     1   6 use warnings;
  1         2  
  1         31  
6 1     1   6 use Carp;
  1         5  
  1         70  
7 1     1   6 use POSIX;
  1         2  
  1         6  
8 1     1   2361 use vars '$VERSION';
  1         2  
  1         434  
9             $VERSION = '1.2';
10              
11             =head1 NAME
12              
13             Image::EXIF::DateTime::Parser - parser for EXIF date/time strings
14              
15             =head1 SYNOPSIS
16              
17             use Image::EXIF::DateTime::Parser;
18              
19             my $parser = Image::EXIF::DateTime::Parser->new;
20             printf "%d\n", $p->parse("2009:05:05 09:17:37");
21              
22             produces "1241540257", if you are in America/Los_Angeles timezone.
23              
24             =head1 DESCRIPTION
25              
26             While parsing standards-compliant EXIF Date/Time string is easy, allowing for
27             the various ways different non-standards-compliant implementations mangle these
28             strings is neither easy nor pleasant. This module encapsulates this complexity
29             for you. It provides a parser which takes an EXIF Date/Time string and returns
30             time in "calendar time" format, aka. time_t.
31              
32             =head2 EXPORTS
33              
34             Nothing.
35              
36             =head2 METHODS
37              
38             =over
39              
40             =item $p = Image::EXIF::DateTime::Parser->new
41              
42             Returns a new parser object.
43              
44             Introduced in version 1.1.
45              
46             =cut
47              
48             sub new
49             {
50 1     1 1 11 my $that = shift;
51 1   33     6 my $class = ref $that || $that;
52 1         2 my $self = {};
53 1         4 bless $self, $class;
54             }
55              
56             =item $time_t = $p->parse( '2009:05:05 09:17:37' )
57              
58             Takes a single argument: an EXIF Date/Time string, and returns a time_t value
59             by interpreting the string as local time.
60              
61             Returns undef when the string represents an unknown date/time (zeros or blanks).
62              
63             Throws an exception if the string is not parseable.
64              
65             Introduced in version 1.1.
66              
67             =cut
68              
69             sub parse
70             {
71 10     10 1 2781 my $self = shift;
72 10         12 my $string = shift;
73 10 100       51 if ($string =~ /^([\d\x20]{4})(.)([\d\x20]{2})(.)([\d\x20]{2})(.)([\d\x20]{2})(.)([\d\x20]{2})(.)([\d\x20]{2})([-+]\d{2}:\d{2}|[.]\d{2}Z|.)?$/)
74             {
75 9         29 my ($y, $m, $d, $H, $M, $S) = ($1, $3, $5, $7, $9, $11);
76 9         27 my @colons = ($2, $4, $8, $10);
77 9         13 my @space = $6;
78             # if all fields were whitespace-only or zeroes, it means that time is unknown
79 9 100       11 return undef unless grep { ! /^( |0)+$/ } ($y, $m, $d, $H, $M, $S);
  54         130  
80 7         395 my $time = POSIX::mktime($S, $M, $H, $d, $m-1, $y-1900, 0, 0, -1);
81 7 50       330 return $time if defined $time;
82             # falls through on mktime() error
83             }
84 1         23 croak "Unrecognized invalid string [$string].\n";
85             }
86              
87             =head1 SECURITY
88              
89             The module untaints the input string and passes the numbers (and spaces in some
90             cases) as arguments to POSIX::mktime. Thus as long as mktime can deal with
91             numbers and/or spaces on its input, the worst that can happen is that an
92             invalid date/time string will produce a surprising calendar time value or an
93             undef.
94              
95             =head1 CAVEATS
96              
97             =head2 Non-canonical time strings
98              
99             Because it uses POSIX::mktime, this module can accept theoretically invalid
100             field values (such as 32nd day of month) and canonicalize them by appropriately
101             changing other field values.
102              
103             =head2 Timezones
104              
105             The parser currently ignores the timezone information and treats the string as
106             date/time in the timezone it currently runs in. Please note that the EXIF
107             standard actually forbids including timezone information the Date/Time string.
108              
109             =head2 Invalid formats
110              
111             This module tries to understand some common non-standards-compliant EXIF
112             Date/Time strings, but naturally it is not possible to allow for all present
113             and future ways that implementations can choose to mangle them. If you
114             encounter a string that is not recognized, but could be, please report it and I
115             will try to add it in the next version.
116              
117             =head1 AUTHOR
118              
119             Marcin Owsiany
120              
121             =head1 SEE ALSO
122              
123             Image::Info(3), Image::ExifTool(3)
124              
125             =head1 LICENSE
126              
127             This program is free software; you can redistribute it and/or modify it under
128             the terms of the GNU General Public License as published by the Free Software
129             Foundation; either version 2 of the License, or (at your option) any later
130             version.
131              
132             =cut
133              
134             1;