standing the test of time: the date provider pattern
TRANSCRIPT
![Page 1: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/1.jpg)
STANDING THE TEST OF TIMETHE DATE PROVIDER PATTERN
DEREK LEE | TOKYO IOS MEETUP APRIL 2017
![Page 2: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/2.jpg)
!
![Page 3: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/3.jpg)
CALENDAR
![Page 4: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/4.jpg)
TO DO
![Page 5: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/5.jpg)
TRANSPORTATION
![Page 6: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/6.jpg)
SHOPPING
![Page 7: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/7.jpg)
DRUMMING
![Page 8: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/8.jpg)
FLIGHT DEPARTUREHANEDA ✈ OKINAWAAPR-25-2017 7:12PM
![Page 9: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/9.jpg)
HOW MUCH TIME DO I HAVEBEFORE MY DEPARTURE?
![Page 10: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/10.jpg)
LETS START WITH A SIMPLE STRUCTstruct Flight { let flightNumber: String let departureCityCode: String let departureDateTime: Date let arrivalCityCode: String let arrivalDateTime: Date}
![Page 11: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/11.jpg)
WE CAN EASILY INITIALIZE WITH SOME DATAlet tripHome = Flight( flightNumber: "JAL925", departureCityCode: "HND", departureDateTime: Date( timeIntervalSince1970: 1493115120 // 4-25-2017 19:12 ), arrivalCityCode: "OKA", arrivalDateTime: Date( timeIntervalSince1970: 1493125920 // 4-25-2017 22:12 ))
![Page 12: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/12.jpg)
CALCULATING THE REMAINING TIME IS EASY...?func timeRemainingUntilDeparture() -> TimeInterval { let departureTimeInterval = departureDateTime.timeIntervalSinceNow
let currentTimeInterval = Date().timeIntervalSinceNow
return departureTimeInterval - currentTimeInterval}
![Page 13: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/13.jpg)
AND WITH SOME QUICK FORMATTING...func formatTimeInterval(timeInterval: TimeInterval) -> String { let d = Int(timeInterval / 86400) let h = Int(timeInterval / 3600) % 24 let m = Int(timeInterval / 60) % 60 let s = Int(timeInterval) % 60
return "\(d) days, \(h) hours, \(m) minutes, and \(s) seconds"}
![Page 14: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/14.jpg)
WE CAN EASILY OUTPUT THE REMAINING TIMElet timeIntervalUntilDeparture = tripHome.timeRemainingUntilDeparture()
let formattedRemainingTime = formatTimeInterval( timeInterval: timeIntervalUntilDeparture)
print("Time until departure: " + formattedRemainingTime)
TIME UNTIL DEPARTURE: 25 DAYS, 19 HOURS,45 MINUTES, AND 50 SECONDS
![Page 15: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/15.jpg)
!
![Page 16: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/16.jpg)
!HMMM....
![Page 17: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/17.jpg)
!MAYBE WE SHOULD WRITE A TEST FOR THIS
![Page 18: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/18.jpg)
func testTimeRemainingUntilDeparture_returnsCorrectTimeInterval() {
}
![Page 19: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/19.jpg)
func testTimeRemainingUntilDeparture_returnsCorrectTimeInterval() { let tripHome = Flight( flightNumber: "JAL925", departureCityCode: "HND", departureDateTime: Date(timeIntervalSince1970: 1493115120), arrivalCityCode: "OKA", arrivalDateTime: Date(timeIntervalSince1970: 1493125920) )
}
![Page 20: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/20.jpg)
func testTimeRemainingUntilDeparture_returnsCorrectTimeInterval() { let tripHome = Flight( flightNumber: "JAL925", departureCityCode: "HND", departureDateTime: Date(timeIntervalSince1970: 1493115120), arrivalCityCode: "OKA", arrivalDateTime: Date(timeIntervalSince1970: 1493125920) )
let remainingTime = tripHome.timeRemainingUntilDeparture()
}
![Page 21: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/21.jpg)
func testTimeRemainingUntilDeparture_returnsCorrectTimeInterval() { let tripHome = Flight( flightNumber: "JAL925", departureCityCode: "HND", departureDateTime: Date(timeIntervalSince1970: 1493115120), arrivalCityCode: "OKA", arrivalDateTime: Date(timeIntervalSince1970: 1493125920) )
let remainingTime = tripHome.timeRemainingUntilDeparture()
XCTAssertEqual(Int(remainingTime), ???)}
![Page 22: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/22.jpg)
func testTimeRemainingUntilDeparture_returnsCorrectTimeInterval() { let tripHome = Flight( flightNumber: "JAL925", departureCityCode: "HND", departureDateTime: Date(timeIntervalSince1970: 1493115120), arrivalCityCode: "OKA", arrivalDateTime: Date(timeIntervalSince1970: 1493125920) )
let remainingTime = tripHome.timeRemainingUntilDeparture()
XCTAssertEqual(Int(remainingTime), 2144133)}
![Page 23: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/23.jpg)
WE RUN THE TEST AND...
![Page 24: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/24.jpg)
![Page 25: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/25.jpg)
HMM.
![Page 26: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/26.jpg)
WELL... LETS UPDATE THE TEST THEN
![Page 27: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/27.jpg)
func testTimeRemainingUntilDeparture_returnsCorrectTimeInterval() { let tripHome = Flight( flightNumber: "JAL925", departureCityCode: "HND", departureDateTime: Date(timeIntervalSince1970: 1493115120), arrivalCityCode: "OKA", arrivalDateTime: Date(timeIntervalSince1970: 1493125920) )
let remainingTime = tripHome.timeRemainingUntilDeparture()
XCTAssertEqual(Int(remainingTime), 2144113)}
![Page 28: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/28.jpg)
![Page 29: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/29.jpg)
!
![Page 30: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/30.jpg)
WE NEED MORE CONTROL
![Page 31: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/31.jpg)
HERE'S OUR CODE:func timeRemainingUntilDeparture() -> TimeInterval { let departureTimeInterval = departureDateTime.timeIntervalSinceNow
let currentTimeInterval = Date().timeIntervalSinceNow
return departureTimeInterval - currentTimeInterval}
![Page 32: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/32.jpg)
WHAT IS IT THAT WE NEED MORE CONTROL OVER?func timeRemainingUntilDeparture() -> TimeInterval { let departureTimeInterval = departureDateTime.timeIntervalSinceNow
let currentTimeInterval = Date().timeIntervalSinceNow
return departureTimeInterval - currentTimeInterval}
![Page 33: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/33.jpg)
THE CURRENT TIMElet currentTimeInterval = Date().timeIntervalSinceNow
![Page 34: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/34.jpg)
THEREFORE, THE CURRENT TIME IS OUR DEPENDENCY
![Page 35: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/35.jpg)
SO HOW CAN WE SOLVE THIS PROBLEM?
![Page 36: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/36.jpg)
USING A DATE PROVIDER
![Page 37: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/37.jpg)
DATE PROVIDER:AN OBJECT THAT WE CAN ASK TO GIVE US
THE CURRENT DATE & TIME
![Page 38: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/38.jpg)
BACK TO OUR TEST THEN...
![Page 39: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/39.jpg)
FIRST WE NEED TO PASS OUR DEPENDENCY INlet remainingTime = tripHome.timeRemainingUntilDeparture()
↓let remainingTime = tripHome.timeRemainingUntilDeparture( dateProvider: ???)
![Page 40: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/40.jpg)
THIS CHANGES OUR METHOD'S DECLARATIONfunc timeRemainingUntilDeparture() -> TimeInterval
↓func timeRemainingUntilDeparture(dateProvider: DateProvider) -> TimeInterval
![Page 41: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/41.jpg)
WHICH MEANS WE'LL NEED A PROTOCOLprotocol DateProvider {
}
![Page 42: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/42.jpg)
... AND A WAY TO GET THE CURRENT DATE/TIMEprotocol DateProvider { func currentDateTime() -> Date}
![Page 43: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/43.jpg)
WE'LL CREATE A FAKE OBJECT FOR TESTINGprotocol DateProvider { func currentDateTime() -> Date}
class FakeDateProvider: DateProvider {
func currentDateTime() -> Date {
}}
![Page 44: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/44.jpg)
WHAT SHOULD THIS FUNCTION RETURN?protocol DateProvider { func currentDateTime() -> Date}
class FakeDateProvider: DateProvider {
func currentDateTime() -> Date { return ??? }}
![Page 45: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/45.jpg)
METHOD NAME + "_RETURNVALUE"protocol DateProvider { func currentDateTime() -> Date}
class FakeDateProvider: DateProvider {
func currentDateTime() -> Date { return currentDateTime_returnValue }}
![Page 46: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/46.jpg)
WHICH WE CAN DEFINE AND INITIALIZEprotocol DateProvider { func currentDateTime() -> Date}
class FakeDateProvider: DateProvider { var currentDateTime_returnValue = Date()
func currentDateTime() -> Date { return currentDateTime_returnValue }}
![Page 47: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/47.jpg)
BACK TO OUR TEST... WE NEED TO PASS IN OUR FAKElet remainingTime = tripHome.timeRemainingUntilDeparture( dateProvider: ???)
![Page 48: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/48.jpg)
BACK TO OUR TEST... WE NEED TO PASS IN OUR FAKElet remainingTime = tripHome.timeRemainingUntilDeparture( dateProvider: ???)
↓let fakeDateProvider = FakeDateProvider()let remainingTime = tripHome.timeRemainingUntilDeparture( dateProvider: fakeDateProvider)
![Page 49: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/49.jpg)
NEXT IS THE MOST IMPORTANT STEP
![Page 50: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/50.jpg)
SET THE VALUE YOU WANT THE FAKE TO RETURNfakeDateProvider.currentDateTime_returnValue = Date( timeIntervalSince1970: 1493028720 // 4-24-2017 19:12)
![Page 51: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/51.jpg)
AND NOW WE CAN ADJUST OUR EXPECTATIONXCTAssertEqual(Int(remainingTime), 86400) // 24 Hours Prior
![Page 52: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/52.jpg)
OUR UPDATED TEST:
![Page 53: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/53.jpg)
func testTimeRemainingUntilDeparture_returnsCorrectTimeInterval() { let tripHome = Flight( flightNumber: "JAL925", departureCityCode: "HND", departureDateTime: Date(timeIntervalSince1970: 1493115120), arrivalCityCode: "OKA", arrivalDateTime: Date(timeIntervalSince1970: 1493125920) )
let fakeDateProvider = FakeDateProvider() fakeDateProvider.currentDateTime_returnValue = Date(timeIntervalSince1970: 1493028720)
let remainingTime = tripHome.timeRemainingUntilDeparture(dateProvider: fakeDateProvider)
XCTAssertEqual(Int(remainingTime), 86400)}
![Page 54: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/54.jpg)
WHAT ABOUT THE ACTUAL IMPLEMENTATION?
![Page 55: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/55.jpg)
THE DEFAULT IMPLEMENTATION IS EASYprotocol DateProvider { func currentDateTime() -> Date}
![Page 56: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/56.jpg)
JUST RETURN THE CURRENT DATE & TIMEprotocol DateProvider { func currentDateTime() -> Date}
struct DefaultDateProvider: DateProvider { func currentDateTime() -> Date { return Date() }}
![Page 57: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/57.jpg)
AND PASS IN THE DEFAULT TO YOUR ACTUAL CALL SITElet timeIntervalUntilDeparture = tripHome.timeRemainingUntilDeparture( dateProvider: DefaultDateProvider())
let formattedRemainingTime = formatTimeInterval( timeInterval: timeIntervalUntilDeparture)
print("Time until departure: " + formattedRemainingTime + " (" + String(timeIntervalUntilDeparture) + ")")
![Page 58: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/58.jpg)
!
![Page 59: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/59.jpg)
...
![Page 60: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/60.jpg)
THIS IS ACTUALLY DEPENDENCY INJECTION
![Page 61: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/61.jpg)
SUMMARY
▸ Identified our dependency (current date/time)▸ Created a protocol for it▸ Extracted it from our method
▸ Passed in the actual value at runtime▸ Created a fake we could use for testing
![Page 62: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/62.jpg)
THANK YOU!@DEREKLEEROCK
GITHUB.COM/DEREKLEEROCK
![Page 63: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/63.jpg)
Q&A: WHAT DO YOU USE FOR GETTING EPOCH DATES AND TIMES?
HTTPS://WWW.EPOCHCONVERTER.COM/MAC TERMINAL "DATE" COMMAND:
$ date -r 1 # Outputs Thu Jan 1 09:00:01 JST 1970
$ date -r 1493125920 # Outputs Tue Apr 25 22:12:00 JST 2017
$ date +%s # Outputs current date/time in # of seconds
![Page 64: Standing the Test of Time: The Date Provider Pattern](https://reader034.vdocuments.mx/reader034/viewer/2022052514/58ed23f31a28abb32d8b45ff/html5/thumbnails/64.jpg)
SOURCE CODE IS AVAILABLE ON GITHUB:
https://github.com/derekleerock/StandingTheTestOfTime