Dates & Times in AppleScripts

This whole thread is VERY intriguing but, unfortunately, I am too limited in my AppleScript knowledge to fully grasp all the intricacies of the coercion of dates.

Currently, I am trying to coerce a string from an astrology program (“Io Sprite”) and add either a day, month or year to advance or regress by any of these intervals.

I can get the LocalDate (app class) out as a string but adding or subtracting from it and and putting it back in the InfoCardWindow is eluding me.

Any ideas or help would be greatly appreciated.

~Roc

Give us an example of the string date you want to coerce.

I suggest you use this simpler way of getting a week number:

--According to ISO 8601 the week 1 of a year is the one with 4 Jan in it: (http://en.wikipedia.org/wiki/ISO_8601#Week_dates)

on weekNumber from inputDate

--First get the number of days since 4 Jan, then divide that by seven to get the number of full weeks passed. Finally round the number up to get the week currently in progress.

	round ((inputDate) - (date ("4 Jan" & year of inputDate))) / days / 7 rounding up
end weekNumber

Hi, solidfox.

Thanks for posting your suggestion. However, there are a few issues with it.

Firstly, the ‘date “”’ construction only works where the user’s Date and Time preferences are compatible with the format of the date string given. As from Snow Leopard, ‘date (“4 Jan” & year of inputDate)’ will error for users in the USA.

Secondly, your calculation works directly from 4th January, not from the beginning of the week in which it occurs.

Thirdly, you need to make provision for when the input date comes before 4th January and for when it’s one of the last three days of December and might be in the first week of the following year.

on weekNumber from inputDate against weekStart
	-- Get a known date in the past with the week-start weekday.
	-- NB. This was compiled in Snow Leopard, where AppleScript dates are Julian rather than Gregorian before some date in the 1500s. With Leopard or earlier, use date "Monday 6 January 1000".
	set baseDate to (date "Monday 1 January 1000 00:00:00") + (offset of (text 1 thru 2 of (weekStart as text)) in "MoTuWeThFrSaSu") div 2 * days
	
	-- Get 4th January in the year of the input date.
	copy inputDate to Jan4
	set Jan4's day to 4
	set Jan4's month to January
	-- If the input date's in the last three days of December, initially try with 4th January the following year.
	if (inputDate's month is December) and (inputDate's day > 28) then set Jan4's year to (Jan4's year) + 1
	
	-- Derive the beginning of the week of the 4th January date.
	set yearStart to Jan4 - (Jan4 - baseDate) mod weeks
	-- If the input date comes before this, it's counted as being in the previous year.
	if (inputDate comes before yearStart) then
		set Jan4's year to (Jan4's year) - 1
		set yearStart to Jan4 - (Jan4 - baseDate) mod weeks
	end if
	
	-- Derive and return the relevant week number for the input date.
	return (inputDate - yearStart + weeks) div weeks
end weekNumber

weekNumber from (current date) against Monday -- or "Monday"

I am trying to add twenty five minutes to the current time and then display the result in QuickSilver. How would I add time to the current time?

I am also not sure why QuickSilver is not posting my results.


--http://www.devdaily.com/apple/applescript-current-time-example-script-format

say "It will be " & getTimeInHoursAndMinutes() & " in 25 minutes" using "Alex"

on getTimeInHoursAndMinutes()
	-- Get the "hour"
	set timeStr to time string of (current date)
	set Pos to offset of ":" in timeStr
	set theHour to characters 1 thru (Pos - 1) of timeStr as string
	set timeStr to characters (Pos + 1) through end of timeStr as string
	
	-- Get the "minute"
	set Pos to offset of ":" in timeStr
	set theMin to characters 1 thru (Pos - 1) of timeStr as string
	set timeStr to characters (Pos + 1) through end of timeStr as string
	
	--Get "AM or PM"
	set Pos to offset of " " in timeStr
	set theSfx to characters (Pos + 1) through end of timeStr as string
	
	return (theHour & ":" & theMin & " " & theSfx) as string
	
end getTimeInHoursAndMinutes


set today to date string of (current date)
get today

tell application "Quicksilver" to show large type (getTimeInHoursAndMinutes())
end

This works but I don’t want to display the date at all.

tell application "Quicksilver" to show large type (current date) as string
end

This will display just the date,

set today to date string of (current date)
get today

tell application "Quicksilver" to show large type (get today)
end

Now how do I do just the time or at least add 25 minutes to the current time and include AM/PM and leave out the seconds?

Browser: Safari 531.21.10
Operating System: Mac OS X (10.6)

use seconds without units:

set TS to time string of ((current date) + (25 * 60))

or the word minutes:

set TS to time string of ((current date) + (25 * minutes))

then:

tell application "Quicksilver" to show large type TS

and by the way, when you call a handler from your script from a tell block you must include the word “my” in front of the handler call – Quicksilver doesn’t know about the handler.

That change makes your script work (without the last “end” you have in it). You do don’t use an “end” statement following a one line tell. You can see from above that there’s a much simpler way than you used.

--http://www.devdaily.com/apple/applescript-current-time-example-script-format

say "It will be " & getTimeInHoursAndMinutes() & " in 25 minutes" using "Alex"

on getTimeInHoursAndMinutes()
	-- Get the "hour"
	set timeStr to time string of (current date)
	set Pos to offset of ":" in timeStr
	set theHour to characters 1 thru (Pos - 1) of timeStr as string
	set timeStr to characters (Pos + 1) through end of timeStr as string
	
	-- Get the "minute"
	set Pos to offset of ":" in timeStr
	set theMin to characters 1 thru (Pos - 1) of timeStr as string
	set timeStr to characters (Pos + 1) through end of timeStr as string
	
	--Get "AM or PM"
	set Pos to offset of " " in timeStr
	set theSfx to characters (Pos + 1) through end of timeStr as string
	
	return (theHour & ":" & theMin & " " & theSfx) as string
	
end getTimeInHoursAndMinutes


set today to date string of (current date)
get today

tell application "Quicksilver" to show large type (my getTimeInHoursAndMinutes())

Wonderful thank you Adam that was very helpful. This seems like a complicated way to get the seconds to not be included and show AM and PM but I am glad that I have something that works. If anyone knows of a simpler way I’d love to hear about it.

I am also guessing as Stephan mentioned it probably wouldn’t work on everyones system and would depend on their time settings.

--http://www.devdaily.com/apple/applescript-current-time-example-script-format

say "It will be " & getTimeInHoursAndMinutes() & " in 25 minutes" using "Alex"

on getTimeInHoursAndMinutes()
	-- Get the "hour"
	set timeStr to time string of (current date)
	set Pos to offset of ":" in timeStr
	set theHour to characters 1 thru (Pos - 1) of timeStr as string
	set timeStr to characters (Pos + 1) through end of timeStr as string
	
	-- Get the "minute"
	set Pos to offset of ":" in timeStr
	set theMin to characters 1 thru (Pos - 1) of timeStr as string
	set timeStr to characters (Pos + 1) through end of timeStr as string
	
	--Get "AM or PM"
	set Pos to offset of " " in timeStr
	set theSfx to characters (Pos + 1) through end of timeStr as string
	
	return (theHour & ":" & (theMin + 25) & " " & theSfx) as string
	
end getTimeInHoursAndMinutes


set today to date string of (current date)
get today

tell application "Quicksilver" to show large type (my getTimeInHoursAndMinutes())

Oh darn I just ran the script again and realized it now says 10:83AM. That worked fine when the time was between 00-30.

Thanks again Adam!

Yeah. You need to add the twenty-five minutes before extracting the time string. :slight_smile:

By the way, lines like:

set theHour to characters 1 thru (Pos - 1) of timeStr as string

. would be better rendered as:

set theHour to text 1 thru (Pos - 1) of timeStr

It’s a more efficient, one-step process and doesn’t depend on the current state of AppleScript’s text item delimiters.

I think you could get away with using the ‘words’ of the time string, which would give you a shorter handler:

on getTimeInHoursAndMinutes(aDate)
	set ts to time string of aDate
	
	set hm to text 1 thru word 2 of ts
	if ((count ts's words) is 4) then set hm to hm & space & word 4 of ts
	
	return hm
end getTimeInHoursAndMinutes

say "It will be " & getTimeInHoursAndMinutes((current date) + 25 * minutes) & " in 25 minutes" using "Alex"

--tell application "Quicksilver" to show large type (my getTimeInHoursAndMinutes())

There are two other units that come in handy when performing business or scheduling calculations. Weeks and Months. Sometimes it’s useful to determine how many weeks or months have elapsed between two particular dates. I’ve also used this in document backup scripts for determining when to trigger weekly & monthly backups.

Nigel I just wanted to say thanks again for your help on this, I use what you helped me with a couple dozen times daily and find it very useful!

I recently installed a pulse water meter. With each 0.1 gallons use a pulse is generated. The pulses are recorded in a variable in Indigo, the home automation system.

I’d like to be able to log the data as current day, prior day, current week, prior week, current month and the preceeding 12 months, possibly going back to a couple of years. Obviously I need to create the relevant variables to store the data, but I’m not sure where to begin to get the data properly sorted. Any advice? I looked thru the thread and did not see a direct example.

Thanks!!!

I think this does what you have in mind:


set timeStr to time string of ((current date) + 25 * 60) -- you add seconds
tell application "Quicksilver" to show large type (get timeStr)

or in shorter form:


tell application "Quicksilver" to show large type (time string of ((current date) + 25 * 60))

thanks for the quick reply. i downloaded Quicksilver and ran the script in the editor. This is what it produced:

If I can ask, why do I want to do this in Quicksilver when i am trying to just partition a data stream from Indigo, that will stay in Indigo variables? I was thinking I would just accumulate the pulses and then segregate them into bins on a schedule.

what about something like this?

I think I figured it out. Each “current variable”, for instance Today, This Week and This Month, are incremented each time the water meter clicks via a single trigger. Every day at 12:01 AM a schedule runs the following script:


set {year:y, month:m, day:d, weekday:w} to (current date)


--Today and Yesterday. Second line in each sequence resets the current variable to ""
set value of variable "WaterUse_2_Yesterday" to value of variable "WaterUse_1_Today" as string

set value of variable "WaterUse_1_Today" to ""


--This week and last week. Only runs on Monday morning. 
if w is Monday then
	set value of variable "WaterUse_4_LastWeek" to value of variable "WaterUse_3_ThisWeek"
	set value of variable "WaterUse_2_Yesterday" to ""
end if


--This month and last month. Only runs on first of month.
if d is 1 then
	set value of variable "WaterUse_6_LastMonth" to value of variable "WaterUse_5_ThisMonth"
	set waterUseThisMonth to value of variable "WaterUse_5_ThisMonth"
	set value of variable "WaterUse_5_ThisMonth" to ""
end if


--Prior Month historical data
if d is 1 then
	if m is January then
		set value of variable "WaterUse_18_Dec" to waterUseThisMonth
	end if
	
	if m is February then
		set value of variable "WaterUse_7_Jan" to waterUseThisMonth
	end if
	
	if m is March then
		set value of variable "WaterUse_8_Feb" to waterUseThisMonth
	end if
	
	if m is April then
		set value of variable "WaterUse_9_Mar" to waterUseThisMonth
	end if
	
	if m is May then
		set value of variable "WaterUse_10_Apr" to waterUseThisMonth
	end if
	
	if m is June then
		set value of variable "WaterUse_11_May" to waterUseThisMonth
	end if
	
	if m is July then
		set value of variable "WaterUse_12_Jun" to waterUseThisMonth
	end if
	
	if m is August then
		set value of variable "WaterUse_13_Jul" to waterUseThisMonth
	end if
	
	if m is September then
		set value of variable "WaterUse_14_Aug" to waterUseThisMonth
	end if
	
	if m is October then
		set value of variable "WaterUse_15_Sep" to waterUseThisMonth
	end if
	
	if m is November then
		set value of variable "WaterUse_16_Oct" to waterUseThisMonth
	end if
	
	if m is December then
		set value of variable "WaterUse_17_Nov" to waterUseThisMonth
	end if
	
end if
			

Honestly, this is probably not very elegant. If anyone can show me how to write this in a less “brute force” way, I’d appreciate seeing how it’s done.

Hi hamw.

Is your query about manipulating AppleScript dates or about scripting Indigo? If the latter, it should be posted in the “AppleScript | Mac OS X” forum rather than appended to this article about dates. And since it’s possible that not many people will have experience of Indigo, you might include some information to lessen any confusion your scripts could cause. For instance, does Indigo have ‘variable’ elements with ‘value’ and ‘name’ properties?

Assuming your script in the previous post works, and that ‘variables’ are indeed elements in Indigo’s scripting dictionary, the following should also work. It makes use of an aspect of AppleScript dates. :wink:


set {year:y, month:m, day:d, weekday:w} to (current date)


--Today and Yesterday. Second line in each sequence resets the current variable to ""
set value of variable "WaterUse_2_Yesterday" to value of variable "WaterUse_1_Today"
set value of variable "WaterUse_1_Today" to ""


--This week and last week. Only runs on Monday morning. 
if w is Monday then
	set value of variable "WaterUse_4_LastWeek" to value of variable "WaterUse_3_ThisWeek"
	set value of variable "WaterUse_2_Yesterday" to ""
end if


--This month and last month. Only runs on first of month.
if d is 1 then
	set m to m as integer -- Coerce the AppleScript month to the equivalent month number.
	set namedLastMonthVariableName to item m of {"WaterUse_18_Dec", "WaterUse_7_Jan", "WaterUse_8_Feb", "WaterUse_9_Mar", "WaterUse_10_Apr", "WaterUse_11_May", "WaterUse_12_Jun", "WaterUse_13_Jul", "WaterUse_14_Aug", "WaterUse_15_Sep", "WaterUse_16_Oct", "WaterUse_17_Nov"}

	set waterUseThisMonth to value of variable "WaterUse_5_ThisMonth"
	set value of variable "WaterUse_6_LastMonth" to waterUseThisMonth
	set value of variable namedLastMonthVariableName to waterUseThisMonth
	set value of variable "WaterUse_5_ThisMonth" to ""
end if

Nigel, of course please move the posts to the proper area. That would be great as I might have some other questions related to this project later.

Appreciate the hints re the script; I am interested to see how your modificatiosn work . Also, yes, Indigo uses variables and values, which make it quite useful for doing stuff. It’s a great program if you have a chance to play with it.

Thanks again!

So Apple documents an issue with the date function, such that you can’t do

date of (current date)

and get December 1, 2014.

Is there any workaround for this? That’s exactly what I need: Some way to return today’s date without the weekday. Just the month and day would be sufficient, or even something like 12/1/2014 or 2014-12-1.

You’ll never use date of (current date) because date is already an date object. The documentation is wrong, we’ll know but similar commands with other classes won’t work either like string of “Hello World!”. To get the date in another notation you could use something like:

tell (current date) to return "" & it's year & "-" & (it's month as integer) & "-" & it's day

Thanks! You’d think there was an easier way to do something so simple, but this should work.

date formatting is never simple, because there are many formatting conventions for all the countries around the world, even you mentioned two quite different string patterns