Add Calendar fixes for Swift 3 (#686)

* Retain localeID when constructing a Calendar

The Calendar destructor releases stored values when the
Calendar is being deallocated, including releasing the localeID.

By default this is an empty string (kCFEmptyString) which results
in multiple Calendars causing a fault when it is over-released.
Ensure that instead the localeID is retained to balance the
release when it is cleaned up.

Issue: SR-2879

* Add support for ISO8601 calendar and others (#677)

The list of valid keys did not include the ISO8601 calendar, which
meant that code running on Linux that used it would fail. Fix this
by adding the kCFISO8601Calendar and others into the list of known
constants valid for calendars, and add tests for the Gregorian
calendar, as well as for creating all other calendars.

Issue: SR-2551
diff --git a/CoreFoundation/Locale.subproj/CFCalendar.c b/CoreFoundation/Locale.subproj/CFCalendar.c
index dd3f9d9..ce5196d 100644
--- a/CoreFoundation/Locale.subproj/CFCalendar.c
+++ b/CoreFoundation/Locale.subproj/CFCalendar.c
@@ -236,20 +236,29 @@
 }
 
 Boolean _CFCalendarInitWithIdentifier(CFCalendarRef calendar, CFStringRef identifier) {
-    if (identifier != kCFGregorianCalendar && identifier != kCFBuddhistCalendar && identifier != kCFJapaneseCalendar && identifier != kCFIslamicCalendar && identifier != kCFIslamicCivilCalendar && identifier != kCFHebrewCalendar && identifier != kCFChineseCalendar) {
+    if (identifier != kCFGregorianCalendar && identifier != kCFBuddhistCalendar && identifier != kCFJapaneseCalendar && identifier != kCFIslamicCalendar && identifier != kCFIslamicCivilCalendar && identifier != kCFHebrewCalendar && identifier != kCFRepublicOfChinaCalendar && identifier != kCFPersianCalendar && identifier != kCFCalendarIdentifierCoptic && identifier != kCFCalendarIdentifierEthiopicAmeteMihret && identifier != kCFCalendarIdentifierEthiopicAmeteAlem && identifier != kCFChineseCalendar && identifier != kCFISO8601Calendar && identifier != kCFIslamicTabularCalendar && identifier != kCFIslamicUmmAlQuraCalendar) {
         if (CFEqual(kCFGregorianCalendar, identifier)) identifier = kCFGregorianCalendar;
         else if (CFEqual(kCFBuddhistCalendar, identifier)) identifier = kCFBuddhistCalendar;
         else if (CFEqual(kCFJapaneseCalendar, identifier)) identifier = kCFJapaneseCalendar;
         else if (CFEqual(kCFIslamicCalendar, identifier)) identifier = kCFIslamicCalendar;
         else if (CFEqual(kCFIslamicCivilCalendar, identifier)) identifier = kCFIslamicCivilCalendar;
         else if (CFEqual(kCFHebrewCalendar, identifier)) identifier = kCFHebrewCalendar;
+        else if (CFEqual(kCFRepublicOfChinaCalendar, identifier)) identifier = kCFRepublicOfChinaCalendar;
+        else if (CFEqual(kCFPersianCalendar, identifier)) identifier = kCFPersianCalendar;
+        else if (CFEqual(kCFIndianCalendar, identifier)) identifier = kCFIndianCalendar;
+        else if (CFEqual(kCFCalendarIdentifierCoptic, identifier)) identifier = kCFCalendarIdentifierCoptic;
+        else if (CFEqual(kCFCalendarIdentifierEthiopicAmeteMihret, identifier)) identifier = kCFCalendarIdentifierEthiopicAmeteMihret;
+        else if (CFEqual(kCFCalendarIdentifierEthiopicAmeteAlem, identifier)) identifier = kCFCalendarIdentifierEthiopicAmeteAlem;
         else if (CFEqual(kCFChineseCalendar, identifier)) identifier = kCFChineseCalendar;
+        else if (CFEqual(kCFISO8601Calendar, identifier)) identifier = kCFISO8601Calendar;
+        else if (CFEqual(kCFIslamicTabularCalendar, identifier)) identifier = kCFIslamicTabularCalendar;
+        else if (CFEqual(kCFIslamicUmmAlQuraCalendar, identifier)) identifier = kCFIslamicUmmAlQuraCalendar;
         else return false;
     }
     
     calendar->_identifier = (CFStringRef)CFRetain(identifier);
     calendar->_locale = NULL;
-    calendar->_localeID = CFLocaleGetIdentifier(CFLocaleGetSystem());
+    calendar->_localeID = CFRetain(CFLocaleGetIdentifier(CFLocaleGetSystem()));
     calendar->_tz = CFTimeZoneCopyDefault();
     calendar->_cal = NULL;
     return true;
@@ -278,7 +287,7 @@
     }
     calendar->_identifier = (CFStringRef)CFRetain(identifier);
     calendar->_locale = NULL;
-    calendar->_localeID = CFLocaleGetIdentifier(CFLocaleGetSystem());
+    calendar->_localeID = CFRetain(CFLocaleGetIdentifier(CFLocaleGetSystem()));
     calendar->_tz = CFTimeZoneCopyDefault();
     calendar->_cal = NULL;
     return (CFCalendarRef)calendar;
diff --git a/CoreFoundation/Locale.subproj/CFLocaleKeys.c b/CoreFoundation/Locale.subproj/CFLocaleKeys.c
index 09ae314..a515818 100644
--- a/CoreFoundation/Locale.subproj/CFLocaleKeys.c
+++ b/CoreFoundation/Locale.subproj/CFLocaleKeys.c
@@ -126,7 +126,7 @@
 CONST_STRING_DECL(kCFCalendarIdentifierRepublicOfChina, "roc");
 CONST_STRING_DECL(kCFCalendarIdentifierPersian, "persian");
 CONST_STRING_DECL(kCFCalendarIdentifierIndian, "indian");
-CONST_STRING_DECL(kCFCalendarIdentifierISO8601, "");
+CONST_STRING_DECL(kCFCalendarIdentifierISO8601, "iso8601");
 CONST_STRING_DECL(kCFCalendarIdentifierCoptic, "coptic");
 CONST_STRING_DECL(kCFCalendarIdentifierEthiopicAmeteMihret, "ethiopic");
 CONST_STRING_DECL(kCFCalendarIdentifierEthiopicAmeteAlem, "ethiopic-amete-alem");
diff --git a/Foundation/NSCalendar.swift b/Foundation/NSCalendar.swift
index 7928224..89981cc 100644
--- a/Foundation/NSCalendar.swift
+++ b/Foundation/NSCalendar.swift
@@ -53,7 +53,7 @@
         public static let ethiopicAmeteMihret = NSCalendar.Identifier("ethiopic")
         public static let ethiopicAmeteAlem = NSCalendar.Identifier("ethiopic-amete-alem")
         public static let hebrew = NSCalendar.Identifier("hebrew")
-        public static let ISO8601 = NSCalendar.Identifier("")
+        public static let ISO8601 = NSCalendar.Identifier("iso8601")
         public static let indian = NSCalendar.Identifier("indian")
         public static let islamic = NSCalendar.Identifier("islamic")
         public static let islamicCivil = NSCalendar.Identifier("islamic-civil")
diff --git a/TestFoundation/TestNSCalendar.swift b/TestFoundation/TestNSCalendar.swift
index fa103d4..9f89858 100644
--- a/TestFoundation/TestNSCalendar.swift
+++ b/TestFoundation/TestNSCalendar.swift
@@ -20,9 +20,11 @@
     
     static var allTests: [(String, (TestNSCalendar) -> () throws -> Void)] {
         return [
+            ("test_allCalendars", test_allCalendars),
             ("test_gettingDatesOnGregorianCalendar", test_gettingDatesOnGregorianCalendar ),
             ("test_gettingDatesOnHebrewCalendar", test_gettingDatesOnHebrewCalendar ),
             ("test_gettingDatesOnChineseCalendar", test_gettingDatesOnChineseCalendar),
+            ("test_gettingDatesOnISO8601Calendar", test_gettingDatesOnISO8601Calendar),
             ("test_copy",test_copy),
             ("test_addingDates", test_addingDates)
             // Disabled because this fails on linux https://bugs.swift.org/browse/SR-320
@@ -30,6 +32,30 @@
         ]
     }
     
+    func test_allCalendars() {
+        for identifier in [
+            Calendar.Identifier.buddhist,
+            Calendar.Identifier.chinese,
+            Calendar.Identifier.coptic,
+            Calendar.Identifier.ethiopicAmeteAlem,
+            Calendar.Identifier.ethiopicAmeteMihret,
+            Calendar.Identifier.gregorian,
+            Calendar.Identifier.hebrew,
+            Calendar.Identifier.indian,
+            Calendar.Identifier.islamic,
+            Calendar.Identifier.islamicCivil,
+            Calendar.Identifier.islamicTabular,
+            Calendar.Identifier.islamicUmmAlQura,
+            Calendar.Identifier.iso8601,
+            Calendar.Identifier.japanese,
+            Calendar.Identifier.persian,
+            Calendar.Identifier.republicOfChina
+            ] {
+                let calendar = Calendar(identifier: identifier)
+                XCTAssertEqual(identifier,calendar.identifier)
+        }
+    }
+
     func test_gettingDatesOnGregorianCalendar() {
         let date = Date(timeIntervalSince1970: 1449332351)
         
@@ -41,6 +67,19 @@
         XCTAssertEqual(components.month, 12)
         XCTAssertEqual(components.day, 5)
     }
+
+    func test_gettingDatesOnISO8601Calendar() {
+        let date = Date(timeIntervalSince1970: 1449332351)
+
+        var calendar = Calendar(identifier: .iso8601)
+        calendar.timeZone = TimeZone(identifier: "UTC")!
+        let components = calendar.dateComponents([.year, .month, .day], from: date)
+
+        XCTAssertEqual(components.year, 2015)
+        XCTAssertEqual(components.month, 12)
+        XCTAssertEqual(components.day, 5)
+    }
+
     
     func test_gettingDatesOnHebrewCalendar() {
         let date = Date(timeIntervalSince1970: 1552580351)