--- /dev/null
+#!/usr/bin/perl
+# UCW Gallery: Symlink photos according to their EXIF timestamps
+# (c) 2013 Martin Mares <mj@ucw.cz>
+
+use strict;
+use warnings;
+
+use Image::EXIF;
+use Getopt::Long;
+
+if (@ARGV && $ARGV[0] eq '--help') {
+ die <<AMEN ;
+Usage: cat list | gal date [<options>]
+ or: gal date [<options>] <files>
+
+Options:
+-d, --destdir=<dir> Create symlinks in specified directory (default: current dir)
+-n, --dry-run Perform a trial run with no changes made
+-o, --offset=<offset> Adjust timestamps by a given offset (<h>[:<m>[:<s>]])
+ --suffix=<s> Add suffix to all names
+-s, --symbolic Create symbolic links (default: hardlinks)
+AMEN
+}
+
+my $destdir = '.';
+my $dry_run = 0;
+my $offset = 0;
+my $suffix = "";
+my $symbolic = 0;
+Getopt::Long::Configure('bundling');
+GetOptions(
+ 'destdir|d=s' => \$destdir,
+ 'dry-run|n!' => \$dry_run,
+ 'offset|o=s' => \$offset,
+ 'suffix=s' => \$suffix,
+ 'symbolic|s!' => \$symbolic,
+) or die "Try gal date --help\n";
+
+my @src = @ARGV;
+if (!@src) {
+ while (<STDIN>) {
+ chomp;
+ push @src, $_;
+ }
+}
+
+if ($offset =~ m{^([+-])?(\d)+(:(\d+)(:(\d+))?)?$}) {
+ $offset = $2 * 3600 + ($4 // 0) * 60 + ($6 // 0);
+ if ($1 eq '-') { $offset = -$offset; }
+} else {
+ die "Invalid offset: $offset\n";
+}
+
+foreach my $f (@src) {
+ my $e = new Image::EXIF($f);
+ my $i = $e->get_all_info();
+ if ($e->error) {
+ print STDERR "EXIF error on $f: ", $e->error, "\n";
+ next;
+ }
+ # print STDERR Dumper($i), "\n";
+
+ my $d = $i->{'image'}->{'Image Created'};
+ if (!defined $d) {
+ print STDERR "No date for $f\n";
+ next;
+ }
+ my ($ty, $tm, $td, $tH, $tM, $tS) = ($d =~ m{^(\d{4}):(\d{2}):(\d{2}) (\d{2}):(\d{2}):(\d{2})$}) or die "EXIF date parse error: $d\n";
+ my $t = 3600*$tH + 60*$tM + $tS;
+ $t = int($t + $offset);
+ $tH = int($t / 3600);
+ $tM = int(($t % 3600) / 60);
+ $tS = $t % 60;
+
+ my $retry = 0;
+ my $dest = "";
+ do {
+ $dest = sprintf("%s/%04d-%02d-%02d-%02d:%02d:%02d%s%s.jpg",
+ $destdir,
+ $ty, $tm, $td,
+ $tH, $tM, $tS,
+ $suffix,
+ $retry ? sprintf("-%d", $retry) : "");
+ $retry++;
+ } while (-f $dest);
+
+ print "$f $dest\n";
+
+ unless ($dry_run) {
+ if ($symbolic) {
+ symlink $f, $dest or die "Cannot symlink $f to $dest: $!\n";
+ } else {
+ link $f, $dest or die "Cannot hardlink $f to $dest: $!\n";
+ }
+ }
+}
+
+STDOUT->autoflush(1);