diff --git a/ACKategories.xcodeproj/project.pbxproj b/ACKategories.xcodeproj/project.pbxproj index 2a49fc86..732af31f 100644 --- a/ACKategories.xcodeproj/project.pbxproj +++ b/ACKategories.xcodeproj/project.pbxproj @@ -49,6 +49,8 @@ 6939359D2080AA6100EDA582 /* UIDeviceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6939359C2080AA6100EDA582 /* UIDeviceExtensions.swift */; }; 6939359F2080AB2800EDA582 /* NSMutableParagraphStyleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6939359E2080AB2800EDA582 /* NSMutableParagraphStyleExtensions.swift */; }; 693935A12080AB5A00EDA582 /* UILabelExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693935A02080AB5A00EDA582 /* UILabelExtensions.swift */; }; + 881A82EC21131CEC00267D2E /* DateFormatting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 881A82EB21131CEC00267D2E /* DateFormatting.swift */; }; + 881A82EF21131D8D00267D2E /* DateFormattingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 881A82ED21131D0F00267D2E /* DateFormattingTests.swift */; }; D2FF92C4202BA8DE00C1A129 /* NSAttributedStringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FF92C3202BA8DD00C1A129 /* NSAttributedStringExtensions.swift */; }; /* End PBXBuildFile section */ @@ -137,6 +139,8 @@ 6939359C2080AA6100EDA582 /* UIDeviceExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDeviceExtensions.swift; sourceTree = ""; }; 6939359E2080AB2800EDA582 /* NSMutableParagraphStyleExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSMutableParagraphStyleExtensions.swift; sourceTree = ""; }; 693935A02080AB5A00EDA582 /* UILabelExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UILabelExtensions.swift; sourceTree = ""; }; + 881A82EB21131CEC00267D2E /* DateFormatting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateFormatting.swift; sourceTree = ""; }; + 881A82ED21131D0F00267D2E /* DateFormattingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateFormattingTests.swift; sourceTree = ""; }; D253FF781F0A65610079215C /* ACKategories.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ACKategories.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D2FF92C3202BA8DD00C1A129 /* NSAttributedStringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSAttributedStringExtensions.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -213,6 +217,7 @@ 6925242920D1434A00228289 /* CollectionExtensions.swift */, 69306C492029C48200BBE8F0 /* ConditionalAssignment.swift */, 6925243620D1470B00228289 /* DateExtensions.swift */, + 881A82EB21131CEC00267D2E /* DateFormatting.swift */, 6925242720D142E200228289 /* DictionaryExtensions.swift */, D2FF92C3202BA8DD00C1A129 /* NSAttributedStringExtensions.swift */, 6939359E2080AB2800EDA582 /* NSMutableParagraphStyleExtensions.swift */, @@ -251,6 +256,7 @@ 691F85632029DE5500DA4FAD /* Supporting files */, 6925243320D145F200228289 /* UIStackViewTests.swift */, 6925243820D1471F00228289 /* DateTests.swift */, + 881A82ED21131D0F00267D2E /* DateFormattingTests.swift */, ); name = UnitTests; path = Tests; @@ -441,6 +447,7 @@ 6925243A20D1472300228289 /* DateTests.swift in Sources */, 691F858B202A00E700DA4FAD /* ConditionalAssignmentTests.swift in Sources */, 69306C872029C92B00BBE8F0 /* StringTests.swift in Sources */, + 881A82EF21131D8D00267D2E /* DateFormattingTests.swift in Sources */, 69306C842029C92B00BBE8F0 /* ControlBlocksTests.swift in Sources */, 69306C852029C92B00BBE8F0 /* FoundationTests.swift in Sources */, ); @@ -460,6 +467,7 @@ 69306C522029C48300BBE8F0 /* UIColorExtensions.swift in Sources */, 69306C5B2029C48300BBE8F0 /* UIImageExtensions.swift in Sources */, 69306C592029C48300BBE8F0 /* UIControlEvents.swift in Sources */, + 881A82EC21131CEC00267D2E /* DateFormatting.swift in Sources */, 69306C5A2029C48300BBE8F0 /* StringExtensions.swift in Sources */, 69306C512029C48300BBE8F0 /* UISearchBarExtensions.swift in Sources */, 6925243220D1455F00228289 /* UIStackViewExtensions.swift in Sources */, diff --git a/ACKategories/DateExtensions.swift b/ACKategories/DateExtensions.swift index a17522d5..00f178d9 100644 --- a/ACKategories/DateExtensions.swift +++ b/ACKategories/DateExtensions.swift @@ -18,4 +18,11 @@ extension Date { /// Year from date public var year: Int { return Calendar.current.component(.year, from: self) } + + /// String from date formatted with given template + /// + /// Uses cached date formatter, so no need to worry about performance. See `DateFormatter.cached(for template:)` + public func toString(with template: String) -> String { + return DateFormatter.cached(for: template).string(from: self) + } } diff --git a/ACKategories/DateFormatting.swift b/ACKategories/DateFormatting.swift new file mode 100644 index 00000000..bd09b733 --- /dev/null +++ b/ACKategories/DateFormatting.swift @@ -0,0 +1,26 @@ +// +// DateFormatting.swift +// Skeleton +// +// Created by Jan Misar on 02.08.18. +// + +import Foundation + +/// Date formatters cached for future use +fileprivate var dateFormattersCache = [String: DateFormatter]() + +extension DateFormatter { + + /// Returns existing DateFormatter from cache or creates the new one + public static func cached(for template: String) -> DateFormatter { + if let cachedFormatter = dateFormattersCache[template] { + return cachedFormatter + } else { + let dateFormatter = DateFormatter() + dateFormatter.setLocalizedDateFormatFromTemplate(template) + dateFormattersCache[template] = dateFormatter + return dateFormatter + } + } +} diff --git a/Tests/DateFormattingTests.swift b/Tests/DateFormattingTests.swift new file mode 100644 index 00000000..2ffbc874 --- /dev/null +++ b/Tests/DateFormattingTests.swift @@ -0,0 +1,31 @@ +// +// DateFormattingTests.swift +// ACKategories-Example +// +// Created by Jan Misar on 02.08.18. +// Copyright © 2018 Ackee, s.r.o. All rights reserved. +// + +import XCTest +import ACKategories + +final class DateFormattingTests: XCTestCase { + + func testCachedDateFormatterWorks() { + let date = Date() + + let df1 = DateFormatter.cached(for: "DDMMYYYY") + + let df2 = DateFormatter() + df2.setLocalizedDateFormatFromTemplate("DDMMYYYY") + + XCTAssertEqual(df1.string(from: date), df2.string(from: date)) + } + + func testCachedDateFormatter() { + let df1 = DateFormatter.cached(for: "DDMMYYYY") + let df2 = DateFormatter.cached(for: "DDMMYYYY") + + XCTAssertEqual(df1, df2) + } +}