Python code to change modified date for xlsx and docx files

 
import os
import sys
import tkinter as tk
from tkinter import filedialog
from datetime import datetime
from docx import Document
from openpyxl import load_workbook
from openpyxl.workbook.properties import WorkbookProperties

# -------------------------------
# Platform-specific creation time
# -------------------------------
def set_file_creation_time(filepath, created_dt):
    """
    Set file creation time (birth time).
    - Linux/macOS: uses os.utime with ns (nanoseconds)
    - Windows: NOT SUPPORTED by Python/os — will skip with warning
    """
    if sys.platform == "win32":
        print("Warning: Changing 'Created' time is NOT supported on Windows via Python.")
        print("     Use third-party tools like 'SetFileTime' or PowerShell if needed.")
        return False

    # Only for macOS and Linux
    try:
        # Convert to timestamp
        timestamp = created_dt.timestamp()
        atime = os.stat(filepath).st_atime  # keep access time
        mtime = timestamp

        # Use nanosecond version if available
        try:
            os.utime(filepath, ns=(int(atime * 1e9), int(mtime * 1e9)))
            return True
        except AttributeError:
            # Fallback to seconds
            os.utime(filepath, (atime, mtime))
            return True
    except Exception as e:
        print(f"Failed to set creation time: {e}")
        return False

# -------------------------------
# Helper Functions
# -------------------------------
def select_file():
    root = tk.Tk()
    root.withdraw()
    file_path = filedialog.askopenfilename(
        title="Select .docx or .xlsx file",
        filetypes=[("Word and Excel files", "*.docx *.xlsx"), ("All files", "*.*")]
    )
    return file_path

def parse_datetime(prompt):
    while True:
        dt_str = input(prompt).strip()
        try:
            return datetime.strptime(dt_str, "%Y-%m-%d %H:%M:%S")
        except ValueError:
            print("Invalid format. Use: YYYY-MM-DD HH:MM:SS (e.g., 2025-04-01 14:30:00)")

def change_docx_metadata(file_path, created_dt, modified_dt):
    doc = Document(file_path)
    
    # FIXED: Use 'core_properties' (with underscore)
    props = doc.core_properties
    
    # Set modified (always available)
    props.modified = modified_dt
    
    # Set created (fallback if not directly settable)
    if hasattr(props, 'created'):
        props.created = created_dt
    else:
        # Fallback: Manually update the XML in the docx zip
        from docx.oxml import OxmlElement
        from docx.oxml.ns import qn
        cp = props._element
        created_el = OxmlElement(qn('dc:created'))
        created_el.set(qn('xsi:type'), 'dcterms:W3CDTF')
        created_el.text = created_dt.isoformat()
        cp.insert(0, created_el)  # Insert at beginning

    doc.save(file_path)

def change_xlsx_metadata(file_path, created_dt, modified_dt):
    wb = load_workbook(file_path)
    
    # Ensure properties object exists
    if not hasattr(wb, 'properties') or wb.properties is None:
        wb.properties = WorkbookProperties()

    wb.properties.created = created_dt
    wb.properties.modified = modified_dt

    wb.save(file_path)

def change_filesystem_timestamps(file_path, created_dt, modified_dt):
    modified_ts = modified_dt.timestamp()

    # Always set modified time
    try:
        os.utime(file_path, (modified_ts, modified_ts))
        print(f"File system 'Modified' time set to: {modified_dt.strftime('%Y-%m-%d %H:%M:%S')}")
    except Exception as e:
        print(f"Failed to set modified time: {e}")

    # Try to set creation time (macOS/Linux only)
    if created_dt != modified_dt:
        success = set_file_creation_time(file_path, created_dt)
        if success:
            print(f"File system 'Created' time set to: {created_dt.strftime('%Y-%m-%d %H:%M:%S')}")
    else:
        print("Created and Modified times are the same — skipping creation time change.")

# -------------------------------
# Main
# -------------------------------
def main():
    print("Select a .docx or .xlsx file...")
    file_path = select_file()
    
    if not file_path:
        print("No file selected.")
        return
    
    ext = os.path.splitext(file_path)[1].lower()
    if ext not in ['.docx', '.xlsx']:
        print("Error: Please select a .docx or .xlsx file.")
        return

    print("\nEnter timestamps in format: YYYY-MM-DD HH:MM:SS")
    created_dt = parse_datetime("Enter CREATED date & time: ")
    modified_dt = parse_datetime("Enter MODIFIED date & time: ")

    print(f"\nApplying changes to: {os.path.basename(file_path)}")
    print(f"  Created  → {created_dt}")
    print(f"  Modified → {modified_dt}")

    # 1. Update internal metadata
    try:
        if ext == '.docx':
            change_docx_metadata(file_path, created_dt, modified_dt)
            print("Internal .docx metadata updated (Created & Modified).")
        elif ext == '.xlsx':
            change_xlsx_metadata(file_path, created_dt, modified_dt)
            print("Internal .xlsx metadata updated (Created & Modified).")
    except Exception as e:
        print(f"Failed to update internal metadata: {e}")
        return

    # 2. Update file system timestamps
    change_filesystem_timestamps(file_path, created_dt, modified_dt)

    print("\nAll changes completed successfully!")

if __name__ == "__main__":
    main()