Dealing with ISO 8601 dates

iso8601

(Shane Stanley) #1

This topic came up elsewhere, but some people here might have missed it. The issue is making dates from ISO 8601 strings, which can come in a variety of forms. In particular, dealing with time zones is tricky in AppleScript.

But there’s a third-party open-source framework that fits the bill nicely. You can read about it and download it here: https://github.com/boredzo/iso-8601-date-formatter. It handles most formats, including week date and ordinal date formats. That download is not going to be much use to most scripters, but essentially it can compile into a framework that can be called from AppleScript. I’ve compiled the framework, and you can download it here: https://www.macosxautomation.com/applescript/apps/ISO8601_framework.zip.

Once you add it to your system, either in ~/Library/Frameworks or within a library or other script bundle, calling it is simple. You can make it run in a strict mode, or the default of more lenient parsing, where it handles different delimiters and things like leading spaces. Here’s an example script:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "ISO8601"
use scripting additions

my ISO8601DateFrom:"2016-01-05 13:01:15"
my ISO8601DateFrom:"2016-01-05"
my ISO8601DateFrom:"2016-01-05T13:01:15"
my ISO8601DateFrom:"2016-01-05 13:01"
my ISO8601DateFrom:"2016-01-05T13:01:15Z"
my ISO8601DateFrom:"2016-01-05 13:01:15+1100"
my ISO8601DateFrom:"2007-W01-01"
my ISO8601DateFrom:"2007-W01-01T13:24:56-0800"
my ISO8601DateFrom:"-01-05"
my ISO8601DateFrom:"2017-032"

on ISO8601DateFrom:theString
	set theFormatter to current application's ISO8601DateFormatter's new()
	set theDate to theFormatter's dateFromString:theString
	considering numeric strings
		if AppleScript's version < "2.5" then
			set theDate to my makeASDateFrom:theDate
		else
			set theDate to theDate as date
		end if
	end considering
	return theDate -- AppleScript Date
end ISO8601DateFrom:

-- Required before 10.11
on makeASDateFrom:theNSDate
	set theCalendar to current application's NSCalendar's currentCalendar()
	set comps to theCalendar's componentsInTimeZone:(missing value) fromDate:theNSDate -- 'missing value' means current time zone
	tell (current date) to set {theASDate, year, day, its month, day, time} to ¬
		{it, comps's |year|(), 1, comps's |month|(), comps's |day|(), (comps's hour()) * hours + (comps's minute()) * minutes + (comps's |second|())}
	return theASDate
end makeASDateFrom:

There are also methods for setting the time zone, as well as making strings from dates.