EXIF Date Renamer
Organize your photo directories by automatically renaming them based on the embedded EXIF timestamp from the earliest photo in each folder. This tool ensures consistent, chronological sorting of photo collections, which is especially helpful when managing backups, archives, or importing media from various sources.
Features
- Scans each directory for image files (JPG, JPEG, PNG, TIFF)
- Reads EXIF metadata to extract creation dates
- Determines the earliest photo date in the folder
- Renames the directory to YYYY-MM-DD format based on that date
- Skips directories that already match the naming pattern or lack EXIF data
- Safe mode prevents renaming if conflicts exist
Usage
Run the script from the command line, passing the parent directory containing photo folders:
python exif_date_renamer.py /path/to/photo_parent_dir
The script will process each subdirectory, extract image timestamps, and rename folders accordingly. For example, a folder named DCIM_001 containing photos from January 15, 2023, will be renamed to 2023-01-15.
Requirements
- Python 3.6+
- Pillow library (
pip install Pillow)
Why This Matters
Photo collections often accumulate with arbitrary or device-generated folder names. This utility brings order by using the actual photo timestamps, enabling intuitive sorting and easier navigation. Itβs ideal for digital archivists, photographers, or anyone managing large personal photo libraries.
Notes
- Only modifies directories with at least one valid image with EXIF date
- Preserves original names if EXIF data is missing
- Uses UTC-normalized timestamps to avoid timezone issues
- Skips locked or read-only directories
Always back up your data before batch-renaming.
import os
import argparse
from datetime import datetime
from PIL import Image
from pathlib import Path
def get_image_creation_date(file_path):
try:
with Image.open(file_path) as img:
exif = img.getexif()
if not exif:
return None
# Common EXIF datetime tags
for tag_id in (36867, 36868, 306): # DateTimeOriginal, DateTimeDigitized, DateTime
date_str = exif.get(tag_id)
if date_str:
try:
return datetime.strptime(date_str[:19], '%Y:%m:%d %H:%M:%S')
except ValueError:
continue
except Exception:
pass
return None
def get_earliest_photo_date(folder_path):
image_extensions = {'.jpg', '.jpeg', '.png', '.tiff', '.bmp'}
earliest = None
for file_path in Path(folder_path).iterdir():
if file_path.is_file() and file_path.suffix.lower() in image_extensions:
date = get_image_creation_date(file_path)
if date and (earliest is None or date < earliest):
earliest = date
return earliest
def rename_folder_by_date(folder_path):
folder = Path(folder_path)
if not folder.is_dir():
return False
# Skip if already in YYYY-MM-DD format
if folder.name.match(r'\d{4}-\d{2}-\d{2}'):
print(f"Skipping (already dated): {folder.name}")
return False
earliest_date = get_earliest_photo_date(folder)
if not earliest_date:
print(f"No EXIF date found: {folder.name}")
return False
new_name = earliest_date.strftime('%Y-%m-%d')
new_path = folder.parent / new_name
if new_path.exists():
print(f"Skip: Target folder exists: {new_name}")
return False
try:
folder.rename(new_path)
print(f"Renamed: '{folder.name}' -> '{new_name}'")
return True
except Exception as e:
print(f"Failed to rename '{folder.name}': {e}")
return False
def main():
parser = argparse.ArgumentParser(description='Rename photo directories by earliest EXIF date.')
parser.add_argument('directory', type=str, help='Parent directory containing photo folders')
args = parser.parse_args()
parent = Path(args.directory)
if not parent.is_dir():
print(f"Error: Directory not found: {parent}")
return
for item in parent.iterdir():
if item.is_dir():
rename_folder_by_date(item)
if __name__ == '__main__':
main()
Top comments (0)