Date typing in AppleScript

I clearly don’t yet understand the typing mechinsm in Applescript.

I have a date variable that I need to try and convert to a string in the format MM/DD/YY

What’s the easiest and fastest way to do this?

Thanks,

Maddog

It might depend on which version of Mac OS/AppleScript you are running. If I’m not mistaken, Panther introduced some changes to the way dates can be manipulated.

– Rob

How do I determine that? I’m running Panther with the very latest updates of XCode for AppleScript Studio.

There’s probably a better way of doing this but this works for me:

set the_date to date "Saturday, January 1, 2000 12:00:00 AM"
return format_date(the_date, "/", false)
-->"01/01/00"

on format_date(the_date, the_sep, inc_time)
	set the_month to month of the_date as integer
	if the_month < 10 then set the_month to "0" & the_month as string
	set the_day to day of the_date as integer
	if the_day < 10 then set the_day to "0" & the_day as string
	set the_year to (text 3 thru 4 of (year of the_date as string))
	set date_string to the_month & the_sep & the_day & the_sep & the_year
	if inc_time = true then set date_string to date_string & ", " & (time string of the_date)
	return date_string as string
end format_date

Jon

Thanks much, using other peoples code is so much better than having to write it yourself… 8)

Seriously though, I really appreciate the help. This is a really great forum.

Well, there’s easiest and there’s fastest…which do you really want? :slight_smile:

on DateToString(d, s)
	(*	d = date
	 *	s = format string, (case sensitive):
	 *
	 *		yyyy	year, 4 digits
	 *		  yy	year, 2 digits
	 *		mmmm	month, full name
	 *		 mmm	month, 3 character abbreviation
	 *		  mm	month, 1 - 12, zero padded
	 *		   m	month, 1 - 12
	 *		dddd	day, full name
	 *		 ddd	day, 3 character abbreviation
	 *		  dd	date, 1 - 31, zero padded
	 *		   d	date, 1 - 31
	 *		  hh	hour, 1 - 12, zero padded
	 *		   h	hour, 1 - 12
	 *		  HH	hour, 0 - 23, zero padded
	 *		   H	hour, 0 - 23
	 *		  MM	minutes, 0 - 59, zero padded
	 *		   M	minutes, 0 - 59
	 *		  ss	seconds, 0 - 59, zero padded
	 *		   s	seconds, 0 - 59
	 *		  AP	AM or PM
	 *		zzzz	4 digit offset from GMT, +hhmm or -hhmm
	 *		  zz	2 digit offset from GMT, +hh or -hh
	 *
	 *		   `	escape character
	 *		   ~	null character
	 *
	 *	Parsing Rules:
	 *		Reading the format string from left to right, the script
	 *	always obtains the longest possible match:
	 *
	 *		"mmmmmmmmm" --> "mmmm" + "mmmm" + "m"
	 *
	 *		The escape and null meta-characters can be used to avoid
	 *	any possible ambiguity:
	 *
	 *			"mmmmmmmm~m" --> "mmmm" + "mmmm" + "m"
	 *			"mmmmmmm~mm" --> "mmmm" + "mmm" + "mm"
	 *			"mmmmmm~mmm" --> "mmmm" + "mm" + "mmm"
	 *			"mmmmm~mmmm" --> "mmmm" + "m" + "mmmm"
	 *			"mmmm~mmmmm" --> "mmmm" + "mmmm" + "m"
	 *			"mmm~mmmmmm" --> "mmm" + "mmmm" + "mm"
	 *			"mm~mmmmmmm" --> "mm" + "mmmm" + "mmm"
	 *			"m~mmmmmmmm" --> "m" + "mmmm" + "mmmm"
	 *
	 *
	 *		set d to current date
	 *
	 *		DateToString(d, "mmm~mm") --> Sep17
	 *		DateToString(d, "mm~mmm") --> 17Sep
	 *
	 *		DateToString(d, "Today is dddd.") --> "To17ay i30 Wednesday."
	 *		DateToString(d, "To`day i`s dddd.") --> "Today is Wednesday."
	 *)
	if (s's class is not string) or (s's length = 0) then return d as string
	set s to s & "    " --> prevent out-of-bounds in parsing
	set t to ""
	considering case
		repeat until s's length < 5
			if (s starts with "yy") then
				set v to d's year as string
				if (s starts with "yyyy") then
					set t to t & v
					set s to s's text 5 thru -1
				else
					set t to t & v's text -2 thru -1
					set s to s's text 3 thru -1
				end if
			else if (s starts with "m") then
				if (s starts with "mmm") then
					set v to d's month as string
					if (s starts with "mmmm") then
						set t to t & v
						set s to s's text 5 thru -1
					else
						set t to t & v's text 1 thru 3
						set s to s's text 4 thru -1
					end if
				else
					(*	Modified from:
					 *		Nigel Garvey's "English Toffee," via
					 *		Richard Hartman's "Vanille Américaine," via
					 *		Emmanuel Lévy's "French Vanilla"
					 *)
					copy d to mm
					set mm's month to January
					set mm to (((mm - 2500000 - d) div -2500000 + 100) as string)'s text -2 thru -1
					if (s starts with "mm") then
						set t to t & mm
						set s to s's text 3 thru -1
					else
						set t to t & (mm as integer)
						set s to s's text 2 thru -1
					end if
				end if
			else if (s starts with "d") then
				if (s starts with "ddd") then
					set v to d's weekday as string
					if (s starts with "dddd") then
						set t to t & v
						set s to s's text 5 thru -1
					else
						set t to t & v's text 1 thru 3
						set s to s's text 4 thru -1
					end if
				else
					set v to d's day as string
					if (s starts with "dd") then
						set t to t & ("0" & v)'s text -2 thru -1
						set s to s's text 3 thru -1
					else
						set t to t & v
						set s to s's text 2 thru -1
					end if
				end if
			else if (s starts with "h") or (s starts with "H") then
				set v to (d's time) div 60 div 60
				if (s starts with "h") and (v > 12) then set v to v - 12
				ignoring case
					if (s starts with "hh") then
						set t to t & ("0" & v)'s text -2 thru -1
						set s to s's text 3 thru -1
					else
						set t to t & v
						set s to s's text 2 thru -1
					end if
				end ignoring
			else if (s starts with "M") then
				set v to (d's time) div 60 mod 60
				if (s starts with "MM") then
					set t to t & ("0" & v)'s text -2 thru -1
					set s to s's text 3 thru -1
				else
					set t to t & v
					set s to s's text 2 thru -1
				end if
			else if (s starts with "s") then
				set v to (d's time) mod 60
				if (s starts with "ss") then
					set t to t & ("0" & v)'s text -2 thru -1
					set s to s's text 3 thru -1
				else
					set t to t & v
					set s to s's text 2 thru -1
				end if
			else if (s starts with "AP") then
				if ((d's time) div 60 div 60 < 12) then
					set t to t & "AM"
				else
					set t to t & "PM"
				end if
				set s to s's text 3 thru -1
			else if (s starts with "zz") then
				tell (time to GMT) / 60 div 60 * 100 to if it < 0 then
					set zzzz to "-" & ("0" & -it)'s text -4 thru -1
				else
					set zzzz to "+" & ("0" & it)'s text -4 thru -1
				end if
				if (s starts with "zzzz") then
					set t to t & zzzz
					set s to s's text 5 thru -1
				else
					set t to t & zzzz's text 1 thru 3
					set s to s's text 3 thru -1
				end if
			else if (s starts with "`") then
				set t to t & s's character 2
				set s to s's text 3 thru -1
			else if (s starts with "~") then
				set s to s's text 2 thru -1
			else
				set t to t & s's character 1
				set s to s's text 2 thru -1
			end if
		end repeat
	end considering
	return t
end DateToString

Here’s something that is slightly more involved, but is almost infinitely flexible, with fairly little code (compared to how flexible it is). It uses a shell command built in to OS X:


set sampleDate to (current date) - 3 * days

return dateUnixFormat(sampleDate, "%D")

on dateUnixFormat(theDate, unixFormatString)
	-- version 1.0, Daniel A. Shockley, http://www.danshockley.com
	-- based on code from Paul Berkowitz and Nigel Garvey on applescript-users mailing list
	try
		
		set uniDate to theDate - (time to GMT)
		set theEpoch to (date (do shell script "date -r 0 "+%a %b %e %Y
%H:%M:%S""))
		set unixSecs to uniDate - (theEpoch)
		set unixSecs to my NumberToString(unixSecs)
		
		set theDate to do shell script "date -r  " & unixSecs & " +"" & unixFormatString & """
		--there are lots and lots of other date formats you can use

	on error errMsg number errNum
		error "dateUnixFormat FAILED: " & errMsg number errNum
	end try
end dateUnixFormat

To find out all the amazing ways you can format your date using this, go to the Terminal and type

man strftime

It explains what you can send as the format string. %D means MM/DD/YY, which you could also get with the format string “%m/%d/%y”

Krioni, it looks like you left out the “NumberToString” handler. Also, in this line:

you have an extra space after "-r " and perhaps you should use the “quoted form” syntax:

set theDate to do shell script "date -r " & unixSecs & " +" & (quoted form of unixFormatString)

Jon

Yikes, and I thought I asked a fairly simple question. Guess not, huh?

Thanks for all your help.

I’ve read that Panther’s StandardAdditions has a “short date string” function, which returns a short date in the format set in the user’s preferences. That would be the easiest if it’s known that the script will only be run on a Panther (or later) machine by a user whose preferences are MM/DD/YY.

set shortDateStr to (short date string of (current date))

Otherwise, the fastest and easiest way to enforce that format on any machine would be:

on MMDDYY(theDate)
  set {day:d, year:y} to theDate
  copy theDate to b
  set b's month to January
  tell (y * 10000 + (b - 2500000 - theDate) div -2500000 * 100 + d) as string
    return text 5 thru 6 & "/" & text 7 thru 8 & "/" & text 3 thru 4
  end tell
end MMDDYY

set shortDateStr to MMDDYY(current date)
--> "03/12/04"

I don’t recognise my bit. :wink:

Nigel’s two suggestions are definitely the fastest and/or easiest. But, to make sure my (flexible for other uses) suggestion is correct, let me respond to Jonn8. Also, Nigel, I think there was a general discussion about using the UNIX date command, and you made some good points on applescript-users.

I most certainly did. It’s a handler by Paul Berkowitz, a great AS programmer. Here’s the whole thing, with the NumberToString handler and with Jonn8’s suggestions about using “quoted from of” included. I would have used those if I had written dateUnixFormat now, but I didn’t notice when posting it here before just how old the code was. :slight_smile:


on dateUnixFormat(theDate, unixFormatString)
	-- version 1.1, Daniel A. Shockley, http://www.danshockley.com
	-- based on code from Paul Berkowitz and Nigel Garvey on applescript-users mailing list
	-- updates suggested by Jonn8 on macscripter.net BBS
	try
		
		set uniDate to theDate - (time to GMT)
		set theEpoch to (date (do shell script "date -r 0 '+%a %b %e %Y %H:%M:%S'"))
		set unixSecs to uniDate - (theEpoch)
		set unixSecs to my NumberToString(unixSecs)
		
		set theDate to do shell script "date -r " & unixSecs & " +" & quoted form of unixFormatString & ""
		--there are lots and lots of other date formats you can use
		
		--> "03/17/02"
		
		
	on error errMsg number errNum
		error "dateUnixFormat FAILED: " & errMsg number errNum
	end try
end dateUnixFormat



on NumberToString(bigNumber)
	-- by Paul Berkowitz
	
	set bigNumber to bigNumber as string
	if bigNumber does not contain "E+" then return bigNumber
	
	set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {"E+"}}
	try
		set {basicReal, powersOfTen} to {bigNumber's text item 1, (bigNumber's text item 2) as integer}
	on error -- e.g. Python strings have lower-case "e", tids case-sensitive
		set AppleScript's text item delimiters to {"e+"}
		set {basicReal, powersOfTen} to {bigNumber's text item 1, (bigNumber's text item 2) as integer}
	end try
	set AppleScript's text item delimiters to {"."}
	try
		set {integerPart, decimalPart} to basicReal's {text item 1, text item 2}
		set decimalSign to "."
	on error
		set AppleScript's text item delimiters to {","}
		set {integerPart, decimalPart} to basicReal's {text item 1, text item 2}
		set decimalSign to ","
	end try
	set AppleScript's text item delimiters to tids
	set n to count decimalPart
	if powersOfTen is greater than or equal to n then
		repeat (powersOfTen - n) times
			set decimalPart to decimalPart & "0"
		end repeat
		set bigNumber to integerPart & decimalPart
	else
		set bigNumber to integerPart & decimalPart
		set bigNumber to text 1 thru (powersOfTen + 1) of bigNumber & decimalSign & text (powersOfTen + 2) thru -1 of bigNumber
	end if
	
	return bigNumber
	
end NumberToString

Krioni,

Using the GMT date is, well, returning the GMT for any date I use with this formatter, not my local time. Are you getting your local time?

Amending the routine to not coerce to GMT returns the proper time on my system:

set the_date to (current date)
dateUnixFormat(the_date, "%m/%d/%y %H:%M:%S")
(*
Event Log:
tell current application
    current date
        date "Friday, March 12, 2004 11:56:17 AM"
    do shell script "date -r 0 '+%a %b %e %Y %H:%M:%S'"
        "Wed Dec 31 1969 19:00:00"
    do shell script "date -r 1079110577 +'%m/%d/%y %H:%M:%S'"
        "03/12/04 11:56:17"
end tell
*)

on dateUnixFormat(theDate, unixFormatString)
	-- version 1.1, Daniel A. Shockley, http://www.danshockley.com 
	-- based on code from Paul Berkowitz and Nigel Garvey on applescript-users mailing list 
	-- updates suggested by Jonn8 on macscripter.net BBS 
	try
		set theEpoch to (date (do shell script "date -r 0 '+%a %b %e %Y %H:%M:%S'"))
		set unixSecs to theDate - (theEpoch)
		set unixSecs to my NumberToString(unixSecs)
		return (do shell script "date -r " & unixSecs & " +" & quoted form of unixFormatString)
	on error errMsg number errNum
		error "dateUnixFormat FAILED: " & errMsg number errNum
	end try
end dateUnixFormat

on NumberToString(bigNumber)
	-- by Paul Berkowitz 
	set bigNumber to bigNumber as string
	if bigNumber does not contain "E+" then return bigNumber
	set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {"E+"}}
	try
		set {basicReal, powersOfTen} to {bigNumber's text item 1, (bigNumber's text item 2) as integer}
	on error -- e.g. Python strings have lower-case "e", tids case-sensitive 
		set AppleScript's text item delimiters to {"e+"}
		set {basicReal, powersOfTen} to {bigNumber's text item 1, (bigNumber's text item 2) as integer}
	end try
	set AppleScript's text item delimiters to {"."}
	try
		set {integerPart, decimalPart} to basicReal's {text item 1, text item 2}
		set decimalSign to "."
	on error
		set AppleScript's text item delimiters to {","}
		set {integerPart, decimalPart} to basicReal's {text item 1, text item 2}
		set decimalSign to ","
	end try
	set AppleScript's text item delimiters to tids
	set n to count decimalPart
	if powersOfTen is greater than or equal to n then
		repeat (powersOfTen - n) times
			set decimalPart to decimalPart & "0"
		end repeat
		set bigNumber to integerPart & decimalPart
	else
		set bigNumber to integerPart & decimalPart
		set bigNumber to text 1 thru (powersOfTen + 1) of bigNumber & decimalSign & text (powersOfTen + 2) thru -1 of bigNumber
	end if
	return bigNumber
end NumberToString

Jon

Jonn8, you’re right, of course. I should look over old code before posting it. I must not have used this handler much myself, or I would have noticed that. Thanks.

Hello. In Panther,

Try short date string of (current date)

It will return a date in whatever format your default short date is.

Bill

Right on, Rob (in Ohio), and Nigel Garvey.

I don’t know about jonn8 (usually pretty helpful) or AdmiralNova, but just noticed Krioni joined in 1969. My respects. I was 23 years old that year (seriously).

Sorry if I misunderstood anybody. Were any of these posts helpful, maddog?

Bill

Actually as an adequate programming hack with no Applescript experience all the posts were very helpful. The more, well explained, code samples I see, the more I understand this language. I have now been able to do just about everything I need to do.

I’m waiting on one thing from the AppleScript studio forum, although it may be that this forum could help me.

I need to set the height of a window separately from the width, essentially I need to be able to add a constant to the second co-ordinate of an array, and don’t know how to do this.

Essentially:

set size of window “windowName” to (call method size of object)
– Given that I don’t know the values of A or B, how can I now make a statement like:

set size of window “windowName” to {A, B + constant}

DOH!! - just writing this down made me realize how easy this is to do.

{widthVar, heightVar} = (call method size of object)
set size of window “windowName” to {widthVar, heightVar + constant}

See, I told you ALL the posts in this reponse were helpful, even this one.

Thanks much to all,

Maddog

I just noticed that Krioni’s location is given as Philadelphia. Yo, homeboy! :slight_smile:

In 1969, my parents had just met each other in highschool.