Skip to content

Commit

Permalink
change to use private enum
Browse files Browse the repository at this point in the history
  • Loading branch information
5d committed Dec 1, 2023
1 parent ec693bf commit b37416c
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 67 deletions.
134 changes: 71 additions & 63 deletions Amplify/Categories/DataStore/Model/Temporal/TimeZone+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,88 +13,96 @@ extension TimeZone {
private static let iso8601TimeZoneHHMMRegex = try? NSRegularExpression(pattern: "^[+-]\\d{2}\\d{2}$")
private static let iso8601TimeZoneHHRegex = try? NSRegularExpression(pattern: "^[+-]\\d{2}$")

/// https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators
@usableFromInline
internal init?(iso8601DateString: String) {
func hasMatch(regex: NSRegularExpression?, str: String) -> Bool {
return regex.flatMap {
$0.firstMatch(in: str, range: NSRange(location: 0, length: str.count))
} != nil
}
// <time>Z
func hasSuffixZ() -> Bool {
return iso8601DateString.hasSuffix("Z")
}
private enum ISO8601TimeZonePart {
case utc
case hhmm(hours: Int, minutes: Int)
case hh(hours: Int)

// <time>±hh:mm
func hasSuffixHHColonMM() -> String? {
if iso8601DateString.count > 6 {
let tz = String(iso8601DateString.dropFirst(iso8601DateString.count - 6))
if hasMatch(regex: TimeZone.iso8601TimeZoneHHColonMMRegex, str: tz) {
return tz
}
init?(iso8601DateString: String) {
func hasMatch(regex: NSRegularExpression?, str: String) -> Bool {
return regex.flatMap {
$0.firstMatch(in: str, range: NSRange(location: 0, length: str.count))
} != nil
}
return nil
}

// <time>±hhmm
func hasSuffixHHMM() -> String? {
if iso8601DateString.count > 5 {
let tz = String(iso8601DateString.dropFirst(iso8601DateString.count - 5))
if hasMatch(regex: TimeZone.iso8601TimeZoneHHMMRegex, str: tz) {
return tz
// <time>±hh:mm
func suffixHHColonMM() -> String? {
if iso8601DateString.count > 6 {
let tz = String(iso8601DateString.dropFirst(iso8601DateString.count - 6))
if hasMatch(regex: TimeZone.iso8601TimeZoneHHColonMMRegex, str: tz) {
return tz
}
}
return nil
}
return nil
}

// <time>±hh
func hasSuffixHH() -> String? {
if iso8601DateString.count > 3 {
let tz = String(iso8601DateString.dropFirst(iso8601DateString.count - 3))
if hasMatch(regex: TimeZone.iso8601TimeZoneHHRegex, str: tz) {
return tz
// <time>±hhmm
func suffixHHMM() -> String? {
if iso8601DateString.count > 5 {
let tz = String(iso8601DateString.dropFirst(iso8601DateString.count - 5))
if hasMatch(regex: TimeZone.iso8601TimeZoneHHMMRegex, str: tz) {
return tz
}
}
return nil
}
return nil
}

if hasSuffixZ() {
self.init(abbreviation: "UTC")
return
}

if let tz = hasSuffixHHColonMM() {
guard let hours = Int(tz.dropLast(3)),
let mins = Int(tz.dropFirst(4))
else {
// <time>±hh
func suffixHH() -> String? {
if iso8601DateString.count > 3 {
let tz = String(iso8601DateString.dropFirst(iso8601DateString.count - 3))
if hasMatch(regex: TimeZone.iso8601TimeZoneHHRegex, str: tz) {
return tz
}
}
return nil
}

self.init(secondsFromGMT: hours * 60 * 60 + (hours > 0 ? 1 : -1) * mins * 60)
return
}
if iso8601DateString.hasPrefix("Z") { // <time>Z
self = .utc
return
}

if let tz = hasSuffixHHMM() {
guard let hours = Int(tz.dropLast(2)),
let mins = Int(tz.dropFirst(3))
else {
return nil
if let tz = suffixHHColonMM(),
let hours = Int(tz.dropLast(3)),
let minutes = Int(tz.dropFirst(4))
{
self = .hhmm(hours: hours, minutes: minutes)
return
}

self.init(secondsFromGMT: hours * 60 * 60 + (hours > 0 ? 1 : -1) * mins * 60)
return
}
if let tz = suffixHHMM(),
let hours = Int(tz.dropLast(2)),
let minutes = Int(tz.dropFirst(3))
{
self = .hhmm(hours: hours, minutes: minutes)
return
}

if let tz = hasSuffixHH() {
guard let hours = Int(tz) else {
return nil
if let tz = suffixHH(),
let hours = Int(tz)
{
self = .hh(hours: hours)
return
}

self.init(secondsFromGMT: hours * 60 * 60)
return
return nil
}
}

return nil
/// https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators
@usableFromInline
internal init?(iso8601DateString: String) {
switch ISO8601TimeZonePart(iso8601DateString: iso8601DateString) {
case .some(.utc):
self.init(abbreviation: "UTC")
case let .some(.hh(hours: hours)):
self.init(secondsFromGMT: hours * 60 * 60)
case let .some(.hhmm(hours: hours, minutes: minutes)):
self.init(secondsFromGMT: hours * 60 * 60 +
(hours > 0 ? 1 : -1) * minutes * 60)
case .none:
return nil
}
}
}
10 changes: 6 additions & 4 deletions AmplifyTests/CategoryTests/DataStore/TemporalTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ class TemporalTests: XCTestCase {
/// - Time should be parsed with utc time zone
func testConvertToIso8601String() {
do {
let datetime = try Temporal.DateTime(iso8601String: "2023-11-30T11:00:00-08:00")
XCTAssertEqual(datetime.iso8601String, "2023-11-30T11:00:00.000-08:00")
let datetime1 = try Temporal.DateTime(iso8601String: "2023-11-30T11:00:00.000-08:00")
XCTAssertEqual(datetime1.iso8601String, "2023-11-30T11:00:00.000-08:00")
let datetime = try Temporal.DateTime(iso8601String: "2023-11-30T11:04:03-08:00")
XCTAssertEqual(datetime.iso8601String, "2023-11-30T11:04:03.000-08:00")
let datetime1 = try Temporal.DateTime(iso8601String: "2023-11-30T11:04:03.322-0800")
XCTAssertEqual(datetime1.iso8601String, "2023-11-30T11:04:03.322-08:00")
let datetime2 = try Temporal.DateTime(iso8601String: "2023-11-30T14:09:27.128-0830")
XCTAssertEqual(datetime2.iso8601String, "2023-11-30T14:09:27.128-08:30")
let date = try Temporal.Date(iso8601String: "2023-11-30-08:00")
XCTAssertEqual(date.iso8601String, "2023-11-30Z")
let time = try Temporal.Time(iso8601String: "11:00:00.000-08:00")
Expand Down

0 comments on commit b37416c

Please sign in to comment.