Working with NSDate objects- as readable AS values

Hi all,

I can’t seem to get dates from a NSDate object (a picker with stepper) in IB.

Here is what I tried:

script TestAppDelegate

property theDate : missing value

	on DoWithDate_(sender)
		display dialog (theDate)
	end DoWithDate_
	on applicationWillFinishLaunching_(aNotification)
		-- Insert code here to initialize your application before any files are opened 
	end applicationWillFinishLaunching_
	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits 
		return my NSTerminateNow
	end applicationShouldTerminate_
end script

The dialog pops up on an edit in the picker, but it displays nothing. I have the value bound to theDate, and the Date Picker wired to “on DoWithDate_(sender)” Also tried to use nsdate’s dateValue, but nothing happened using:

set theDate to theDate’s dateValue as string (or text)

Still trying to master these OBJC methods.

Any help appreciated.

I’d put your property declaration inside the script object, and make it missing value rather than “”, and from then on refer to “my theDate”.

Having said that, I’m having no luck with dates – they should be coerceable to dates (and then to text), but I can’t get them to.

The NSDatePicker class has a dateValue method.

Connect a property to the date picker in IB.
Then get the value like this.

property datePicker : missing value
set curDate to datePicker's dateValue()

-- result => 1982-02-12 08:00:00 -0800

Ok thanks, I cleaned up the first post with Shane’s recemmendation.

Also Craig’s in this post to look like:

	property datePicker : missing value
	on DoWithTheDate_(sender)
		set curDate to datePicker's dateValue()  ### also tried with "as Text" and with "as string"
		display dialog (curDate)	
	end DoWithTheDate_	

Now I get from the console:

2009-10-16 20:09:52.788 Test[368:a0f] -[__NSCFDate dateValue]: unrecognized selector sent to instance 0x2003df740
2009-10-16 20:09:52.788 Test[368:a0f] *** -[TestAppDelegate DoWithTheDate:]: -[__NSCFDate dateValue]: unrecognized selector sent to instance 0x2003df740 (error -10000)

(I think I’m getting closer :slight_smile: )

I think I’m on to something here, after reading a lot of the documentation, just don’t know how to make the statement in AS:

The documentation suggests adding a date formatter to the control and using it’s instance methods to get the date string. Not a good choice for calculating in AS, but I’ll take it for starters if it let’s us under the hood of the NSDate class lol.

There are 2 methods on the formatter class to extract the date string hence. This being the more relevant I think:

Returns a string representation of a given date formatted using the receiver’s current settings.

  • (NSString *)stringFromDate:(NSDate *)date

The date to format.

Return Value
A string representation of date formatted using the receiver’s current settings.

So now we will have an instance of Date formatter returning from the datePicker.

Any ideas on this or am I off on a tangent?


Read Stefan’s comment here =>

Hi Craig, Yes I read that earlier, but now it makes more sense after I stumbled into the NSDateFormatter from IB :slight_smile:

So Iare we saying one cannot coerce the strings out of (or into) the Date Picker OR the Date Formatter objects coming out of IB?

I am trying a lot of different things and getting usually a singe error in the log as above, or an execution error:
“Cannot create date from object <NSDateFormatter: 0x20055e800> of class NSDateFormatter”

So there has GOT to be a way to ASOC’ize this code. It’s just not logical to not make such an important function unavailable to ASOC IMHO… is it?

Not at all. I don’t know how long they have been working on this framework, but things like this take time. It might be another year or more before we see things working the way Apple has planned. Until then, learning Objective-C and using it when necessary is the way to go.

You might try creating an Objective-C class, hooking up all that code to the date picker, and calling it from AppleScriptObjC. Have the Objective-C class return a string of the date in the format you want.

I know it is frustrating, but it will get better. For now, I write most everything in Objective-C and only use AppleScriptObjC when I need to use Apple Events. Other than that, it is just easier (to me) to write it all in Objective-C.

Thanks Craig, I will give it a try and post back.

… but before I do :slight_smile:

Have a look at this. the DatePicker object is bound to my datePicker. Tried all variations of the NSDateFormatter too but no go, declared an NSObject class, and put those little | thingies around the description method, coerced the description to text.

property parent : class "NSObject"
	property datePicker : missing value
	property curDate : missing value
	on DoWithTheDate_(sender)
		set my curDate to datePicker's |description| as text
		log my curDate
		display dialog (my curDate)
	end DoWithTheDate_

	on applicationWillFinishLaunching_(aNotification)
		-- Insert code here to initialize your application before any files are opened 
	end applicationWillFinishLaunching_
	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits 
		return true
	end applicationShouldTerminate_

Got the long date and long time (with offset from UTC)


When I selected the Value Transformers “NSKeyedUnarchiveFromData and NSUnarchiveFromData” the dialog had key coded data in it, encoded I believe.

Is this progress? (before I go the OBJ-C route)

So it seems that NSDates can’t be coerced to AS dates, or even to AS strings easily. You can get the description and parse the resulting string, but that looks fragile to me.

One of the differences between NSDate and AS dates is that AS dates assume the user’s calendar, whereas getting the details out of an NSDate involves specifying the calendar. In fact, it’s a multi-part process.

You can get the calendar in use by calling NSCalendar’s class method currentCalendar:. With that instance of a calendar, you can call the calendar’s components:fromDate: method. This returns an NSDateComponents object, which has methods for returning the year, month, etc.

So let’s assume a date from a date picker:

set theDate to my picker's dateValue()
set theCal to current application's class "NSCalendar"'s currentCalendar()
set theComponents to theCal's components_fromDate_(254, theDate)

The 254 is a mask for which components we want the result to contain; 254 means year, month, day, hour, minute, second, but there are others.

The NSDateComponents class has methods for extracting the components individually, so:

set theYear to theComponents's |year|()
set theMonth to theComponents's |month|()
set theDay to theComponents's |day|()
set theHour to theComponents's hour()
set theMinute to theComponents's minute()
set theSecond to theComponents's |second|()

Now you need to make an AS date, and set the various components:

set theDate to current date
set day of theDate to 1 -- important
set seconds of theDate to theSecond
set year of theDate to theYear
set month of theDate to theMonth
set day of theDate to theDay
set hours of theDate to theHour
set minutes of theDate to theMinute
log (theDate as text)

It’s a fair bit of code to do what I suspect should happen automatically, but on my MacBook it takes all of 0.003 seconds, so there’s no real performance hit. If you need to use it often, you could easily wrap it up in a handler.

Edited: I’ve inserted the line “set day of theDate to 1” to avoid problems when the day of the current date exceeds the number of days in the new date.

Thanks Shane. This is getting very cool.

I am continuing to experiment in IB as I absorb what’s been learned so far, and today I took some time in IB and saw that I could also connect a datePicker’s string value directly to a text field and got the string value to display in that text field with no further coding… just the connections… I had no luck with the formatters, but was able to manipulate the display of the text field easily, using the datePicker’s attributes to set the date to long, short, or none… and same with time. So in one case all I wanted in the text field was 5:23 PM, and setting the datePicker’s attributes and connecting the two I got just that. I am thinking this may work for other IB items also?

I ran out of time today but will pick up tomorrow. I think by connection to a property I should be able to take the string value easily out of the text field again for processing/conversion to AS for use in a NStimer for example. The only issue I had was populating the value of a property with the new value of the text field.
Again, this would be for parsing and processing in AS from the values input by the user into a control.

I agree with Shane that this should be automatic. In the absence of any significant ASOC documentation, maybe it’s there, just undiscovered country? :slight_smile:

Play as I may in IB with connections, I really got nowhere beyond the description field functioning as an output string in AS. But I was finally able to do some processing of date/times using Shane’s great example code above, using the resultant conversion to do math in AS.

A couple questions.
In the case of the theDate initially being an instance of NSDate coming from the datePicker, could I do my math directly between that instance and and another i.e against the result of a current time method in AS that modifies the components of a new NSDate?

Is this method (reversed), a logical way to set the datePicker to “now” for first presentation to the user? I tried the init method, but the “id” parameter got me lost. One would think it would default to that but in IB there is no “now” default setting for the control that I can see.

What does the 254 mean in the code, could you give me a reference to the documentation for that?

In one case I am using the datePicker to specify a time only, setting its attributes accordingly, using AS to calculate time since midnight to process the task once a day at that time… Would this method, without the extra code (day,month,year etc) be an appropriate use for getting that time into AS as well? or would there be something more efficient.

Many thanks!

Here is a quote from Chris Nebel from the AppleScript Studio mailing list.

You might want to look at my follow-up to Chris’s post – there seems to be a potential 64-bit issue involved.

I don’t follow…

The NSDate equivalent of current date is NSDate’s “date” class method, and you can use the picker’s setDateValue: method:

		set theDate to current application's class "NSDate"'s |date|()
		my picker's setDateValue_(theDate)

Object-C uses enumerations that represent individual bits in a byte for a lot of these flags. They are usually listed under "Constants’ in the docs. So in NSCalendar’s Calendar Units, you’ll see that NSYearCalendarUnit = kCFCanlendarUnitYear, and if you click on that you’ll eventually come to the CFCalendarUnit constants. kCFCalendarUnitYear is listed as (1 << 2), which translates to 4 as an integer. Similarly, kCFCalendarUnitMonth is (1 << 3), which means 8 ( 1* 2^3). You just add up the total of all the ones you want to include.

There may be something more efficient in typing terms, but it’ll do exactly what you want.

I meant something like:

property theDate:<> --1/1/2010
property userzDate:<>-- 1/1/2008

Code would be in the proposal

Set difDate to theDate - userzDate
log difDate (result would be either an NSdate or a string value equivalent to 2 years)

Something like that was what I was getting at… could I do math directly against the instance and not the value? (I’m guessing the answer is no)

On the post regarding using the DateFormatter to get strings from NSDates, through at least the 60 or so exercises I have done in the past 3 days on this, I was never able to get a string from a formatter, or when I did get a string from a NSDate (via the picker or a text field), it was never in the attached formatter’s … format. I couldn’t find what I was not doing right so ultimately gave up on it.

Thanks for all this great information Craig and Shane. It is truly appreciated.

No – you’d use something like:

set theDiff to theDate’s timeIntervalSinceDate_(userzDate)

Try something like this:

		set now to current application's class "NSDate"'s |date|() -- current date
		set myFormatter to current application's class "NSDateFormatter"'s alloc()'s init()
		myFormatter's setDateStyle_(1) -- 0 = none, 1 = short, 2 = med, 3 = long, 4 = full
		myFormatter's setTimeStyle_(3) 
		set theString to myFormatter's stringFromDate_(now)

In case anyone is after the code for Chris’s method:

set theDate to current application's class "NSDate"'s |date|() -- current date
set theDiff to theDate's timeIntervalSinceReferenceDate()
set ASDate to (date "Monday, January 1, 2001 12:00:00 AM") + theDiff div 1 + (time to GMT)

Unbelievable! it works! Your advice here Shane and Craig has made working with dates so flexible, and much easier to understand.

I can now:

  1. Present a DatePicker to the user with today’s date and/or time as the picker’s default.

  2. Based on the user’s input calculate a difference ,using AS seconds serial value as an option to tell the user how much time left before the task is performed.

  3. Set up an NSTimer for the scheduled task (which I learned in my previous posts)

  4. Save the user’s date setting as a datePicker object in the preferences file (also learned in previous posts regarding NS User deaults) which loads at run time to populate the item’s above during app initialization.

  5. Use the NSdateFormatter to update the log in natural language.

I am putting the finishing touches on this utility app which as I stated in my other post in the forum, was a hard coded AS app running headless Now it has a really elegant UI with a drawer for optional preferences, and a single window with live updating etc.

When I am finished I will put a sample in this thread to show what the above assistance has helped me to accomplish regarding dates and date math, but would also like to give Shane and Craig a copy of the finished product to show what I’ve done in the 21 days (in my spare time) since I came here looking for help as a complete amateur with no AS Studio or XCode knowledge. I am sure you will probably chuckle at some things that could be done easier, but the version of the app without this date option has been running non stop for 2 weeks on 3 local machines and 2 beta tester’s equipment (and they love it!) so the result is that this product is very robust.

There are still a few things to do, like make an icon, and implement help although it is very straight forward. I have the “About” code finished, and I need to find a place to host it as a freeware utility (for non-commercial anyway) and also I need to learn how to obscure my script/code in the bundle as it seems to be there in plain text format for all to see to that’s not a desirable feature but may be that I need to set something to get the script to compile into the OBJ-c code in the executable or something but I haven’t approached that issue yet so research may solve that for me.

So although I am sure I will be coming back to the forum to learn more from you folks as other challenges present themselves, just wanted you to know that I would not have even bothered to move forward with this app until I saw a way to do it with the new ASOC which is awesome, and I discovered this website with the tutorials that Craig and Shane provide, as well as the advice I have received. About 30 hours (in 3 weeks) later and I can’t believe what was accomplished. Thanks to you all who post to for making this possible.