I post the occasional script on here in the vague hope it will help someone sometime but suspect a lot of them are too specialist (in terms of being rather specifically related to my journal records in DEVONThink). However, this week I had a fairly intense scripting session trying to work out how to convert a name of a record like:
Wednesday 13 October 2021.md
into a date AppleScript would recognise.
Stripping the extension is easy (look for past help with that on the forum from @Bluefrog ) but here’s the handler I devised for what I (at least) regard as the heavy lifting—actual conversion of a long text date to an actual AppleScript date.
Just invoke it with something like set theLongDate to my formatDate(theLongDateText).
on formatDate(LongDateStr)
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to " "
-- break the text date down into its individual components using a space
set the nameComponents to (text items of LongDateStr)
-- item 1 is the day of the week so we ignore that
-- item 2 is a text number so that's easy to convert to an integer
set theDay to item 2 of nameComponents as integer
-- item 3 is the name of the month, which we have to convert to an integer
set theMonth to item 3 of nameComponents as string
set monthList to {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
repeat with i from 1 to the count of monthList
-- here's the number of the month
if item i of monthList is theMonth then set theMonth to i
end repeat
-- item 4 is a text number so that's easy to convert to an integer
set theYear to item 4 of nameComponents as integer
-- assemble from the pieces something that looks like a date
set formattedDateText to theDay & "/" & theMonth & "/" & theYear as string
set AppleScript's text item delimiters to astid
-- set up a real AppleScript date
set theDate to current date
-- set the date using the bits and pieces we've assembled
tell theDate to set {its day, its month, its year} to words of formattedDateText
tell theDate to set {its hours, its minutes, its seconds} to {0, 0, 0}
set formattedDate to theDate
-- breathe a sigh of relief and return a real date
return formattedDate
end formatDate
I’m sure there are better, faster ways, (and have no doubt someone will tell me so) but at least it works!
Edit: I just know you’re going to produce a single line of JavaScript, with a plethora of brackets and incomprehensible actions, that does the same thing!
const s ="Wednesday 13 October 2021";
const longMonths = ["January","February", "March", "April", "May", "June",
"July", "August", "September", "October", "November","December"];
const splitDate = s.split(" "); /* split the date string at blanks and store in an array */
/* get the index of the month in the longMonths array, i.e. a number between 0 and 11.
Add 1 to get the usual month number 1...12
*/
const monthNumber = longMonths.indexOf(splitDate[2])+1;
/* Build a date object from the year, monthNumber and day. They are passed as a string
"yyyy-mm-dd" to the Date constructor.
*/
const myDate = new Date(`${splitDate[3]}-${monthNumber}-${splitDate[1]}`);
console.log(myDate);
Or even better
const s ="Wednesday 13 October 2021";
/* Use a regular expression to weed out the weekday and reformat the rest as
"October 13, 2021 00:00:00" */
const fixedDate = s.replace(/^\w+\W+(\d+)\W+(\w+)\W+(\d+)$/,"$2 $1, $3 00:00:00");
const myDate = new Date(fixedDate);
But (big but): The latter does not really work reliably because it depends on the parsing of a date string (“October 13, 2021”) and this is, according to MDN, browser-dependend. Or more generally implementation-dependend. The above code run in node.js gives me October 12, 2021 at 22:00 – apparently it does something weird with the timezones.
Now, don’t complain about the parenthesis, brackets and stuff – you baited me into it, now you have to suffer the consequences.
However, more significantly, I’m getting different results when using my original handler and the revised handler. The revised handler is this:
on formatDate(LongDateStr)
set {dd, mm, yyyy} to words of (short date string of (date LongDateStr))
return (short date string of (date LongDateStr))
set formattedDate to (dd & "/" & mm & "/" & yyyy)
return formattedDate
end formatDate
If I run both scripts on a record with the name Tuesday 2 March 2021.md my original script correctly populates the custom metadata. The revised handler returns 02/03/2021 (which is obviously correct) but populates the custom metadata with Wednesday 3 February 2021 (clearly reversing the day and month in the process).
My date settings in System Preferences are as follows:
So I’m not quite sure why I’m getting two different results.
the first return statement was left in by mistake after I’d been testing it;
all of that shouldn’t really have been included in the reply to you: I wasn’t really expecting you to deal in detail with AppleScript problems in that context!
I think it’s better if I start a separate thread for something that may possibly be a bug (somewhere, in something!).
I guess this code could be more stable (esp with different localizations):
on formatLongDate from LongDateStr by thisDelimeter
set {saveTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, thisDelimeter}
set {dd, mm, yyyy} to every text item of (short date string of (date LongDateStr))
set AppleScript's text item delimiters to saveTID
set formattedDate to (dd & "/" & mm & "/" & yyyy)
return formattedDate
end formatLongDate