Photo Timestamp Adjustment

My wife and I recently returned from a vacation to Glacier National Park in Montana with lots of pictures we had both taken. I wanted to combine our photos so that they would all appear in chronological order for easy review.

Unfortunately, my wife’s camera resets its clock when the batteries are removed. A few days before the trip, she charged the batteries and replaced them, setting the clock to midnight on 01/01/06. My camera keeps its time even when the battery is removed, so the photos have the correct times. To get a chronological listing of all our photos, I needed to set the timestamps of her photos to their correct times. Her camera keeps accurate time from the reset date, so relative to each other, the pictures timestamps are correct. To set the timestamps to the correct times, I needed to apply an offset (the difference between 01/01/06 and the day she replaced the batteries).

I wrote a bash script that reassigns file timestamps to a configurable interval in the future. I found two photos of the same thing, one of mine and one of hers, so that I knew they were taken about the same time. I copied the “Modified” time from the file manager properties dialog of each picture. I pasted the time from her picture into the INPUT_BASE_TIME and the time from my picture into the OUTPUT_BASE_TIME (see script). The times are processed by the “date” command, which can parse many different date formats, so you should be able to specify the date nearly any way you like. Then, I ran this script to correct the timestamps:

#! /bin/bash

# Set this to the time the camera assigned to a picture
INPUT_BASE_TIME="Tue 03 Jan 2006 11:38:24 AM CST"

# Set this to the time the picture was actually taken
OUTPUT_BASE_TIME="Wed 19 Jun 2013 12:22:00 PM CDT"

# Convert the specified times to seconds-since-epoch
in_base=$(date -d "${INPUT_BASE_TIME}" +%s)
out_base=$(date -d "${OUTPUT_BASE_TIME}" +%s)

# Calculate the time offset in seconds
offset=$((out_base - in_base))

# For each file...
for file in $*; do
    # Read the time in seconds of the input file
    time=$(ls -l --time-style=+%s ${file} | awk '{print $6}')

    # Adjust by the offset
    time=$((time + offset))

    # Convert to a date string (so that touch can interpret it)
    time=$(date --date="1970-01-01 ${time} sec GMT")

    # Update the file timestamp
    touch -d "${time}" ${file}

The script updates the timestamps of all files specified on the command line, so I just specify all the files in her directory:

./ wifephotodir/*.jpg

Then I copied all of her photos into the same directory as mine. Her camera uses a different image naming format, so there is no danger of her files overwriting mine with the same name. If two cameras use the same naming, you will want to either avoid this step, or rename one set to be unique. If you’re using “cp” to copy, you’ll want to pass the option to preserve the newly generated timestaps instead of creating all the copies with the current time. I think nautilus and other graphical file managers preserve timestamps by default.

cp --preserve=timestamps wifephotodir/*.jpg photodir/

Lastly, I wanted to rename the photos so that they are in the correct order when listed alphabetically. To do this, I listed them in order by modification date, then copied them to a different directory with an increasing number for the new file name:

for file in $(ls -rt *.JPG); do
    name=$(printf "%03d" $idx).jpg
    cp --preserve=timestamp ${file} finalphotodir/${name}
    idx=$((idx + 1))

Now our photos are all named in order for easy viewing!

This entry was posted in Linux, Scripting. Bookmark the permalink.