Skip to content

Commit 3a857e0

Browse files
committed
Merge remote-tracking branch 'origin/master' into swift-4.0-branch
2 parents 22c4d63 + 9b4cebe commit 3a857e0

File tree

4 files changed

+232
-0
lines changed

4 files changed

+232
-0
lines changed

Diff for: Foundation/Calendar.swift

+33
Original file line numberDiff line numberDiff line change
@@ -1189,3 +1189,36 @@ extension Calendar: _ObjectTypeBridgeable {
11891189
return result!
11901190
}
11911191
}
1192+
1193+
extension Calendar : Codable {
1194+
private enum CodingKeys : Int, CodingKey {
1195+
case identifier
1196+
case locale
1197+
case timeZone
1198+
case firstWeekday
1199+
case minimumDaysInFirstWeek
1200+
}
1201+
1202+
public init(from decoder: Decoder) throws {
1203+
let container = try decoder.container(keyedBy: CodingKeys.self)
1204+
let identifierString = try container.decode(String.self, forKey: .identifier)
1205+
let identifier = Calendar._fromNSCalendarIdentifier(NSCalendar.Identifier(rawValue: identifierString))
1206+
self.init(identifier: identifier)
1207+
1208+
self.locale = try container.decodeIfPresent(Locale.self, forKey: .locale)
1209+
self.timeZone = try container.decode(TimeZone.self, forKey: .timeZone)
1210+
self.firstWeekday = try container.decode(Int.self, forKey: .firstWeekday)
1211+
self.minimumDaysInFirstWeek = try container.decode(Int.self, forKey: .minimumDaysInFirstWeek)
1212+
}
1213+
1214+
public func encode(to encoder: Encoder) throws {
1215+
var container = encoder.container(keyedBy: CodingKeys.self)
1216+
1217+
let identifier = Calendar._toNSCalendarIdentifier(self.identifier).rawValue
1218+
try container.encode(identifier, forKey: .identifier)
1219+
try container.encode(self.locale, forKey: .locale)
1220+
try container.encode(self.timeZone, forKey: .timeZone)
1221+
try container.encode(self.firstWeekday, forKey: .firstWeekday)
1222+
try container.encode(self.minimumDaysInFirstWeek, forKey: .minimumDaysInFirstWeek)
1223+
}
1224+
}

Diff for: Foundation/DateComponents.swift

+79
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,82 @@ extension DateComponents : _ObjectTypeBridgeable {
341341
}
342342
}
343343

344+
extension DateComponents : Codable {
345+
private enum CodingKeys : Int, CodingKey {
346+
case calendar
347+
case timeZone
348+
case era
349+
case year
350+
case month
351+
case day
352+
case hour
353+
case minute
354+
case second
355+
case nanosecond
356+
case weekday
357+
case weekdayOrdinal
358+
case quarter
359+
case weekOfMonth
360+
case weekOfYear
361+
case yearForWeekOfYear
362+
}
363+
364+
public init(from decoder: Decoder) throws {
365+
let container = try decoder.container(keyedBy: CodingKeys.self)
366+
let calendar = try container.decodeIfPresent(Calendar.self, forKey: .calendar)
367+
let timeZone = try container.decodeIfPresent(TimeZone.self, forKey: .timeZone)
368+
let era = try container.decodeIfPresent(Int.self, forKey: .era)
369+
let year = try container.decodeIfPresent(Int.self, forKey: .year)
370+
let month = try container.decodeIfPresent(Int.self, forKey: .month)
371+
let day = try container.decodeIfPresent(Int.self, forKey: .day)
372+
let hour = try container.decodeIfPresent(Int.self, forKey: .hour)
373+
let minute = try container.decodeIfPresent(Int.self, forKey: .minute)
374+
let second = try container.decodeIfPresent(Int.self, forKey: .second)
375+
let nanosecond = try container.decodeIfPresent(Int.self, forKey: .nanosecond)
376+
377+
let weekday = try container.decodeIfPresent(Int.self, forKey: .weekday)
378+
let weekdayOrdinal = try container.decodeIfPresent(Int.self, forKey: .weekdayOrdinal)
379+
let quarter = try container.decodeIfPresent(Int.self, forKey: .quarter)
380+
let weekOfMonth = try container.decodeIfPresent(Int.self, forKey: .weekOfMonth)
381+
let weekOfYear = try container.decodeIfPresent(Int.self, forKey: .weekOfYear)
382+
let yearForWeekOfYear = try container.decodeIfPresent(Int.self, forKey: .yearForWeekOfYear)
383+
384+
self.init(calendar: calendar,
385+
timeZone: timeZone,
386+
era: era,
387+
year: year,
388+
month: month,
389+
day: day,
390+
hour: hour,
391+
minute: minute,
392+
second: second,
393+
nanosecond: nanosecond,
394+
weekday: weekday,
395+
weekdayOrdinal: weekdayOrdinal,
396+
quarter: quarter,
397+
weekOfMonth: weekOfMonth,
398+
weekOfYear: weekOfYear,
399+
yearForWeekOfYear: yearForWeekOfYear)
400+
}
401+
402+
public func encode(to encoder: Encoder) throws {
403+
var container = encoder.container(keyedBy: CodingKeys.self)
404+
try container.encodeIfPresent(self.calendar, forKey: .calendar)
405+
try container.encodeIfPresent(self.timeZone, forKey: .timeZone)
406+
try container.encodeIfPresent(self.era, forKey: .era)
407+
try container.encodeIfPresent(self.year, forKey: .year)
408+
try container.encodeIfPresent(self.month, forKey: .month)
409+
try container.encodeIfPresent(self.day, forKey: .day)
410+
try container.encodeIfPresent(self.hour, forKey: .hour)
411+
try container.encodeIfPresent(self.minute, forKey: .minute)
412+
try container.encodeIfPresent(self.second, forKey: .second)
413+
try container.encodeIfPresent(self.nanosecond, forKey: .nanosecond)
414+
415+
try container.encodeIfPresent(self.weekday, forKey: .weekday)
416+
try container.encodeIfPresent(self.weekdayOrdinal, forKey: .weekdayOrdinal)
417+
try container.encodeIfPresent(self.quarter, forKey: .quarter)
418+
try container.encodeIfPresent(self.weekOfMonth, forKey: .weekOfMonth)
419+
try container.encodeIfPresent(self.weekOfYear, forKey: .weekOfYear)
420+
try container.encodeIfPresent(self.yearForWeekOfYear, forKey: .yearForWeekOfYear)
421+
}
422+
}

Diff for: Foundation/TimeZone.swift

+23
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,26 @@ extension TimeZone {
283283
return result!
284284
}
285285
}
286+
287+
extension TimeZone : Codable {
288+
private enum CodingKeys : Int, CodingKey {
289+
case identifier
290+
}
291+
292+
public init(from decoder: Decoder) throws {
293+
let container = try decoder.container(keyedBy: CodingKeys.self)
294+
let identifier = try container.decode(String.self, forKey: .identifier)
295+
296+
guard let timeZone = TimeZone(identifier: identifier) else {
297+
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath,
298+
debugDescription: "Invalid TimeZone identifier."))
299+
}
300+
301+
self = timeZone
302+
}
303+
304+
public func encode(to encoder: Encoder) throws {
305+
var container = encoder.container(keyedBy: CodingKeys.self)
306+
try container.encode(self.identifier, forKey: .identifier)
307+
}
308+
}

Diff for: TestFoundation/TestCodable.swift

+97
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,100 @@ class TestCodable : XCTestCase {
305305
}
306306
}
307307

308+
// MARK: - TimeZone
309+
lazy var timeZoneValues: [TimeZone] = {
310+
var values = [
311+
TimeZone(identifier: "America/Los_Angeles")!,
312+
TimeZone(identifier: "UTC")!,
313+
]
314+
315+
#if !os(Linux)
316+
// Disabled due to [SR-5598] bug, which occurs on Linux, and breaks
317+
// TimeZone.current == TimeZone(identifier: TimeZone.current.identifier) equality,
318+
// causing encode -> decode -> compare test to fail.
319+
values.append(TimeZone.current)
320+
#endif
321+
322+
return values
323+
}()
324+
325+
func test_TimeZone_JSON() {
326+
for timeZone in timeZoneValues {
327+
expectRoundTripEqualityThroughJSON(for: timeZone)
328+
}
329+
}
330+
331+
// MARK: - Calendar
332+
lazy var calendarValues: [Calendar] = {
333+
var values = [
334+
Calendar(identifier: .gregorian),
335+
Calendar(identifier: .buddhist),
336+
Calendar(identifier: .chinese),
337+
Calendar(identifier: .coptic),
338+
Calendar(identifier: .ethiopicAmeteMihret),
339+
Calendar(identifier: .ethiopicAmeteAlem),
340+
Calendar(identifier: .hebrew),
341+
Calendar(identifier: .iso8601),
342+
Calendar(identifier: .indian),
343+
Calendar(identifier: .islamic),
344+
Calendar(identifier: .islamicCivil),
345+
Calendar(identifier: .japanese),
346+
Calendar(identifier: .persian),
347+
Calendar(identifier: .republicOfChina),
348+
]
349+
350+
#if os(Linux)
351+
// Custom timeZone set to work around [SR-5598] bug, which occurs on Linux, and breaks equality after
352+
// serializing and deserializing TimeZone.current
353+
for index in values.indices {
354+
values[index].timeZone = TimeZone(identifier: "UTC")!
355+
}
356+
#endif
357+
358+
return values
359+
}()
360+
361+
func test_Calendar_JSON() {
362+
for calendar in calendarValues {
363+
expectRoundTripEqualityThroughJSON(for: calendar)
364+
}
365+
}
366+
367+
// MARK: - DateComponents
368+
lazy var dateComponents: Set<Calendar.Component> = [
369+
.era,
370+
.year,
371+
.month,
372+
.day,
373+
.hour,
374+
.minute,
375+
.second,
376+
.weekday,
377+
.weekdayOrdinal,
378+
.weekOfMonth,
379+
.weekOfYear,
380+
.yearForWeekOfYear,
381+
.timeZone,
382+
.calendar,
383+
// [SR-5576] Disabled due to a bug in Calendar.dateComponents(_:from:) which crashes on Darwin and returns
384+
// invalid values on Linux if components include .nanosecond or .quarter.
385+
// .nanosecond,
386+
// .quarter,
387+
]
388+
389+
func test_DateComponents_JSON() {
390+
#if os(Linux)
391+
var calendar = Calendar(identifier: .gregorian)
392+
// Custom timeZone set to work around [SR-5598] bug, which occurs on Linux, and breaks equality after
393+
// serializing and deserializing TimeZone.current
394+
calendar.timeZone = TimeZone(identifier: "UTC")!
395+
#else
396+
let calendar = Calendar(identifier: .gregorian)
397+
#endif
398+
399+
let components = calendar.dateComponents(dateComponents, from: Date(timeIntervalSince1970: 1501283776))
400+
expectRoundTripEqualityThroughJSON(for: components)
401+
}
308402
}
309403

310404
extension TestCodable {
@@ -323,6 +417,9 @@ extension TestCodable {
323417
("test_CGSize_JSON", test_CGSize_JSON),
324418
("test_CGRect_JSON", test_CGRect_JSON),
325419
("test_CharacterSet_JSON", test_CharacterSet_JSON),
420+
("test_TimeZone_JSON", test_TimeZone_JSON),
421+
("test_Calendar_JSON", test_Calendar_JSON),
422+
("test_DateComponents_JSON", test_DateComponents_JSON),
326423
]
327424
}
328425
}

0 commit comments

Comments
 (0)