motion/date_parser.rb
module DateParser
@@isoDateFormatter = nil
@@detector = nil
# Parse a date string: E.g.:
#
# DateParser.parse_date "There is a date in here tomorrow at 9:00 AM"
#
# => 2013-02-20 09:00:00 -0800
def self.parse_date(date_string)
if date_string.match(/\d{2}T\d{2}/)
return fractional_date(date_string) if date_string =~ /\.\d{3}Z$/
return Time.iso8601(date_string)
end
detect(date_string).first.date
end
# Parse time zone from date
#
# DateParser.parse_date "There is a date in here tomorrow at 9:00 AM EDT"
#
# Caveat: This is implemented per Apple documentation. I've never really
# seen it work.
def self.parse_time_zone(date_string)
detect(date_string).first.timeZone
end
# Parse a date string: E.g.:
#
# SugarCube::DateParser.parse_date "You have a meeting from 9:00 AM to 3:00 PM"
#
# => 21600.0
#
# Divide by 3600.0 to get number of hours duration.
def self.parse_duration(date_string)
detect(date_string).first.send(:duration)
end
# Parse a date into a raw match array for further processing
def self.match(date_string)
detect(date_string)
end
private
def self.detect(date_string)
error = Pointer.new(:object)
detector = NSDataDetector.dataDetectorWithTypes(NSTextCheckingTypeDate, error:error)
matches = detector.matchesInString(date_string, options:0, range:NSMakeRange(0, date_string.length))
end
def self.allocate_date_formatter
@@isoDateFormatter = NSDateFormatter.alloc.init
@@isoDateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ'"
end
def self.fractional_date(date_string)
allocate_date_formatter if @@isoDateFormatter.nil?
date = @@isoDateFormatter.dateFromString date_string
return date
end
def self.allocate_data_detector
error = Pointer.new(:object)
@@detector = NSDataDetector.dataDetectorWithTypes(NSTextCheckingTypeDate, error:error)
end
def self.detector
allocate_data_detector if @@detector.nil?
return @@detector
end
end
class String
# Use NSDataDetector to parse a string containing a date
# or duration. These can be of the form:
#
# "tomorrow at 7:30 PM"
# "11.23.2013"
# "from 7:30 to 10:00 AM"
#
# etc.
def to_date
DateParser.parse_date(self)
end
def to_timezone
DateParser.parse_time_zone(self)
end
def to_duration
DateParser.parse_duration(self)
end
end