Adjust formatting

This commit is contained in:
Daniel Saidi 2022-10-23 09:41:11 +02:00
parent 66589c6ccb
commit 3d092ab2c2
18 changed files with 296 additions and 83 deletions

View File

@ -5,6 +5,10 @@
This version adjusts the library for Xcode 14 and deprecates some things.
### ✨ New features
* `DateFormatter+Init` has a new convenience initializer.
### 💥 Breaking changes
* Due to conflicting with TagKit, `String+Slugifies` has been removed.

View File

@ -23,7 +23,10 @@ public extension Date {
second: Int = 0,
calendar: Calendar = .current) {
let components = DateComponents(year: year, month: month, day: day, hour: hour, minute: minute, second: second)
guard let date = calendar.date(from: components) else { return nil }
guard let date = calendar.date(from: components) else {
assertionFailure("Invalid date")
return nil
}
self = date
}
}

View File

@ -0,0 +1,71 @@
//
// DateFormatter+Init.swift
// SwiftKit
//
// Created by Daniel Saidi on 2018-09-05.
// Copyright © 2018 Daniel Saidi. All rights reserved.
//
import Foundation
public extension DateFormatter {
/**
Create a custom date formatter, that uses a custom date
format, calendar, locale and time zone.
- Parameters:
- dateStyle: The date style to use.
- timeStyle: The time style to use, by default `.none`.
- locale: The locale to use, by default `en_US_POSIX`.
- calendar: The calendar to use, by default `iso8601`.
*/
convenience init(
dateStyle: DateFormatter.Style,
timeStyle: DateFormatter.Style = .none,
locale: Locale = Locale(identifier: "en_US_POSIX"),
calendar: Calendar = Calendar(identifier: .iso8601)
) {
self.init()
self.dateStyle = dateStyle
self.timeStyle = timeStyle
self.locale = locale
self.calendar = calendar
}
/**
Create a custom date formatter, that uses a custom date
format, calendar, locale and time zone.
- Parameters:
- dateFormat: The date string format to use.
- calendar: The calendar to use, by default `iso8601`.
- locale: The locale to use, by default `en_US_POSIX`.
- timeZone: The time zone to use, by default `GMT`.
*/
convenience init(
dateFormat: String,
calendar: Calendar = Calendar(identifier: .iso8601),
locale: Locale = Locale(identifier: "en_US_POSIX"),
timeZone: TimeZone? = TimeZone(secondsFromGMT: 0)) {
self.init()
self.calendar = calendar
self.locale = locale
self.dateFormat = dateFormat
self.timeZone = timeZone
}
/**
Create a date formatter using the ISO8601 second format.
*/
static var iso8601Seconds: DateFormatter {
DateFormatter(dateFormat: "yyyy-MM-dd'T'HH:mm:ssZ")
}
/**
Create a date formatter using the ISO8601 ms format.
*/
static var iso8601Milliseconds: DateFormatter {
DateFormatter(dateFormat: "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
}
}

View File

@ -1,42 +0,0 @@
//
// DateFormatters.swift
// SwiftKit
//
// Created by Daniel Saidi on 2018-09-05.
// Copyright © 2020 Daniel Saidi. All rights reserved.
//
import Foundation
public extension DateFormatter {
/**
Create a custom date formatter, that uses a custom date
format, calendar, locale and time zone.
*/
convenience init(
dateFormat: String,
calendar: Calendar = Calendar(identifier: .iso8601),
locale: Locale = Locale(identifier: "en_US_POSIX"),
timeZone: TimeZone? = TimeZone(secondsFromGMT: 0)) {
self.init()
self.calendar = calendar
self.locale = locale
self.dateFormat = dateFormat
self.timeZone = timeZone
}
/**
Create a date formatter using the ISO8601 second format.
*/
static var iso8601Seconds: DateFormatter {
DateFormatter(dateFormat: "yyyy-MM-dd'T'HH:mm:ssZ")
}
/**
Create a date formatter using the ISO8601 ms format.
*/
static var iso8601Milliseconds: DateFormatter {
DateFormatter(dateFormat: "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
}
}

View File

@ -0,0 +1,50 @@
//
// NumberFormatter+Init.swift
// SwiftKit
//
// Created by Daniel Saidi on 2022-10-19.
// Copyright © 2022 Daniel Saidi. All rights reserved.
//
import Foundation
public extension NumberFormatter {
/**
Create number formatter with a certain locale and style.
The initializer will default to US English to make sure
that we by default get the default Qapital locale.
- Parameters:
- numberStyle: The number style to use.
- fixedDecimals: The number of fixed decimals to use, if any, by default `nil`.
- locale: The locale to use, by default `en-US`.
*/
convenience init(
numberStyle: NumberFormatter.Style,
fixedDecimals: Int? = nil,
locale: Locale = Locale(identifier: "en-US")
) {
self.init()
self.numberStyle = numberStyle
if let decimals = fixedDecimals {
minimumFractionDigits = decimals
maximumFractionDigits = decimals
}
self.locale = locale
}
}
public extension NumberFormatter {
/**
A percent formatter with a fixed number of decimals.
*/
static func percent(decimals: Int) -> NumberFormatter {
NumberFormatter(
numberStyle: .percent,
fixedDecimals: decimals
)
}
}

View File

@ -0,0 +1,19 @@
//
// NumberFormatter+Util.swift
// SwiftKit
//
// Created by Daniel Saidi on 2022-10-19.
// Copyright © 2022 Daniel Saidi. All rights reserved.
//
import Foundation
public extension NumberFormatter {
/**
Create a string for a double value.
*/
func string(for value: Double) -> String? {
string(for: NSNumber(value: value))
}
}

View File

@ -0,0 +1,65 @@
//
// DateFormatter+InitTests.swift
// SwiftKitTests
//
// Created by Daniel Saidi on 2018-09-05.
// Copyright © 2018 Daniel Saidi. All rights reserved.
//
import Foundation
import SwiftKit
import XCTest
class DateFormatter_InitTests: XCTestCase {
func testConvenienceInitializerUsesUsEnglishWithNoTimeByDefault() {
let formatter = DateFormatter(dateStyle: .medium)
XCTAssertEqual(formatter.locale.identifier, "en_US_POSIX")
XCTAssertEqual(formatter.dateStyle, .medium)
XCTAssertEqual(formatter.timeStyle, .none)
}
func testConvenienceInstanceGeneratesValidDateStringForMediumDateStyle() {
let date = Date(year: 2022, month: 10, day: 19) ?? Date()
let formatter = DateFormatter(dateStyle: .medium)
let result = formatter.string(from: date)
XCTAssertEqual(result, "Oct 19, 2022")
}
func testConvenienceInstanceGeneratesValidDateStringForLongDateStyleAndShortTimeStyle() {
let date = Date(year: 2022, month: 10, day: 19) ?? Date()
let formatter = DateFormatter(
dateStyle: .long,
timeStyle: .short
)
let result = formatter.string(from: date)
XCTAssertEqual(result, "October 19, 2022 at 12:00 AM")
}
func testConvenienceInstanceGeneratesValidDateStringForCustomLocale() {
let date = Date(year: 2022, month: 10, day: 19) ?? Date()
let formatter = DateFormatter(
dateStyle: .long,
timeStyle: .short,
locale: Locale(identifier: "sv-SE")
)
let result = formatter.string(from: date)
XCTAssertEqual(result, "19 oktober 2022 00:00")
}
func testIso8601SecondFormatterIsValid() {
let formatter = DateFormatter.iso8601Seconds
XCTAssertEqual(formatter.dateFormat, "yyyy-MM-dd'T'HH:mm:ssZ")
XCTAssertEqual(formatter.calendar.identifier, .iso8601)
XCTAssertEqual(formatter.locale.identifier, "en_US_POSIX")
XCTAssertNotNil(formatter.timeZone)
}
func testIso8601MilliSecondFormatterIsValid() {
let formatter = DateFormatter.iso8601Milliseconds
XCTAssertEqual(formatter.dateFormat, "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
XCTAssertEqual(formatter.calendar.identifier, .iso8601)
XCTAssertEqual(formatter.locale.identifier, "en_US_POSIX")
XCTAssertNotNil(formatter.timeZone)
}
}

View File

@ -1,40 +0,0 @@
//
// DateFormattersTests.swift
// SwiftKitTests
//
// Created by Daniel Saidi on 2018-09-05.
// Copyright © 2020 Daniel Saidi. All rights reserved.
//
import Foundation
import Quick
import Nimble
import SwiftKit
class DateFormattersTests: QuickSpec {
override func spec() {
describe("iso8601 second formatter") {
it("is correctly setup") {
let formatter = DateFormatter.iso8601Seconds
expect(formatter.dateFormat).to(equal("yyyy-MM-dd'T'HH:mm:ssZ"))
expect(formatter.calendar.identifier).to(equal(.iso8601))
expect(formatter.locale.identifier).to(equal("en_US_POSIX"))
expect(formatter.timeZone).toNot(beNil())
}
}
describe("iso8601 millisecond formatter") {
it("is correctly setup") {
let formatter = DateFormatter.iso8601Milliseconds
expect(formatter.dateFormat).to(equal("yyyy-MM-dd'T'HH:mm:ss.SSSZ"))
expect(formatter.calendar.identifier).to(equal(.iso8601))
expect(formatter.locale.identifier).to(equal("en_US_POSIX"))
expect(formatter.timeZone).toNot(beNil())
}
}
}
}

View File

@ -0,0 +1,56 @@
//
// NumberFormatter+InitTests.swift
// SwiftKit
//
// Created by Daniel Saidi on 2022-10-19.
// Copyright © 2012 Daniel Saidi. All rights reserved.
//
import SwiftKit
import XCTest
class NumberFormatter_InitTests: XCTestCase {
func testConvenienceInitializerUsesUsEnglishByDefault() {
let formatter = NumberFormatter(numberStyle: .currency)
XCTAssertEqual(formatter.locale.identifier, "en-US")
XCTAssertEqual(formatter.numberStyle, .currency)
}
func testConvenienceInitializerCanEnforceFixedDecimals() {
let formatter = NumberFormatter(numberStyle: .percent, fixedDecimals: 2)
XCTAssertEqual(formatter.locale.identifier, "en-US")
XCTAssertEqual(formatter.numberStyle, .percent)
XCTAssertEqual(formatter.minimumFractionDigits, 2)
XCTAssertEqual(formatter.maximumFractionDigits, 2)
}
func testConvenienceInstanceGeneratesValidDateStringForDollars() {
let value = 123_456_789.123
let formatter = NumberFormatter(numberStyle: .currency)
let result = formatter.string(from: NSNumber(value: value))
XCTAssertEqual(result, "$123,456,789.12")
}
func testConvenienceInstanceGeneratesValidDateStringForSwedishKrona() {
let value = 123_456_789.123
let locale = Locale(identifier: "sv-SE")
let formatter = NumberFormatter(numberStyle: .currency, locale: locale)
let result = formatter.string(from: NSNumber(value: value))
XCTAssertEqual(result, "123 456 789,12 kr")
}
func testPercentFormatterGeneratesValidStringWithTwoDecimals() {
let value = 0.09156
let formatter = NumberFormatter.percent(decimals: 2)
let result = formatter.string(from: NSNumber(value: value))
XCTAssertEqual(result, "9.16%")
}
func testPercentFormatterGeneratesValidStringWithZeroDecimals() {
let value = 0.09156
let formatter = NumberFormatter.percent(decimals: 0)
let result = formatter.string(from: NSNumber(value: value))
XCTAssertEqual(result, "9%")
}
}

View File

@ -0,0 +1,27 @@
//
// NumberFormatter+UtilTests.swift
// SwiftKit
//
// Created by Daniel Saidi on 2022-10-19.
// Copyright © 2012 Daniel Saidi. All rights reserved.
//
import SwiftKit
import XCTest
class NumberFormatter_UtilTests: XCTestCase {
func testStringForDoubleReturnsValidResult() {
let value = 0.09156
let formatter = NumberFormatter.percent(decimals: 2)
let result = formatter.string(for: value)
XCTAssertEqual(result, "9.16%")
}
func testStringForIntReturnsValidResult() {
let value: Int = 9
let formatter = NumberFormatter.percent(decimals: 2)
let result = formatter.string(for: value)
XCTAssertEqual(result, "900.00%")
}
}