Cocoa's NSDate class has sequestered deep within its bowels an exotic
method ("function" in FB parlance) called
"dateWithNaturalLanguageString."
Simply put, if you pass this method a limited set of non-case-
sensitive colloquial English phrases related to dates, i.e.,
"yesterday", "TODAY", "Tomorrow", "next week", "last year",
"12-09-07", etc., the function uses a bit of fuzzy logic and returns
the date in the format specified in your OS X International System
Preferences.
Now be forewarned, here is the official word from the Cocoa docs: "It
may give unexpected results, and its use is strongly discouraged."
It's no wonder the method is sparsely documented. And it's no wonder
I was immediately attracted to it!
That being said, the method has generated a good amount of attention,
especially in the iPhone community (iPhones and iPods are coded in
Cocoa). And when I first discovered it, I had great fun playing with
it and trying to figure out how it parses the phrases tossed at it.
Look at it as a latter-day Eliza for the space-time continuum with
the potential of having a speech recognition front end added to it so
you can play Star Trek and ask your iPhone to tell you the date of a
given day.
At any rate, like most Cocoa Objective-C code, it's succinct:
NSDate *date = [NSDate dateWithNaturalLanguageString:queryRef];
This one-liner takes the English phrase entered as the NSString
"queryRef" (remember that NSStrings are toll-free bridged with our
CFStrings) and returns an NSDate variable with a date derived from
the phrase.
(It can also be programmed to accept user designated phrases with
code something like this:
[me setValue:d forProperty:@"Grad Date"]
which allows the function to see the English phrase "Grad Date" as a
referecne to a particular date.")
FWIW, I created an Objective-C function that:
[1]. Inputs a Str255 containing our English date-related phrase
[2]. Converts it to a CFStringRef
[3]. Runs it through dateWithNaturalLanguageString
[4]. Returns the NSDate variable
[5]. Converts the NSDate variable and returns a CFStringRef
IMPORTANT NOTE: Be sure to check FBtoC's "Use Objective C Compiler"
preference.
One interesting thing is that some time this code generates gcc
warnings in FBtoC, and sometimes it doesn't. Go figure.
In this little demo I've thrown in several different phrases,
including a bogus one, for your entertainment.
I hope this stuff isn't boring the list, but I've put together a
bunch of little C and Objective-C functions wrapped in GUIs created
in FB and it's a nice break from Xcode.
Ken
/*
Fuzzy Date Finder
Demo of Cocoa's NSDate dateWithNaturalLanguageString
method embedded in FB.
Takes colloquial English phrases, i.e., "today," "Last week",
"December 15, 2009," and returns an NSDate that is
converted back into a human-readable date in the
format specified in the OS X System Preferences
International preference pane.
NOTE: Requires FBtoC's "Use Objective C Compiler" preference
Ken Shmidheiser
July 12, 2009
*/
output file "Fuzzy Date Finder"
include "Util_Containers.incl"
begin globals
dim as Container gC
end globals
#if def _PASSTHROUGHFUNCTION
#import <Cocoa/Cocoa.h>
CFStringRef FuzzyDateFinder( Str255 fuzzyDate )
{
CFStringRef queryRef, outDate;
queryRef = CFStringCreateWithPascalString( kCFAllocatorDefault,
fuzzyDate, kCFStringEncodingMacRoman );
NSDate *date = [NSDate dateWithNaturalLanguageString: queryRef];
CFRelease( queryRef );
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init]
autorelease];
[ dateFormatter setDateStyle: NSDateFormatterLongStyle ];
NSString *dateString = [ dateFormatter stringFromDate: date ];
outDate = (CFStringRef) dateString;
return( outDate );
}
#endif
toolbox fn FuzzyDateFinder( Str255 ) = CFStringRef
window 1, "Fuzzy Date Finder", ( 0, 0 )-( 400, 600 )
text _courier, 12
_arrayElements = 22
dim as Str255 sampleStrings( _arrayElements )
dim as CFStringRef tempCFRef
dim as Long i
sampleStrings(0) = "Yesterday"
sampleStrings(1) = "today"
sampleStrings(2) = "Tomorrow"
sampleStrings(3) = "last month"
sampleStrings(4) = "Next month"
sampleStrings(5) = "Third Friday of this month"
sampleStrings(6) = "last Tuesday at dinner"
sampleStrings(7) = "3pm December 31, 2001"
sampleStrings(8) = "12/31/09"
sampleStrings(9) = "Today next year"
sampleStrings(10) = "last monday 00:00"
sampleStrings(11) = "Noon next Friday"
sampleStrings(12) = "1-5-92"
sampleStrings(13) = "29/11/10"
sampleStrings(14) = "28 Feb 07"
sampleStrings(15) = "Wednesday at 12am"
sampleStrings(16) = "Saturday morning"
sampleStrings(17) = "Lunch next week"
sampleStrings(18) = "2008-11-01 17:00:00 -0500"
sampleStrings(19) = "2011"
sampleStrings(20) = "yesterday 5pm"
sampleStrings(21) = "February 22, 2013"
print
for i = 0 to _arrayElements
gC = " "
long if ( len( sampleStrings(i) ))
tempCFRef = fn FuzzyDateFinder( sampleStrings(i) )
long if ( tempCFRef )
fn ContainerCreateWithCFString( tempCFRef, gC )
CFRelease( tempCFRef )
print i; ". "; sampleStrings(i); " is "; gC
print
xelse
print i; ". [Sorry, could not parse this phrase]"
print
end if
xelse
exit for
end if
next i
local fn DoDialog
if dialog(0) = _wndClose then end
end fn
on dialog fn DoDialog
do
HandleEvents
until ( gFBQuit )