Filename parsed to date?

Started by okayphoto, June 14, 2010, 04:38:18 AM

Previous topic - Next topic

okayphoto

Hello -

Exiftool just plan rocks.  I want to try something my google-fu can't seem to help with but would seem to be not completely rare.  I have scans of film negatives as TIFFs, and their filenames begin with the date the photo was taken in YYMMDD form.  (Then there is a roll and frame number.)  I would love to be able to add a DateTime (create date, DateTimeOriginal, etc whichenver) exif entry to the TIFFs based on the those first six characters of the filename.  Anyone know of any way to do that?

Thanks.

Phil Harvey

This is a bit tricky because ExifTool expects date/time values in the form "YYYY:MM:DD hh:mm:ss".  The biggest problem is the 4-digit year, but with a bit of -if magic, we can get around this with 2 commands:

exiftool -if "$filename lt '70'" "-datetimeoriginal<20$filename 00:00:00" DIR
exiftool -if "$filename ge '70'" "-datetimeoriginal<19$filename 00:00:00" DIR


(Note: If you are on Mac or Linux, swap all single for double quotes in these commands.)

Here I tacked "00:00:00" on the end of the date/time string because ExifTool expects a time, and will skip over any garbage in between.  The only problem is if the rest of the filename contains numbers, because then they may be interpreted as part of the time, giving you random time values.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

Phil Harvey

Oops.  I just re-read your post.  The rest of the filename contains numbers, which won't be pretty because it will mess up the time values.  So the best solution here is a user-defined tag to reformat the filename appropriately:


%Image::ExifTool::UserDefined = (
    'Image::ExifTool::Composite' => {
        MyDateTime => {
            Require => 'FileName',
            ValueConv => q[
                return undef unless $val =~ /^(\d{6})/;
                return $1 lt '70' ? "20$1 000000" : "19$1 000000";
            ],
        },
    },
);
1; #end


and as a bonus, we can now do this with a single command:

exiftool "-datetimeoriginal<mydatetime" DIR

See the sample config file for details about how to activate this config file.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

okayphoto

Thank you Phil!

I think my poor brain (which only speaks some rusty PHP and perhaps a tiny bit of mid-80s Basic and Logo) can actually sort of follow that.  Two questions for you if you don't mind:

In your first example (I'll try the second, but just for my own understanding), the filenames are always six digits, then a letter, then almost always n-nn format digits.  Will that seventh character always being a letter cause it to not try to incorrectly parse those few digits as a time?

In your second example, I see you've got the time listed as 000000 - I presume I put in whatever fake time I like - but in your first example they're formatted with colons.  Do I need to format that or will it figure it out?

Thanks!

Phil Harvey

#4
ExifTool is pretty lenient about the input date/time formatting.  The way it parses the date/time is to take the first 4-digit number as the year, then 2-digit numbers for the month, day, hour, minute and second.  These numbers may be separated by anything (except other 2-digit numbers), or nothing at all.  This allows a variety of formats to be accepted.

I don't think I have mentioned this feature anywhere in the documentation, but it certainly comes in handy at times.  (especially when copying date/time values which are formatted differently)

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

okayphoto

An update for anyone following along at home:

Phil's first example did indeed try to parse the frame numbers as times; not a huge deal for me, but might be for some.

The user-defined tag worked great.  I am on a Mac, so I did have to swap some of the ' and " around, and cut and paste from the forum got weird junk invisible characters instead of tabs, so if you get an error, that might be it.  But the code is flawless.

I couldn't figure out how to use -config to run an arbitrary config location, so I went ahead with one in my home directory, and was perfect.

Thanks!


Phil Harvey

#6
Thanks for the update.  I'm on a Mac and I get weird invisible characters when I cut from the forum too. :(  They are non-breaking spaces.  I'm not sure why these occur, but I'm glad you figured it out.

The -config option might not have worked for 3 reasons:

1) If you were using an old version of exiftool.

2) If it wasn't the first option on the command line.

3) If the file or directory specification wasn't right.  (It should be something like -config "/Users/phil/subdirectory/configFileName".  The quotes are necessary if any there are any spaces in the directory names.  The "pwd" command may be useful to display the current path.)

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

okayphoto

I'm a PHP guy and I find errors are caused by: 5% I'm stupid, 5% weird invisible characters, and 90% forgotten semicolons.  In this case, with stupidity a given and it not being PHP, I instantly looked for weird invisible characters.

3) is right; I didn't specify the directory correctly.  Thanks, for next time.

Here's a question.  Based on your sample, I wrote up a version to handle another batch of images that were taken with an old cell phone that named files with the date and time in the name, but no EXIF info at all.  So I did this:
%Image::ExifTool::UserDefined = (
'Image::ExifTool::Composite' => {
MyDateTime2 => {
Require => 'FileName',
ValueConv => q[
return undef unless $val =~ /^(\d{6})p-*(\d{4})/;
return $1 lt '70' ? "20$1 $2" : "19$1 $2";
],
},
},
);
1; #end


It worked great, turning YYMMDDp-HHMM into the proper format; your leniency with the time format is much appreciated!  1300 images, zero errors.  Afterwards, I got to wondering about that 'return $1 part' - should I have done something to also return $2?  I know so little about Perl I don't even know how I'd Google that.  I know it worked, but was curious if it worked from dumb luck, or if I actually did something correctly for once.

Phil Harvey

What you did with the $2 in your example was correct.  Good guess.  $1, $2, $3, etc return the strings which matched the patterns inside the brackets of the regular expressions.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).