Add todays date to end of filename before the extension in set format

Hey all,

This should be an easy one!

I need to add todays date the end of my file names, before the extension.

I need it to be in the format: ddMMMyy. i.e. 17NOV05

I need it to work on a file that is already being worked on in the script, rather than all the files in a folder.

The background is that so far, my script exports an email from entourage, truncates it to first 9 characters, and this is where I want to add the date.

You guys were so great helping me with a previouc issue, so help again would be even more greatly approciated!

Thanks,

Jason

Jason,

Try this for your date and then add it to your file name before the suffix.

set theDate to (current date) - (8 * days)
set dday to day of theDate as text
if length of dday is less than 2 then
	set dday to "0" & dday as text
end if
set mnth to month of theDate as text
set theMnth to text 1 thru 3 of mnth
set yr to year of theDate as text
set theYr to text 3 thru 4 of yr
set myDate to dday & theMnth & theYr as text

PreTech

P.S. You can get rid of the -(8*days). I used that to see how the day of the date would show up if it was a single digit day.

Model: dual 1.8 G5
AppleScript: 2.1 (80)
Browser: Safari 412.5
Operating System: Mac OS X (10.4)

Nice one, PreTech. :slight_smile:

If, like me, you’re a sucker for one-liners - you could even consider running it like this:

tell (current date) to tell (its month as string) & year * 100 + day to set d to text -2 thru -1 & text 1 thru 3 & text -4 thru -3

(I have to slip these things in quietly - before Nigel catches a glimpse of the subject heading.) :wink:

do shell script "date '+%d%b%y'"

This nice short line would result in 17Nov05. If you need the all caps month you could use:

set dateStamp to changeCase(do shell script "date '+%d%b%y'", 1)

on changeCase(t, c)
	set upCase to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	set lowCase to "abcdefghijklmnopqrstuvwxyz"
	set newText to {}
	repeat with thisChr in t
		try
			if c is -1 then
				copy character (offset of (contents of thisChr) in lowCase) of lowCase to end of newText
			else if c is 1 then
				copy character (offset of (contents of thisChr) in upCase) of upCase to end of newText
			end if
		on error
			copy contents of thisChr to end of newText
		end try
	end repeat
	return newText as text
end changeCase

The following script will rename whatever is selected in the Finder or if nothing is selected and a window is open, it will rename ever item in the window. I’ve got few checks and no warning dialogs in this so be careful with it. (Yes, it’s long and not very simple but that’s just because I like avoiding the Finder whenever possible.)

set dateStamp to changeCase(do shell script "date '+%d%b%y'", 1)

tell application "Finder" to set sel to selection
if (count of sel) > 0 then
	renameItems(sel, dateStamp)
else if (count of sel) is 0 then
	-- if 0 then check for window 1
	if exists window 1 then
		tell application "Finder" to set t to target of window 1
		renameItems(every item of t, dateStamp)
	end if
end if

on changeCase(t, c)
	set upCase to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	set lowCase to "abcdefghijklmnopqrstuvwxyz"
	set newText to {}
	repeat with thisChr in t
		try
			if c is -1 then
				copy character (offset of (contents of thisChr) in lowCase) of lowCase to end of newText
			else if c is 1 then
				copy character (offset of (contents of thisChr) in upCase) of upCase to end of newText
			end if
		on error
			copy contents of thisChr to end of newText
		end try
	end repeat
	return newText as text
end changeCase

on getExt(thisName, keepDot)
	set thisName to thisName as text
	if keepDot then
		set myOffset to offset of "." in (reverse of characters in thisName as text)
	else
		set myOffset to (offset of "." in (reverse of characters in thisName as text)) - 1
	end if
	if myOffset > 0 then
		return characters -myOffset thru -1 of thisName as text
	else
		return ""
	end if
end getExt

on pathToName(thisPath, keepExt)
	set thisPath to thisPath as text
	set delim to ":"
	if thisPath does not contain ":" then set delim to "/"
	if the last character of thisPath is delim then -- it's a folder
		set theOffset to (offset of delim in (reverse of characters 1 thru -2 of thisPath) as string)
		try
			set theName to (characters -theOffset thru -2 of thisPath as text)
		on error -- it's the root disk
			set theName to (text 1 thru -2 of thisPath as text)
		end try
	else -- it's a file
		set theOffset to (offset of delim in (reverse of characters of thisPath) as string) - 1
		set theName to (characters -theOffset thru -1 of thisPath as text)
	end if
	if keepExt then
		return theName
	else
		return removeExt(theName)
	end if
end pathToName

on removeExt(thisItem)
	set thisItem to thisItem as text
	set extText to ""
	set myOffset to offset of "." in (reverse of characters in thisItem as text)
	set newName to characters 1 thru -(myOffset + 1) of thisItem as text
	return newName
end removeExt

on renameItems(itemList, addName)
	if addName is not "" then
		repeat with thisItem in itemList
			set newName to pathToName(thisItem, false) & addName & getExt(thisItem, true)
			tell application "Finder" to set name of item (thisItem as text) to newName
		end repeat
	end if
end renameItems

I particularly like the year * 100 + day bit, Kai

For those for whom this solution was a bit mysterious, it amounts to this:

set now to current date
-- Result: date "Thursday, November 17, 2005 1:46:39 PM"
set mo to (month of now as string)
-- Result: "November"
set addDaytoYear to (year of now) * 100 + (day of now) as string
-- Result: "200517"
set d to text -2 thru -1 of addDaytoYear
-- Result: "17"
set e to text 1 thru 3 of mo
-- Result: "Nov"
set f to text -4 thru -3 of addDaytoYear
-- Result: "05"
d & e & f
-- Result: "17Nov05"

-- And, if you want spaces, Kai's solution becomes:

tell (current date) to tell (its month as string) & year * 100 + day to set d to text -2 thru -1 & space & text 1 thru 3 & space & text -4 thru -3
-- Result: "17 Nov 05"

Seeing how you’re already using a shell script, you could try something like this:

do shell script "date '+%d%b%y' | ruby -n -e 'print $_.upcase'"

You can, of course, get the same output with other languages or commands.

Excellent explanation, Adam. :slight_smile:

Just to explore all the options, AppleScript’s text item delimiters can also be used to switch case relatively quickly:

to switchCase(l)
	tell "ABCDEFGHIJKLMNOPQRSTUVWXYZzyxwvutsrqponmlkjihgfedcba" to repeat with i in l
		set AppleScript's text item delimiters to i
		set i's contents to item (1 + (count text item 2))
	end repeat
	set text item delimiters to {""}
	l
end switchCase

tell (current date) to tell (its month as string) & year * 100 + day to set d to text -2 thru -1 & character 1 & my switchCase(characters 2 thru 3) & text -4 thru -3

It may be worth mentioning that shell scripts, while very fast on many jobs, carry an initial overhead for external calls. For comparatively simple tasks, such as these date functions, native AppleScript can be significantly faster. (The above script, for example, executes between 20-40 times faster than one that uses an equivalent shell script - OMM.) However, since execution times are pretty short anyway, this would normally be a minor consideration.

Certainly, for what it achieves, the brevity of Bruce’s suggestion would take some beating! :smiley:

Thanks, Bruce! I was wondering about that and was hoping someone would post the better code. I knew it was possible I just couldn’t find out how.

Kai;

The capitalizer/lowercaser stumps me. I tried to generalize it so it would simply switch every character in any string and can’t get it to work.

Thanks Kai, but obviously I’ve a long way to go.

So please 'splain to me how

set addDaytoYear to (year of now) * 100 + (day of now) as string
set d to text -2 thru -1 of addDaytoYear

this returns “17”. I would think you’d want text 5 thru 6.

Thanks.

PreTech

Year of now returns 2005 as a number
multipy by 100 to get 200500
add day of now (17) to get 200517
convert to text “200517”
text -2 through -1 picks the second last and last item in that text: “1” and “7” to yield “17”
Hope that helps - and, btw, in this instance text 5 thru 6 would have produced the same result.
The minus sign means to start at the other end and is very useful for grabbing extensions, etc.

Thanks Adam,

I did understand basicaly what it was doing. I was just wondering about the - in front of the numbers. It doesn’t seem to matter at first glance but maybe there is something there I don’t understand completely. Here’s your code with slight modification that seems to get the same result.

set now to current date
-- Result: date "Thursday, November 17, 2005 1:46:39 PM"
set mo to (month of now as string)
-- Result: "November"
set addDaytoYear to (year of now) * 100 + (day of now) as string
-- Result: "200517"
set d to text 5 thru 6 of addDaytoYear
-- Result: "17"
set e to text 1 thru 3 of mo
-- Result: "Nov"
set f to text 3 thru 4 of addDaytoYear
-- Result: "05"
set kdk to d & e & f
display dialog kdk
-- Result: "17Nov05"

-- And, if you want spaces, Kai's solution becomes:

tell (current date) to tell (its month as string) & year * 100 + day to set d to text -2 thru -1 & space & text 1 thru 3 & space & text -4 thru -3
-- Result: "17 Nov 05"

PreTech

Indeed it does as I pointed out in an edit addition to the original post. (I added that bit as an edit and you presumably responded while I was editing)

Ah yes, Adam. The handler was hard-coded for that particular job. Sorry if it caused a problem.

(Of course, the hard-coding might have been taken even further. If we could be sure that only English month names were to be involved, we could reduce the character set down to “ABCEGLNOPRTUVYyvutrponlgecba”. Then again, we might need to consider extending it to include accented characters for certain languages - but I’d rather not go down that path right now… ;))

To modify the script so that it ignores unlisted characters (spaces, numerical characters, etc.), we could just add a check - perhaps something like the one in this next version. However, I warn you that the results aren’t very pretty, since the case of each character is toggled - making for some decidedly ugly text.

to switchCase(l)
	tell "ABCDEFGHIJKLMNOPQRSTUVWXYZzyxwvutsrqponmlkjihgfedcba" to repeat with i in l
		set AppleScript's text item delimiters to i
		if (count text items) is 2 then set i's contents to item (1 + (count text item 2))
	end repeat
	set text item delimiters to {""}
	l as string
end switchCase

set testString to "This Reverses The Case Of Each Character"

switchCase(testString's characters)
--> "tHIS rEVERSES tHE cASE oF eACH cHARACTER"

For more useful results, a few extra tweaks would be necessary. Rather than iterating through the characters of the text to be converted, this next version turns the algorithm on its head - and runs through the letters of the alphabet instead. This should make it a bit more efficient for converting longer strings, since there should only ever be a maximum of 26 iterations (unless, again, some special/accented characters need to be included for conversion purposes).

to switchCase of t with caps
	set n to (caps as integer) * 27
	set tid to text item delimiters
	tell "ABCDEFGHIJKLMNOPQRSTUVWXYZzyxwvutsrqponmlkjihgfedcba" to ¬
		repeat with i from n - 26 to n - 1
			set AppleScript's text item delimiters to item -i
			set t to t's text items
			set AppleScript's text item delimiters to item i
			tell t to set t to beginning & ({""} & rest)
		end repeat
	set text item delimiters to tid
	t
end switchCase

set testString to "tHis iS a BiT of a MixeD bAg"

switchCase of testString with caps
--> "THIS IS A BIT OF A MIXED BAG"

switchCase of testString without caps
--> "this is a bit of a mixed bag"

I’m sure this has all been cleared up now (apologies for my absence when all this was going on). Just in case there are any lingering doubts, I had to back-count in my version because the various date/string elements were truncated or manipulated only in the final stage of the operation.

The first half of the statement put together all the date elements…

… while the second half broke them up, moved them around and joined them all up again:

Without the ability to count backwards from the end of the entire string, it would have been necessary to either calculate the length of the month each time - or, as Adam did in his step-by-step version, truncate the month string at an earlier stage - so that all string elements would then be of a known, consistent length each time. (At which point the direction of the count, whether forwards from the beginning, or back from the end, becomes largely a matter of preference.)

There’s another example, above, which takes advantage of this ability to count items from the end of an object. At the start of the (revised) ‘switchCase’ handler, this statement…

… coerces a boolean value (true or false) to an integer (1 or 0) and then multiplies it by 27 (”> 27 or 0). Then, a couple of lines later, this statement appears:

So, if the calling statement specifies with caps, then the variable caps has a boolean value of true - which is coerced to 1… n = 1 * 27 = 27.

In the repeat loop, then, the variable i will increment from a starting value of ( 27 - 26 = ) 1… to a final value of ( 27 - 1 = ) 26. (Straightforward enough.)

When the calling statement passes a without caps parameter, caps = false ”> 0… n = 0 * 27 = 0.

So this time within the loop, i will increment from a starting value of ( 0 - 26 = ) -26… to a final value of ( 0 - 1 = ) -1. (I just found it simpler, from a shared calculation, to derive the range -26 to -1, rather than 27 to 52.)

:slight_smile: