Photos: Sequentially Set Date Taken, Digitized, Created and Modified

Lots of apps are super annoying in how they handle photo folders, not letting us sort photos in an album by name, but only using metadata such as date taken. Google Photos is an example.

Would someone know of an existing script which, when many pictures are selected, allow you to set an initial "Date Taken" date, and sequentially increment that date to all the selected pictures, adding, say, one minute or day to each picture? Searched but couldn't locate.

This script does that, starting with the current date and adding one day per file.

// https://resource.dopus.com/t/photos-sequentially-set-date-taken-digitized-created-and-modified/43090

// 2022-12-08

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var tab = clickData.func.sourcetab;
    cmd.deselect = false;

    var currDate = DOpus.Create().Date();

    for (var e = new Enumerator(tab.selected_files); !e.atEnd(); e.moveNext()) {
        var item = e.item();
        var str = currDate.Format('D#yyyy-MM-dd T#HH:mm:ss');
        cmd.RunCommand('SetAttr FILE="' + item + '" META "createdate:' + str + '" "datedigitized:' + str + '" "datetaken:' + str + '" "lastmodifieddate:' + str + '"');
        currDate.Add(1, 'd');
    }
}
Button as XML
<?xml version="1.0"?>
<button backcol="none" display="both" label_pos="right" textcol="none">
	<label>43090</label>
	<icon1>#newcommand</icon1>
	<function type="script">
		<instruction>@script JScript</instruction>
		<instruction>// https://resource.dopus.com/t/photos-sequentially-set-date-taken-digitized-created-and-modified/43090</instruction>
		<instruction />
		<instruction>// 2022-12-08</instruction>
		<instruction />
		<instruction>function OnClick(clickData) {</instruction>
		<instruction>    var cmd = clickData.func.command;</instruction>
		<instruction>    var tab = clickData.func.sourcetab;</instruction>
		<instruction>    cmd.deselect = false;</instruction>
		<instruction />
		<instruction>    var currDate = DOpus.Create().Date();</instruction>
		<instruction />
		<instruction>    for (var e = new Enumerator(tab.selected_files); !e.atEnd(); e.moveNext()) {</instruction>
		<instruction>        var item = e.item();</instruction>
		<instruction>        var str = currDate.Format(&apos;D#yyyy-MM-dd T#HH:mm:ss&apos;);</instruction>
		<instruction>        cmd.RunCommand(&apos;SetAttr FILE=&quot;&apos; + item + &apos;&quot; META &quot;createdate:&apos; + str + &apos;&quot; &quot;datedigitized:&apos; + str + &apos;&quot; &quot;datetaken:&apos; + str + &apos;&quot; &quot;lastmodifieddate:&apos; + str + &apos;&quot;&apos;);</instruction>
		<instruction>        currDate.Add(1, &apos;d&apos;);</instruction>
		<instruction>    }</instruction>
		<instruction>}</instruction>
	</function>
</button>
4 Likes

Do you want to set the 'Date Taken' like that for adding dates to scanned photos? I do that with a plugin for Lightroom Classic, and now thanks to @lxp I can do that in DOpus! Yay!
Almost all applications for viewing and enjoying photos sort by 'Date Taken' by default because typical filenames (like IMG_1234.jpg) offer not value.
In order to always be able to view by date OR filename, I recommend renaming files starting with the 'Date Taken' in the format YYYY-MM-DD. By doing that, the files will sort the same way when sorted by filename or 'Date Taken'.

Thank you so much! Works perfectly!
:smile: :+1:

Really pleased to have that, thank you for doing the hard work.

Here's a version of your script that uses the first file's date as a baseline instead of the current date and adds one minute.

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var tab = clickData.func.sourcetab;
    cmd.deselect = false;

    // var currDate = DOpus.Create().Date();
	var first_item = true;
    for (var e = new Enumerator(tab.selected_files); !e.atEnd(); e.moveNext()) {
        var item = e.item();
        if (first_item) {
    		first_item = false;
    		var currDate = item.metadata.image.datetaken;    
        }
        var str = currDate.Format('D#yyyy-MM-dd T#HH:mm:ss');
        cmd.RunCommand('SetAttr FILE="' + item + '" META "createdate:' + str + '" "datedigitized:' + str + '" "datetaken:' + str + '" "lastmodifieddate:' + str + '"');
        currDate.Add(1, 'm');
    }
}
3 Likes

Hello, Why date taken and date digitized stays untouched for me? it only changes created and modified dates.

Which types are involved? Metadata is read-only for most/all raw digital camera formats, and the dates are not supported in BMP images, as a couple of examples.

1 Like

May be, that's the key! I can't change .CR2 files, but with .JPG meta it changes good

I'm trying to modify the @lpx code so that the user interactively specifies the new date, but it doesn't work?!?

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var tab = clickData.func.sourcetab;
    cmd.deselect = false;

	var date = getString("Enter date:");
	if (!date) {
		return;
	}

    for (var e = new Enumerator(tab.selected_files); !e.atEnd(); e.moveNext()) {
        var item = e.item();
        var str = date.Format('D#yyyy-MM-dd T#HH:mm:ss');
        cmd.RunCommand('SetAttr FILE="' + item + '" META "createdate:' + str + '" "datedigitized:' + str + '" "datetaken:' + str + '" "lastmodifieddate:' + str + '"');
        currDate.Add(1, 'm');
    }
}

“It doesn’t work” isn’t very specific. From a glance at the code, it’s calling a global getString function, which (AFAIK) doesn’t exist and presumably results in an error when the script is run.

Opus scripts can use the Dialog object to prompt the user to type in a string.

Gracias @Leo, voy a estudiar sobre el objeto Dialog.

Hi @bytespiller, could you help me one more time, please?

Believe it or not, you already have the solution for both this problem and another one hiding after that.

Details
  1. What Leo explained: your function getString is undefined, you need to reference it from its origin like so:
    var date = clickData.func.Dlg.getString("Enter date:");
  2. Bonus problem waiting for you: after the user-cancel check (if (!date) return which you already have), but before the for loop you need to convert the string date to an Opus' Date object, so you need this:
    date = DOpus.Create().Date(date); (otherwise the date.Format call you have below would fail).

Thank you @bytespiller a thousand times, you not only solved my problem, you also taught me! Thanks also to @lxp for creating the original code.

The final code is the following:

function OnClick(clickData) {
    var cmd = clickData.func.command;
    var tab = clickData.func.sourcetab;
    cmd.deselect = false;

	var date = clickData.func.Dlg.getString("Enter date:");
	if (!date) {
		return;
	}

	date = DOpus.Create().Date(date);

    for (var e = new Enumerator(tab.selected_files); !e.atEnd(); e.moveNext()) {
        var item = e.item();
        var str = date.Format('D#yyyy-MM-dd T#HH:mm:ss');
        cmd.RunCommand('SetAttr FILE="' + item + '" META "createdate:' + str + '" "datedigitized:' + str + '" "datetaken:' + str + '" "lastmodifieddate:' + str + '"');
        date.Add(1, 'm');
    }
}