Skip to content

Instantly share code, notes, and snippets.

@huntfx
Created August 11, 2019 15:23
Show Gist options
  • Save huntfx/37db342a8b8e98bd6870fc8751fa1ab7 to your computer and use it in GitHub Desktop.
Save huntfx/37db342a8b8e98bd6870fc8751fa1ab7 to your computer and use it in GitHub Desktop.
Figure out the date an image was created, and set the created/modified time to match. Run the Python file from inside a folder to apply to all images.
import os
import time
from contextlib import suppress
if os.name == 'nt':
from ctypes import windll, wintypes, byref
def set_creation_time(path, timestamp):
"""Set the creation time of files in Windows.
Source: https://stackoverflow.com/a/56805533/2403000
"""
timestamp = int((timestamp * 10000000) + 116444736000000000)
ctime = wintypes.FILETIME(timestamp & 0xFFFFFFFF, timestamp >> 32)
handle = windll.kernel32.CreateFileW(path, 256, 0, None, 3, 128, None)
windll.kernel32.SetFileTime(handle, byref(ctime), None, None)
windll.kernel32.CloseHandle(handle)
else:
set_creation_time = lambda path, timestamp: None
def str_to_timestamp(string, time_format):
return time.mktime(time.strptime(string, time_format))
def get_timestamp_from_filename(filename):
"""Calculate the timestamp of a file based on its name.
If it is unable to calculate, None will be returned.
"""
filename_len = len(filename)
filename_prefix = filename.split('_', 1)[0]
# 20120401_165412 (Android)
if filename_len == 15 and filename[:4].isdigit():
with suppress(ValueError):
return str_to_timestamp(filename, '%Y%m%d_%H%M%S')
if filename_len == 16:
# 20190209184635_1 (Steam)
if filename[-2] == '_' and filename[:-2].isdigit() and filename[-1].isdigit():
with suppress(ValueError):
return str_to_timestamp(filename[:-1], '%Y%m%d%H%M%S_')
# 2015-01-29_00002 (Steam)
elif filename[:4].isdigit() and filename[-5:].isdigit():
return str_to_timestamp(filename[:-5], '%Y-%m-%d_')
# For Honor2018-8-29-0-3-48 (UPlay)
if filename_len > 18:
dash_split = filename.rsplit('-', 5)
if len(dash_split) == 6:
date_string = dash_split[0][-4:] + '-' + '-'.join(dash_split[1:])
if date_string.count('-') == 5 and '_' not in date_string:
with suppress(ValueError):
return str_to_timestamp(date_string, '%Y-%m-%d-%H-%M-%S')
# IMG_20160803_175206 (Instagram)
if filename_len == 19 and filename_prefix == 'IMG':
with suppress(ValueError):
return str_to_timestamp(filename, 'IMG_%Y%m%d_%H%M%S')
# FaceApp_1492541591338 (FaceApp)
if filename_len == 21 and filename_prefix == 'FaceApp':
with suppress(ValueError):
return int(filename[8:]) / 1000
if filename_len == 23:
if filename_prefix == 'IMG':
# IMG_20161224_134354_765 (Instagram)
if filename[12] == filename[19] == '_':
with suppress(ValueError):
return str_to_timestamp(filename[:-4], 'IMG_%Y%m%d_%H%M%S')
# IMG_2016-07-09-15295765 (Pokemon Go)
if filename[8] == filename[11] == filename[14] == '-':
with suppress(ValueError):
return str_to_timestamp(filename, 'IMG_%Y-%m-%d-%H%M%S%f')
# 2016-09-27 13-49-41.513 (Lifecam)
if filename[:4].isdigit() and filename[10] == ' ' and filename[19] == '.':
with suppress(ValueError):
return str_to_timestamp(filename, '%Y-%m-%d %H-%M-%S.%f')
# Screenshot_20181104-153209 (Android)
if filename_len == 26 and filename_prefix == 'Screenshot':
with suppress(ValueError):
return str_to_timestamp(filename, 'Screenshot_%Y%m%d-%H%M%S')
# Screenshot_2016-03-19-15-21-29 (Android)
if filename_len == 30 and filename_prefix == 'Screenshot':
with suppress(ValueError):
return str_to_timestamp(filename, 'Screenshot_%Y-%m-%d-%H-%M-%S')
# HighResScreenShot_2015-12-06_14-12-26 (Elite Dangerous)
if filename_len == 37 and filename_prefix == 'HighResScreenShot':
with suppress(ValueError):
return str_to_timestamp(filename, 'HighResScreenShot_%Y-%m-%d_%H-%M-%S')
# 2013-05-19 12.03.16 252886351658901753_8111220388 (4K Stogram)
if filename_len >= 49 and filename[:4].isdigit() and filename[10] == filename[19] == ' ':
with suppress(ValueError):
return str_to_timestamp(filename[:19], '%Y-%m-%d %H.%M.%s')
return None
def edit_time(path, modified=None, created=None, access=None):
"""Edit the times of a file."""
if modified is not None or access is not None:
if modified is None:
modified = os.stat(path).st_mtime
if access is None:
access = os.stat(path).st_atime
os.utime(path, (access, modified))
if created is not None:
set_creation_time(path, created)
def edit_file(path, access_time=None):
"""Parse a filename and set the time created/modified."""
path = os.path.normpath(path)
timestamp = get_timestamp_from_filename(path.rsplit(os.path.sep, 1)[-1].rsplit('.', 1)[0])
if timestamp is None:
print('Failed to update {}'.format(path))
return None
if access_time is None:
access_time = time.time()
edit_time(path, modified=timestamp, created=timestamp, access=access_time)
print('Updated {}'.format(path))
return timestamp
def edit_folder(path):
"""Parse and set time created/modified for all files within a folder."""
count = 0
for root, dirs, files in os.walk(path):
for file in files:
file_path = os.path.join(root, file)
if edit_file(file_path):
count += 1
return count
if __name__ == '__main__':
count = edit_folder(os.path.abspath(__file__).rsplit(os.path.sep, 1)[0])
print('Number of files updated: {}'.format(count))
input('Press enter to exit...')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment