Skip to content

Instantly share code, notes, and snippets.

@nutrino
Last active January 17, 2023 15:43
Show Gist options
  • Save nutrino/95fa1cf2e74574818fe9722a6086058b to your computer and use it in GitHub Desktop.
Save nutrino/95fa1cf2e74574818fe9722a6086058b to your computer and use it in GitHub Desktop.
set image file date from exif data
#!/usr/bin/env python
# https://gist.github.com/ikoblik/7089165
"""A simple utility to restore file creation and modification
dates back to their original values from EXIF.
This script requires exif module to be installed or the exif
command line utility to be in the path.
To function correctly under windows this script needs win32file and
win32con modules. Otherwise it will not be able to restore the creation
date."""
import os, sys, time, re, glob
import os.path
from datetime import datetime, timedelta
from PIL import Image
from PIL.ExifTags import TAGS
TEN_MINUTES = timedelta(minutes=10)
__description = """Restores file's creation and modification dates back to the original
value from EXIF.
usage: exif_date.py [File name mask]"""
def get_exif_timestamp(src) :
ret = {}
exifTimestamp = ''
i = Image.open(src)
try :
info = i._getexif()
if info is None:
import re
m = re.search(r'(\d{4})(\d{2})(\d{2})(?:-|_)(\d{2})(\d{2})(\d{2})', src)
if m is not None and len(m.groups()) == 6:
return '{}:{}:{} {}:{}:{}'.format(m.group(1),m.group(2),m.group(3),m.group(4),m.group(5),m.group(6))
m = re.search(r'(\d{4})-(\d{2})-(\d{2}) (\d{2})\.(\d{2})\.(\d{2})', src)
if m is not None and len(m.groups()) == 6:
return '{}:{}:{} {}:{}:{}'.format(m.group(1),m.group(2),m.group(3),m.group(4),m.group(5),m.group(6))
for tag, value in info.items() :
decoded = TAGS.get(tag, tag)
ret[decoded] = value
if ret.get('DateTimeOriginal') != None :
return ret['DateTimeOriginal']
if ret.get('DateTimeDigitized') != None:
return ret['DateTimeDigitized']
if ret.get('DateTime') != None:
return ret['DateTime']
except Exception as e :
print(e)
return exifTimestamp
def getFileDates(path):
"""Returns a dictionary of file creation (ctime), modification (mtime), exif (exif) dates"""
dates = {}
exif_timestamp = get_exif_timestamp(path)
if exif_timestamp != '':
dates['exif'] = datetime.strptime(exif_timestamp, '%Y:%m:%d %H:%M:%S')
else:
dates['exif'] = None
dates['mtime'] = datetime.utcfromtimestamp(os.path.getmtime(path))
dates['ctime'] = datetime.utcfromtimestamp(os.path.getctime(path))
return dates
def setFileDates(fileName, dates):
"""Sets file modification and creation dates to the specified value"""
os.utime(fileName, (time.mktime(dates['exif'].utctimetuple()),)*2)
def fixFileDate(fileName):
"""Reads file's EXIF header, gets the earliest date and sets it to the file"""
dates = getFileDates(fileName)
if (dates['exif']):
cmp_time = lambda x, y: x - y > TEN_MINUTES
diff = [cmp_time(dates[x], dates['exif']) for x in ('mtime', 'ctime')]
if(sum(diff)):
setFileDates(fileName, dates)
return dates, diff
else:
return dates, None
def main(args):
if (not len(args)):
return - 1
processedFiles = []
for fileNameMask in args:
if "*" in fileNameMask or "?" in fileNameMask:
print("Looking for files with mask " + fileNameMask)
for fileName in filter(lambda x: x not in processedFiles, glob.glob(fileNameMask)):
processedFiles.append(fileName)
print(fileName + ' - ')
try:
dates, diff = fixFileDate(fileName)
except Exception as e:
print(e)
diff = None
if (not diff):
print('SKIP, NO EXIF')
else:
if (sum(diff) != 0):
print('SET TO "%s" (updated M:%d, C:%d)' % (dates['exif'].strftime('%Y:%m:%d %H:%M:%S'), diff[0], diff[1]))
else:
print('OK')
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment