「ソフトウェア設計のトレードオフと誤り」にある日付の演算に伴う注意点をswiftで検証する
「ソフトウェア設計のトレードオフと誤り」という本を読んでいます.
cf. O’Reilly Japan - ソフトウェア設計のトレードオフと誤り
この本の「7章 日付と時間のデータを効率よく扱う」に日付の演算に関する実装の注意点が書いてあり,swiftだとどのような挙動になるのか,学習のためにコードを書いてみました.
検証用のテストコード
import XCTest
@testable import swift_date_learning
final class swift_date_learningTests: XCTestCase {
let dateFormatter = {
let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" return dateFormatter }()
func test_1_1月31日の2ヶ月後は3月31日() throws {
let endOfJanuary = Calendar.current.date(from: DateComponents(year: 2024, month: 1, day: 31))!
let endOfJanuaryPlus2Months = Calendar.current.date(byAdding: .month, value: 2, to: endOfJanuary)!
XCTAssertEqual(dateFormatter.string(from: endOfJanuaryPlus2Months), "2024-03-31")
}
func test_2_1月31日の1ヶ月後の1ヶ月後は3月29日() throws {
let endOfJanuary = Calendar.current.date(from: DateComponents(year: 2024, month: 1, day: 31))!
let endOfJanuaryPlus1Month = Calendar.current.date(byAdding: .month, value: 1, to: endOfJanuary)!
let endOfJanuaryPlus1MonthPlus1Month = Calendar.current.date(byAdding: .month, value: 1, to: endOfJanuaryPlus1Month)!
XCTAssertEqual(dateFormatter.string(from: endOfJanuaryPlus1MonthPlus1Month), "2024-03-29")
}
func test_3_1月31日の1ヶ月後は2月29日() throws {
let endOfJanuary = Calendar.current.date(from: DateComponents(year: 2024, month: 1, day: 31))!
let endOfJanuaryPlus1Month = Calendar.current.date(byAdding: .month, value: 1, to: endOfJanuary)!
XCTAssertEqual(dateFormatter.string(from: endOfJanuaryPlus1Month), "2024-02-29")
}
func test_4_2月29日の1ヶ月前は1月29日() throws {
let endOfFebrary = Calendar.current.date(from: DateComponents(year: 2024, month: 2, day: 29))!
let endOfFebraryMinus1Month = Calendar.current.date(byAdding: .month, value: -1, to: endOfFebrary)!
XCTAssertEqual(dateFormatter.string(from: endOfFebraryMinus1Month), "2024-01-29")
}
}
テスト実行結果
$ swift test 2>/dev/null | xcpretty
All tests
Test Suite swift-date-learningPackageTests.xctest started
swift_date_learningTests
✓ test_1_1月31日の2ヶ月後は3月31日 (0.004 seconds)
✓ test_2_1月31日の1ヶ月後の1ヶ月後は3月29日 (0.000 seconds)
✓ test_3_1月31日の1ヶ月後は2月29日 (0.000 seconds)
✓ test_4_2月29日の1ヶ月前は1月29日 (0.000 seconds)
Executed 4 tests, with 0 failures (0 unexpected) in 0.004 (0.005) seconds
2ヶ月を加算した日付と,1ヶ月を加算した日付にさらに1ヶ月を加算した日付は異なる場合がある
1月31日の2ヶ月後は3月31日になります. しかし,1月31日に1ヶ月を加算した日付(今年は閏年なので2月29日)にさらに1ヶ月を加算した場合,3月29日になります. これは1,2つ目のテストコードです.
1ヶ月を加算した日付から,1ヶ月を減算しても元の日付にはならない場合がある
1月31日の1ヶ月後は,今年は閏年なので2月29日になります. しかし,2月29日の1ヶ月前は1月29日になります. これは3,4つ目のテストコードです.