I should start by saying I don't think an onChange/onEdit solution is what you are looking for as I'm assuming you are dynamically importing data which might not necessarily trigger an event. I will however answer your question and then show another way of doing this.
Looking at the Google Apps Script documentation for Events you will see that edit events can return 4 parameters: user
(owner of Sheet), source
(which Sheet), range
(where in Sheet) and value
. The range
in particular is useful because it lets us know where the edit has taken place (here is more on Range Class). It is also worth noting that this information is not returned in Change Event which has broader scope.
It is also worth pointing out that triggers can be set from the Script editor Resources menu or programmatically (see Using Container-Specific Installable Triggers) as you've done in your question. Generally I set trigger events from the Resources menu as I'm often the only user. Sticking with the programmatic route your script could be expressed as (note there is a 2-3 sec delay updating after onEdit events):
function onChange() {
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("fixDate")
.forSpreadsheet(sheet)
.onChange()
.create();
}
function fixDate(e) {
e.range.setValue(formatDate(e.value)); // set value based on formating existing value
}
function formatDate(aDate){
var regexp = /([a-zA-Z]{3,4}) ([a-zA-Z]{3}) (\d{2}) (\d{2,4}) (\d{2}:\d{2}:\d{2}\s[A-Z]{3}).*$/; // RegEx to match date format
return aDate.replace(regexp, "$1, $3 $2 $4 $5"); // return modified date as string
}
To use this you'd run the onChange
function once to add the trigger. After this every time there is an edit in the spreadsheet the e
parameter which contains the range, value information is used to get and set the edited value. This script will run regardless of the column being edited. You could extend this to check which column is being edited anf only affect column D and F by replacing fixDate with:
function fixDate(e) {
var col = e.range.getColumn(); // returns int https://developers.google.com/apps-script/reference/spreadsheet/range#getColumn()
if (col === 4 || col === 6){ // 4 = D, = F
e.range.setValue(formatDate(e.value)); // set value based on formating existing value
}
}
For the formatDate
function I'm using a Regular Expression to match parts of the string like dayofweek, month, day etc. returning in you desired format using String.replace(). This is more reliable than splitting on spaces as it looks for a pattern. This means that once a date has been edited it won't be reformatted again because the pattern won't match.
Using built-in formula instead
In the example above we have used a regular expression to return a string. Google Sheets has an existing functions/formula called REGEXREPLACE. Using the same pattern used in formatDate we can use the formula:
=REGEXREPLACE(D1,"([a-zA-Z]{3,4}) ([a-zA-Z]{3}) (\d{2}) (\d{2,4}) (\d{2}:\d{2}:\d{2}\s[A-Z]{3}).*$", "$1, $3 $2 $4 $5")
this will return a value in cell D1 in the desired format. Note this would have to be in a separate column as you can't have a circular reference. The issue might be that you don't want to copy this formula down an entire column manually, but Google Sheets has another formula which essentially allows applying this to a range of formula using ARRAYFORUMLA. To use this you could for example enter in cell G1:
=ARRAYFORMULA(REGEXREPLACE(D:D,"([a-zA-Z]{3,4}) ([a-zA-Z]{3}) (\d{2}) (\d{2,4}) (\d{2}:\d{2}:\d{2}\s[A-Z]{3}).*$", "$1, $3 $2 $4 $5"))
This will output formatted dates for the entire D:D column.
All the code used in this answer including the sheet formula can be found here (File > Make a copy to see code/formula)