├── .gitignore ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── Images └── header.png ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── DateFormatterPool │ ├── DateFormat.swift │ ├── DateFormatterContainer.swift │ ├── DateFormatterPropertyWrapper.swift │ └── RecursiveLock.swift └── Tests └── DateFormatterPoolTests └── DateFormatterPoolTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/config/registries.json 8 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 9 | .netrc 10 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Images/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bartleby/DateFormatterPool/a8460e1887d3f0d9022c7e382caf46075512f3b6/Images/header.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Aleksei Artemev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.6 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "DateFormatterPool", 8 | products: [ 9 | // Products define the executables and libraries a package produces, and make them visible to other packages. 10 | .library( 11 | name: "DateFormatterPool", 12 | targets: ["DateFormatterPool"]), 13 | ], 14 | dependencies: [ 15 | // Dependencies declare other packages that this package depends on. 16 | // .package(url: /* package url */, from: "1.0.0"), 17 | ], 18 | targets: [ 19 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 20 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 21 | .target( 22 | name: "DateFormatterPool", 23 | dependencies: []), 24 | .testTarget( 25 | name: "DateFormatterPoolTests", 26 | dependencies: ["DateFormatterPool"]), 27 | ] 28 | ) 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | Date Formatter Pool 6 | ======== 7 | 8 | Date Formatter Pool - is a small utility that creates and stores your `Date Formatter` for simpler reuse 9 | 10 | ## Installation 11 | 12 | is available in the [Swift Package Manager](https://swift.org/package-manager/). 13 | 14 | ### Swift Package Manager 15 | 16 | ``` 17 | https://github.com/bartleby/DateFormatterPool.git 18 | ``` 19 | 20 | 21 | ## Basic Usage 22 | 23 | First, add a your `format` to a `Pool`, through the expansion of `DateFormat` 24 | 25 | 26 | ```swift 27 | extension DateFormat { 28 | static let shortDateAndTime = DateFormat(value: "MMM d, E 'at' HH:mm") 29 | static let shortDay = DateFormat(value: "d") 30 | static let shortMonth = DateFormat(value: "MMM") 31 | static let monthAndYear = DateFormat(value: "LLLL YYYY") 32 | static let shortWeekName = DateFormat(value: "EE") 33 | } 34 | ``` 35 | 36 | On this site you can create the format you need: [nsdateformatter.com](https://nsdateformatter.com) 37 | 38 | 39 | 40 | Then get an `DateFormatter` from the pool using `PropertyWrapper`. 41 | 42 | ```swift 43 | struct ContentView: View { 44 | @DateFormatterPool(.shortDateAndTime) var shortDateAndTimeFormatter 45 | 46 | var body: some View { 47 | VStack { 48 | Text(shortDateAndTimeFormatter.string(from: Date())) // Aug 23, Tue at 12:10 49 | } 50 | } 51 | } 52 | ``` 53 | 54 | or in ViewModel 55 | 56 | ```swift 57 | final class ViewModel { 58 | @Published var dateString: String 59 | 60 | @DateFormatterPool(.shortDateAndTime) var shortDateAndTimeFormatter 61 | 62 | //... 63 | 64 | func configure() { 65 | dateString = shortDateAndTimeFormatter.string(from: Date())) // Aug 23, Tue at 12:10 66 | } 67 | } 68 | ``` 69 | 70 | 71 | ## Example Apps 72 | 73 | Coming soon 74 | 75 | 76 | ## License 77 | 78 | MIT license. See the [LICENSE file](LICENSE) for details. 79 | -------------------------------------------------------------------------------- /Sources/DateFormatterPool/DateFormat.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 iDevs.io. All rights reserved. 2 | 3 | import Foundation 4 | 5 | public struct DateFormat { 6 | public var value: String 7 | 8 | public init(value: String) { 9 | self.value = value 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/DateFormatterPool/DateFormatterContainer.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 iDevs.io. All rights reserved. 2 | 3 | import Foundation 4 | 5 | final class DateFormatterContainer { 6 | 7 | // MARK: - Properties 8 | private var pool = [String: DateFormatter]() 9 | private var lock: RecursiveLock = RecursiveLock() 10 | 11 | // MARK: - Singleton 12 | public static let shared = DateFormatterContainer() 13 | 14 | // MARK: - Init/Deinit 15 | private init() {} 16 | 17 | // MARK: - Public methods 18 | public func obtain(format: DateFormat) -> DateFormatter { 19 | return lock.sync { 20 | let key = format.value 21 | 22 | if let formatter = pool[key] { 23 | return formatter 24 | } 25 | 26 | let formatter = DateFormatter() 27 | formatter.dateFormat = key 28 | pool[key] = formatter 29 | 30 | return formatter 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/DateFormatterPool/DateFormatterPropertyWrapper.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 iDevs.io. All rights reserved. 2 | 3 | import Foundation 4 | 5 | @propertyWrapper 6 | public final class DateFormatterPool { 7 | 8 | // MARK: - Properties 9 | private let format: DateFormat 10 | private var dateFormatterContainer = DateFormatterContainer.shared 11 | public var wrappedValue: DateFormatter { value } 12 | 13 | // MARK: - Lazy Properties 14 | private lazy var value: DateFormatter = { 15 | dateFormatterContainer.obtain(format: format) 16 | }() 17 | 18 | 19 | // MARK: - Init/Deinit 20 | public init(_ format: DateFormat) { 21 | self.format = format 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/DateFormatterPool/RecursiveLock.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Bartleby on 23.08.2022. 6 | // 7 | 8 | import Foundation 9 | 10 | final class RecursiveLock { 11 | 12 | // MARK: - Private methods 13 | private let lock = NSRecursiveLock() 14 | 15 | // MARK: - Public methods 16 | func sync(action: () -> T) -> T { 17 | lock.lock() 18 | defer { lock.unlock() } 19 | return action() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Tests/DateFormatterPoolTests/DateFormatterPoolTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import DateFormatterPool 3 | 4 | final class DateFormatterPoolTests: XCTestCase { 5 | 6 | func testExample() throws {} 7 | } 8 | --------------------------------------------------------------------------------