Implementation of ISO8601DateFormatter (#998)

diff --git a/Foundation.xcodeproj/project.pbxproj b/Foundation.xcodeproj/project.pbxproj
index e15e703..f929ba1 100644
--- a/Foundation.xcodeproj/project.pbxproj
+++ b/Foundation.xcodeproj/project.pbxproj
@@ -311,8 +311,8 @@
 		61E0117F1C1B5990000037DD /* CFRunLoop.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5D88D81BBC9AD800234F36 /* CFRunLoop.c */; };
 		61E011811C1B5998000037DD /* CFMessagePort.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5D88DC1BBC9AEC00234F36 /* CFMessagePort.c */; };
 		61E011821C1B599A000037DD /* CFMachPort.c in Sources */ = {isa = PBXBuildFile; fileRef = 5B5D88D01BBC9AAC00234F36 /* CFMachPort.c */; };
-		63DCE9D21EAA430100E9CB02 /* NSISO8601DateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63DCE9D11EAA430100E9CB02 /* NSISO8601DateFormatter.swift */; };
-		63DCE9D41EAA432400E9CB02 /* TestNSISO8601DateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63DCE9D31EAA432400E9CB02 /* TestNSISO8601DateFormatter.swift */; };
+		63DCE9D21EAA430100E9CB02 /* ISO8601DateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63DCE9D11EAA430100E9CB02 /* ISO8601DateFormatter.swift */; };
+		63DCE9D41EAA432400E9CB02 /* TestISO8601DateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63DCE9D31EAA432400E9CB02 /* TestISO8601DateFormatter.swift */; };
 		6EB768281D18C12C00D4B719 /* UUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EB768271D18C12C00D4B719 /* UUID.swift */; };
 		7900433B1CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 790043391CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift */; };
 		7900433C1CACD33E00ECCBF1 /* TestNSPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7900433A1CACD33E00ECCBF1 /* TestNSPredicate.swift */; };
@@ -754,8 +754,8 @@
 		61D6C9EE1C1DFE9500DEF583 /* TestNSTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSTimer.swift; sourceTree = "<group>"; };
 		61E0117B1C1B554D000037DD /* TestNSRunLoop.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSRunLoop.swift; sourceTree = "<group>"; };
 		61F8AE7C1C180FC600FB62F0 /* TestNSNotificationCenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSNotificationCenter.swift; sourceTree = "<group>"; };
-		63DCE9D11EAA430100E9CB02 /* NSISO8601DateFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSISO8601DateFormatter.swift; sourceTree = "<group>"; };
-		63DCE9D31EAA432400E9CB02 /* TestNSISO8601DateFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSISO8601DateFormatter.swift; sourceTree = "<group>"; };
+		63DCE9D11EAA430100E9CB02 /* ISO8601DateFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ISO8601DateFormatter.swift; sourceTree = "<group>"; };
+		63DCE9D31EAA432400E9CB02 /* TestISO8601DateFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestISO8601DateFormatter.swift; sourceTree = "<group>"; };
 		6E203B8C1C1303BB003B2576 /* TestBundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestBundle.swift; sourceTree = "<group>"; };
 		6EB768271D18C12C00D4B719 /* UUID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UUID.swift; sourceTree = "<group>"; };
 		790043391CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSCompoundPredicate.swift; sourceTree = "<group>"; };
@@ -1430,7 +1430,7 @@
 				BDFDF0A61DFF5B3E00C04CC5 /* TestNSPersonNameComponents.swift */,
 				CD1C7F7C1E303B47008E331C /* TestNSError.swift */,
 				90E645DE1E4C89A400D0D47C /* TestNSCache.swift */,
-				63DCE9D31EAA432400E9CB02 /* TestNSISO8601DateFormatter.swift */,
+				63DCE9D31EAA432400E9CB02 /* TestISO8601DateFormatter.swift */,
 			);
 			name = Tests;
 			sourceTree = "<group>";
@@ -1526,7 +1526,7 @@
 				5BDC3F351BCC5DCB00ED97BB /* NSDateFormatter.swift */,
 				5BDC3F391BCC5DCB00ED97BB /* NSFormatter.swift */,
 				5B628EDE1D1C995C00CA9570 /* NSMeasurementFormatter.swift */,
-				63DCE9D11EAA430100E9CB02 /* NSISO8601DateFormatter.swift */,
+				63DCE9D11EAA430100E9CB02 /* ISO8601DateFormatter.swift */,
 			);
 			name = Formatters;
 			sourceTree = "<group>";
@@ -2021,7 +2021,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				63DCE9D21EAA430100E9CB02 /* NSISO8601DateFormatter.swift in Sources */,
+				63DCE9D21EAA430100E9CB02 /* ISO8601DateFormatter.swift in Sources */,
 				5BF7AE831BCD50CD008F214A /* NSArray.swift in Sources */,
 				EADE0B991BD15DFF00C49C64 /* NSEnergyFormatter.swift in Sources */,
 				EADE0BBF1BD15E0000C49C64 /* NSURLError.swift in Sources */,
@@ -2284,7 +2284,7 @@
 				5B13B3281C582D4C00651CE2 /* TestBundle.swift in Sources */,
 				5B13B32A1C582D4C00651CE2 /* TestNSCharacterSet.swift in Sources */,
 				BF8E65311DC3B3CB005AB5C3 /* TestNotification.swift in Sources */,
-				63DCE9D41EAA432400E9CB02 /* TestNSISO8601DateFormatter.swift in Sources */,
+				63DCE9D41EAA432400E9CB02 /* TestISO8601DateFormatter.swift in Sources */,
 				EA01AAEC1DA839C4008F4E07 /* TestProgress.swift in Sources */,
 				5B13B3411C582D4C00651CE2 /* TestNSRegularExpression.swift in Sources */,
 				5B13B3491C582D4C00651CE2 /* TestNSTimeZone.swift in Sources */,
diff --git a/Foundation/ISO8601DateFormatter.swift b/Foundation/ISO8601DateFormatter.swift
new file mode 100644
index 0000000..fbc82e0
--- /dev/null
+++ b/Foundation/ISO8601DateFormatter.swift
@@ -0,0 +1,119 @@
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See http://swift.org/LICENSE.txt for license information
+// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+
+import CoreFoundation
+
+extension ISO8601DateFormatter {
+
+    public struct Options : OptionSet {
+        
+        public private(set) var rawValue: UInt
+        
+        public init(rawValue: UInt) { self.rawValue = rawValue }
+
+        public static var withYear = ISO8601DateFormatter.Options(rawValue: 1 << 0)
+
+        public static var withMonth = ISO8601DateFormatter.Options(rawValue: 1 << 1)
+
+        public static var withWeekOfYear = ISO8601DateFormatter.Options(rawValue: 1 << 2)
+        
+        public static var withDay = ISO8601DateFormatter.Options(rawValue: 1 << 4)
+        
+        public static var withTime = ISO8601DateFormatter.Options(rawValue: 1 << 5)
+        
+        public static var withTimeZone = ISO8601DateFormatter.Options(rawValue: 1 << 6)
+        
+        public static var withSpaceBetweenDateAndTime = ISO8601DateFormatter.Options(rawValue: 1 << 7)
+        
+        public static var withDashSeparatorInDate = ISO8601DateFormatter.Options(rawValue: 1 << 8)
+        
+        public static var withColonSeparatorInTime = ISO8601DateFormatter.Options(rawValue: 1 << 9)
+        
+        public static var withColonSeparatorInTimeZone = ISO8601DateFormatter.Options(rawValue: 1 << 10)
+        
+        public static var withFullDate = ISO8601DateFormatter.Options(rawValue: withYear.rawValue + withMonth.rawValue + withDay.rawValue + withDashSeparatorInDate.rawValue)
+        
+        public static var withFullTime = ISO8601DateFormatter.Options(rawValue: withTime.rawValue + withTimeZone.rawValue + withColonSeparatorInTime.rawValue + withColonSeparatorInTimeZone.rawValue)
+
+        public static var withInternetDateTime = ISO8601DateFormatter.Options(rawValue: withFullDate.rawValue + withFullTime.rawValue)
+    }
+
+}
+
+open class ISO8601DateFormatter : Formatter, NSSecureCoding {
+    
+    typealias CFType = CFDateFormatter
+    private var __cfObject: CFType?
+    private var _cfObject: CFType {
+        guard let obj = __cfObject else {
+            #if os(OSX) || os(iOS)
+                let format = CFISO8601DateFormatOptions(rawValue: formatOptions.rawValue)
+            #else
+                let format = CFISO8601DateFormatOptions(self.formatOptions.rawValue)
+            #endif
+            let obj = CFDateFormatterCreateISO8601Formatter(kCFAllocatorSystemDefault, format)!
+            CFDateFormatterSetProperty(obj, kCFDateFormatterTimeZone, timeZone._cfObject)
+            __cfObject = obj
+            return obj
+        }
+        return obj
+    }
+    
+    /* Please note that there can be a significant performance cost when resetting these properties. Resetting each property can result in regenerating the entire CFDateFormatterRef, which can be very expensive. */
+    
+    open var timeZone: TimeZone! { willSet { _reset() } }
+    
+    open var formatOptions: ISO8601DateFormatter.Options { willSet { _reset() } }
+    
+    public override init() {
+        timeZone = TimeZone(identifier: "GMT")
+        formatOptions = [.withInternetDateTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withColonSeparatorInTimeZone]
+        super.init()
+    }
+    
+    public required init?(coder aDecoder: NSCoder) { NSUnimplemented() }
+    open override func encode(with aCoder: NSCoder) { NSUnimplemented() }
+    public static var supportsSecureCoding: Bool { return true }
+    
+    open func string(from date: Date) -> String {
+        return CFDateFormatterCreateStringWithDate(kCFAllocatorSystemDefault, _cfObject, date._cfObject)._swiftObject
+    }
+    
+    open func date(from string: String) -> Date? {
+        
+        var range = CFRange(location: 0, length: string.length)
+        let date = withUnsafeMutablePointer(to: &range) { (rangep: UnsafeMutablePointer<CFRange>) -> Date? in
+            guard let res = CFDateFormatterCreateDateFromString(kCFAllocatorSystemDefault, _cfObject, string._cfObject, rangep) else {
+                return nil
+            }
+            return res._swiftObject
+        }
+        return date
+        
+    }
+    
+    open class func string(from date: Date, timeZone: TimeZone, formatOptions: ISO8601DateFormatter.Options = []) -> String {
+        
+        #if os(OSX) || os(iOS)
+            let format = CFISO8601DateFormatOptions(rawValue: formatOptions.rawValue)
+        #else
+            let format = CFISO8601DateFormatOptions(formatOptions.rawValue)
+        #endif
+        
+        let obj = CFDateFormatterCreateISO8601Formatter(kCFAllocatorSystemDefault, format)
+        CFDateFormatterSetProperty(obj, kCFDateFormatterTimeZone, timeZone._cfObject)
+        return CFDateFormatterCreateStringWithDate(kCFAllocatorSystemDefault, obj, date._cfObject)._swiftObject
+        
+    }
+    
+    private func _reset() {
+        __cfObject = nil
+    }
+    
+}
diff --git a/Foundation/NSISO8601DateFormatter.swift b/Foundation/NSISO8601DateFormatter.swift
deleted file mode 100644
index 995bff5..0000000
--- a/Foundation/NSISO8601DateFormatter.swift
+++ /dev/null
@@ -1,79 +0,0 @@
-// This source file is part of the Swift.org open source project
-//
-// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
-// Licensed under Apache License v2.0 with Runtime Library Exception
-//
-// See http://swift.org/LICENSE.txt for license information
-// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-//
-
-import CoreFoundation
-
-extension ISO8601DateFormatter {
-    
-    
-    public struct Options : OptionSet {
-        public private(set) var rawValue: UInt
-        public init(rawValue: UInt) { self.rawValue = rawValue }
-        
-        public static var withYear = ISO8601DateFormatter.Options(rawValue: 1 << 0)
-        
-        public static var withMonth = ISO8601DateFormatter.Options(rawValue: 1 << 1)
-        
-        public static var withWeekOfYear = ISO8601DateFormatter.Options(rawValue: 1 << 2)
-        
-        public static var withDay = ISO8601DateFormatter.Options(rawValue: 1 << 3)
-        
-        public static var withTime = ISO8601DateFormatter.Options(rawValue: 1 << 4)
-        
-        public static var withTimeZone = ISO8601DateFormatter.Options(rawValue: 1 << 5)
-        
-        public static var withSpaceBetweenDateAndTime = ISO8601DateFormatter.Options(rawValue: 1 << 6)
-        
-        public static var withDashSeparatorInDate = ISO8601DateFormatter.Options(rawValue: 1 << 7)
-        
-        public static var withColonSeparatorInTime = ISO8601DateFormatter.Options(rawValue: 1 << 8)
-        
-        public static var withColonSeparatorInTimeZone = ISO8601DateFormatter.Options(rawValue: 1 << 9)
-        
-        public static var withFullDate = ISO8601DateFormatter.Options(rawValue: 1 << 10)
-        
-        public static var withFullTime = ISO8601DateFormatter.Options(rawValue: 1 << 11)
-        
-        public static var withInternetDateTime = ISO8601DateFormatter.Options(rawValue: 1 << 12)
-    }
-}
-
-open class ISO8601DateFormatter : Formatter, NSSecureCoding {
-    
-    
-    /* Please note that there can be a significant performance cost when resetting these properties. Resetting each property can result in regenerating the entire CFDateFormatterRef, which can be very expensive. */
-    open var timeZone: TimeZone! // The default time zone is GMT.
-    
-    
-    open var formatOptions: ISO8601DateFormatter.Options
-    
-    
-    /* This init method creates a formatter object set to the GMT time zone and preconfigured with the RFC 3339 standard format ("yyyy-MM-dd'T'HH:mm:ssXXXXX") using the following options:
-     NSISO8601DateFormatWithInternetDateTime | NSISO8601DateFormatWithDashSeparatorInDate | NSISO8601DateFormatWithColonSeparatorInTime | NSISO8601DateFormatWithColonSeparatorInTimeZone
-     */
-    public override init() { NSUnimplemented() }
-    
-    public required init?(coder aDecoder: NSCoder) { NSUnimplemented() }
-    open override func encode(with aCoder: NSCoder) { NSUnimplemented() }
-    public static var supportsSecureCoding: Bool { return true }
-    
-    
-    open func string(from date: Date) -> String {
-        NSUnimplemented()
-    }
-    
-    open func date(from string: String) -> Date? {
-        NSUnimplemented()
-    }
-    
-    
-    open class func string(from date: Date, timeZone: TimeZone, formatOptions: ISO8601DateFormatter.Options = []) -> String {
-        NSUnimplemented()
-    }
-}
diff --git a/TestFoundation/TestISO8601DateFormatter.swift b/TestFoundation/TestISO8601DateFormatter.swift
new file mode 100644
index 0000000..2173a22
--- /dev/null
+++ b/TestFoundation/TestISO8601DateFormatter.swift
@@ -0,0 +1,295 @@
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See http://swift.org/LICENSE.txt for license information
+// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+
+
+
+#if DEPLOYMENT_RUNTIME_OBJC || os(Linux)
+    import Foundation
+    import XCTest
+#else
+    import SwiftFoundation
+    import SwiftXCTest
+#endif
+
+class TestISO8601DateFormatter: XCTestCase {
+    
+    static var allTests : [(String, (TestISO8601DateFormatter) -> () throws -> Void)] {
+        
+        return [
+            ("test_stringFromDate", test_stringFromDate),
+            ("test_dateFromString", test_dateFromString),
+            ("test_stringFromDateClass", test_stringFromDateClass),
+        ]
+    }
+    
+    func test_stringFromDate() {
+        let formatter = DateFormatter()
+        formatter.dateFormat = "yyyy/MM/dd HH:mm zzz"
+        let someDateTime = formatter.date(from: "2016/10/08 22:31 GMT")
+        let isoFormatter = ISO8601DateFormatter()
+
+        //default settings check
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "2016-10-08T22:31:00Z")
+        
+        /*
+         The following tests cover various cases when changing the .formatOptions property.
+         */
+        isoFormatter.formatOptions = [.withInternetDateTime]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "2016-10-08T22:31:00Z")
+        
+        isoFormatter.formatOptions = [.withInternetDateTime, .withSpaceBetweenDateAndTime]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "2016-10-08 22:31:00Z")
+        
+        isoFormatter.formatOptions = .withFullTime
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "22:31:00Z")
+        
+        isoFormatter.formatOptions = .withFullDate
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "2016-10-08")
+        
+        isoFormatter.formatOptions = [.withFullTime, .withFullDate]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "2016-10-08T22:31:00Z")
+        
+        isoFormatter.formatOptions = [.withFullTime, .withFullDate, .withSpaceBetweenDateAndTime]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "2016-10-08 22:31:00Z")
+        
+        isoFormatter.formatOptions = [.withDay, .withTime]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "282T223100")
+        
+        isoFormatter.formatOptions = [.withWeekOfYear, .withTime]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "W40T223100")
+
+        isoFormatter.formatOptions = [.withMonth, .withTime]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "10T223100")
+
+        isoFormatter.formatOptions = [.withDay, .withWeekOfYear, .withTime]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "W4006T223100")
+
+        isoFormatter.formatOptions = [.withDay, .withMonth, .withTime]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "1008T223100")
+
+        isoFormatter.formatOptions = [.withWeekOfYear, .withMonth, .withTime]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "10W40T223100")
+
+        isoFormatter.formatOptions = [.withWeekOfYear, .withMonth, .withTime, .withColonSeparatorInTime]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "10W40T22:31:00")
+
+        isoFormatter.formatOptions = [.withWeekOfYear, .withMonth, .withTime, .withColonSeparatorInTime, .withSpaceBetweenDateAndTime]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "10W40 22:31:00")
+
+        isoFormatter.formatOptions = [.withWeekOfYear, .withMonth, .withTime, .withColonSeparatorInTime, .withSpaceBetweenDateAndTime, .withDashSeparatorInDate]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "10-W40 22:31:00")
+
+        isoFormatter.formatOptions = [.withDay, .withWeekOfYear]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "W4006")
+
+        isoFormatter.formatOptions = [.withDay, .withMonth]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "1008")
+
+        isoFormatter.formatOptions = [.withWeekOfYear, .withMonth]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "10W40")
+
+        isoFormatter.formatOptions = [.withDay, .withWeekOfYear, .withMonth]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "10W4006")
+
+        isoFormatter.formatOptions = [.withMonth, .withDay, .withWeekOfYear, .withDashSeparatorInDate]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "10-W40-06")
+
+        /*
+         The following tests cover various cases when changing the .formatOptions property with a different TimeZone set.
+         */
+
+        isoFormatter.timeZone = TimeZone(identifier: "PST")
+
+        isoFormatter.formatOptions = [.withInternetDateTime]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "2016-10-08T15:31:00-07:00")
+        
+        isoFormatter.formatOptions = [.withTime, .withTimeZone]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "153100-0700")
+
+        isoFormatter.formatOptions = [.withDay, .withTimeZone]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "282-0700")
+
+        isoFormatter.formatOptions = [.withWeekOfYear, .withTimeZone]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "W40-0700")
+
+        isoFormatter.formatOptions = [.withMonth, .withTimeZone]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "10-0700")
+
+        isoFormatter.formatOptions = [.withDay, .withWeekOfYear, .withTimeZone]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "W4006-0700")
+
+        isoFormatter.formatOptions = [.withDay, .withMonth, .withTimeZone]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "1008-0700")
+
+        isoFormatter.formatOptions = [.withDay, .withWeekOfYear, .withMonth, .withTimeZone]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "10W4006-0700")
+
+        isoFormatter.formatOptions = [.withFullDate, .withTimeZone]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "2016-10-08-0700")
+
+        isoFormatter.formatOptions = [.withFullTime, .withTimeZone]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "15:31:00-07:00")
+
+        isoFormatter.formatOptions = [.withDay, .withWeekOfYear, .withMonth, .withTimeZone, .withColonSeparatorInTimeZone]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "10W4006-07:00")
+
+        isoFormatter.formatOptions = [.withDay, .withWeekOfYear, .withMonth, .withTimeZone, .withColonSeparatorInTimeZone, .withDashSeparatorInDate]
+        XCTAssertEqual(isoFormatter.string(from: someDateTime!), "10-W40-06-07:00")
+        
+    }
+    
+    
+    
+    func test_dateFromString() {
+        
+        let f = ISO8601DateFormatter()
+        var result = f.date(from: "2016-10-08T00:00:00Z")
+        XCTAssertNotNil(result)
+        if let stringResult = result?.description {
+            XCTAssertEqual(stringResult, "2016-10-08 00:00:00 +0000")
+        }
+
+        result = f.date(from: "2016-10-08T00:00:00+0600")
+        XCTAssertNotNil(result)
+        if let stringResult = result?.description {
+            XCTAssertEqual(stringResult, "2016-10-07 18:00:00 +0000")
+        }
+        
+        result = f.date(from: "2016-10-08T00:00:00-0600")
+        XCTAssertNotNil(result)
+        if let stringResult = result?.description {
+            XCTAssertEqual(stringResult, "2016-10-08 06:00:00 +0000")
+        }
+
+        result = f.date(from: "12345")
+        XCTAssertNil(result)
+
+    }
+    
+    
+    
+    func test_stringFromDateClass() {
+        
+        let formatter = DateFormatter()
+        formatter.dateFormat = "yyyy/MM/dd HH:mm zzz"
+        let someDateTime = formatter.date(from: "2016/10/08 22:31 GMT")
+        var timeZone = TimeZone(identifier: "GMT")
+        var formatOptions: ISO8601DateFormatter.Options = [.withInternetDateTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withColonSeparatorInTimeZone]
+
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "2016-10-08T22:31:00Z")
+
+        /*
+         The following tests cover various cases when changing the .formatOptions property.
+         */
+        
+        formatOptions = [.withInternetDateTime]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "2016-10-08T22:31:00Z")
+
+        formatOptions = [.withInternetDateTime, .withSpaceBetweenDateAndTime]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "2016-10-08 22:31:00Z")
+        
+        formatOptions = .withFullTime
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "22:31:00Z")
+
+        formatOptions = .withFullDate
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "2016-10-08")
+
+        formatOptions = [.withFullTime, .withFullDate]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "2016-10-08T22:31:00Z")
+
+        formatOptions = [.withFullTime, .withFullDate, .withSpaceBetweenDateAndTime]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "2016-10-08 22:31:00Z")
+
+        formatOptions = [.withDay, .withTime]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "282T223100")
+
+        formatOptions = [.withWeekOfYear, .withTime]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "W40T223100")
+
+        formatOptions = [.withMonth, .withTime]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "10T223100")
+
+        formatOptions = [.withDay, .withWeekOfYear, .withTime]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "W4006T223100")
+
+        formatOptions = [.withDay, .withMonth, .withTime]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "1008T223100")
+
+        formatOptions = [.withWeekOfYear, .withMonth, .withTime]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "10W40T223100")
+
+        formatOptions = [.withWeekOfYear, .withMonth, .withTime, .withColonSeparatorInTime]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "10W40T22:31:00")
+
+        formatOptions = [.withWeekOfYear, .withMonth, .withTime, .withColonSeparatorInTime, .withSpaceBetweenDateAndTime]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "10W40 22:31:00")
+
+        formatOptions = [.withWeekOfYear, .withMonth, .withTime, .withColonSeparatorInTime, .withSpaceBetweenDateAndTime, .withDashSeparatorInDate]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "10-W40 22:31:00")
+
+        formatOptions = [.withDay, .withWeekOfYear]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "W4006")
+
+        formatOptions = [.withDay, .withMonth]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "1008")
+
+        formatOptions = [.withWeekOfYear, .withMonth]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "10W40")
+
+        formatOptions = [.withDay, .withWeekOfYear, .withMonth]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "10W4006")
+
+        formatOptions = [.withMonth, .withDay, .withWeekOfYear, .withDashSeparatorInDate]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "10-W40-06")
+
+        /*
+         The following tests cover various cases when changing the .formatOptions property with a different TimeZone set.
+         */
+
+        timeZone = TimeZone(identifier: "PST")
+        
+        formatOptions = [.withInternetDateTime]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "2016-10-08T15:31:00-07:00")
+
+        formatOptions = [.withTime, .withTimeZone]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "153100-0700")
+
+        formatOptions = [.withDay, .withTimeZone]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "282-0700")
+
+        formatOptions = [.withWeekOfYear, .withTimeZone]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "W40-0700")
+
+        formatOptions = [.withMonth, .withTimeZone]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "10-0700")
+
+        formatOptions = [.withDay, .withWeekOfYear, .withTimeZone]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "W4006-0700")
+
+        formatOptions = [.withDay, .withMonth, .withTimeZone]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "1008-0700")
+
+        formatOptions = [.withDay, .withWeekOfYear, .withMonth, .withTimeZone]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "10W4006-0700")
+
+        formatOptions = [.withFullDate, .withTimeZone]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "2016-10-08-0700")
+
+        formatOptions = [.withFullTime, .withTimeZone]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "15:31:00-07:00")
+
+        formatOptions = [.withDay, .withWeekOfYear, .withMonth, .withTimeZone, .withColonSeparatorInTimeZone]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "10W4006-07:00")
+
+        formatOptions = [.withDay, .withWeekOfYear, .withMonth, .withTimeZone, .withColonSeparatorInTimeZone, .withDashSeparatorInDate]
+        XCTAssertEqual(ISO8601DateFormatter.string(from: someDateTime!, timeZone: timeZone!, formatOptions: formatOptions), "10-W40-06-07:00")
+  
+    }
+
+}
diff --git a/TestFoundation/TestNSISO8601DateFormatter.swift b/TestFoundation/TestNSISO8601DateFormatter.swift
deleted file mode 100644
index ba52258..0000000
--- a/TestFoundation/TestNSISO8601DateFormatter.swift
+++ /dev/null
@@ -1,28 +0,0 @@
-// This source file is part of the Swift.org open source project
-//
-// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
-// Licensed under Apache License v2.0 with Runtime Library Exception
-//
-// See http://swift.org/LICENSE.txt for license information
-// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-//
-
-#if DEPLOYMENT_RUNTIME_OBJC || os(Linux)
-    import Foundation
-    import XCTest
-#else
-    import SwiftFoundation
-    import SwiftXCTest
-#endif
-
-class TestNSISO8601DateFormatter: XCTestCase {
-    
-    let DEFAULT_LOCALE = "en_US"
-    let DEFAULT_TIMEZONE = "GMT"
-    
-    static var allTests : [(String, (TestNSISO8601DateFormatter) -> () throws -> Void)] {
-        return [
-
-        ]
-    }
-}
diff --git a/TestFoundation/main.swift b/TestFoundation/main.swift
index 8fa08ff..a1993fc 100644
--- a/TestFoundation/main.swift
+++ b/TestFoundation/main.swift
@@ -43,6 +43,7 @@
     testCase(TestNSHTTPCookieStorage.allTests),
     testCase(TestNSIndexPath.allTests),
     testCase(TestNSIndexSet.allTests),
+    testCase(TestISO8601DateFormatter.allTests),
     testCase(TestNSJSONSerialization.allTests),
     testCase(TestNSKeyedArchiver.allTests),
     testCase(TestNSKeyedUnarchiver.allTests),
@@ -94,6 +95,5 @@
     testCase(TestProgress.allTests),
     testCase(TestObjCRuntime.allTests),
     testCase(TestNotification.allTests),
-    testCase(TestNSISO8601DateFormatter.allTests),
     testCase(TestMassFormatter.allTests),
 ])
diff --git a/build.py b/build.py
index 9d4e4e1..c98850c 100644
--- a/build.py
+++ b/build.py
@@ -346,6 +346,7 @@
 	'Foundation/NSHTTPCookieStorage.swift',
 	'Foundation/NSIndexPath.swift',
 	'Foundation/NSIndexSet.swift',
+	'Foundation/ISO8601DateFormatter.swift',
 	'Foundation/NSJSONSerialization.swift',
 	'Foundation/NSKeyedCoderOldStyleArray.swift',
 	'Foundation/NSKeyedArchiver.swift',