Skip to content

Commit

Permalink
Add support for medium-length abbreviations for time #1
Browse files Browse the repository at this point in the history
  • Loading branch information
Reed Es committed Nov 30, 2022
1 parent 5dda0d6 commit 5caf0b3
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 20 deletions.
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,19 @@ By default, values will show up to one fractional decimal point of the value, ro

### Suffixes

The suffix will depend on the style, of which there is currently `.short` (default) and `.full`.

| short | full | value |
| ------ | ------------------- | ---------- |
| s | second | 1 |
| m | minute | 60 |
| h | hour | 3,600 |
| d | day | 86,400 |
| y | year | d × 365.25 |
| c | century | y × 100 |
| ky | millennium | y × 1000 |
The suffix will depend on the style, of which there is currently `.short` (default), `.medium`, and `.full`.

| short | medium | full | value |
| ------ | ------ | ------------------- | ---------- |
| s | sec | second | 1 |
| m | min | minute | 60 |
| h | hr | hour | 3,600 |
| d | day | day | 86,400 |
| y | yr | year | d × 365.25 |
| c | cent | century | y × 100 |
| ky | ky | millennium | y × 1000 |

Note that `.medium` and `.full` include plural forms.

## See Also

Expand Down
46 changes: 43 additions & 3 deletions Sources/TimeCompactor+Scale.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ extension TimeCompactor {
}
}

var abbreviation: String {
// shortest possible, with no plural form
var shortAbbreviation: String {
switch self {
case .second:
return "s"
Expand All @@ -66,7 +67,46 @@ extension TimeCompactor {
}
}

var singular: String {
// usually longer than short, at most 4-5 chars, and may require plural form
var mediumSingular: String {
switch self {
case .second:
return "sec"
case .minute:
return "min"
case .hour:
return "hr"
case .day:
return "day"
case .year:
return "yr"
case .century:
return "cent"
case .millenium:
return "ky"
}
}

var mediumPlural: String {
switch self {
case .second:
return "secs"
case .minute:
return "mins"
case .hour:
return "hrs"
case .day:
return "days"
case .year:
return "yrs"
case .century:
return "cents"
case .millenium:
return "kys"
}
}

var fullSingular: String {
switch self {
case .second:
return "second"
Expand All @@ -85,7 +125,7 @@ extension TimeCompactor {
}
}

var plural: String {
var fullPlural: String {
switch self {
case .second:
return "seconds"
Expand Down
5 changes: 3 additions & 2 deletions Sources/TimeCompactor+Style.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import Foundation

extension TimeCompactor {
public enum Style {
case short
case full
case short // s, m, h, ...
case medium // sec, min, hr, ...
case full // second(s), minute(s), hour(s), ...
}
}
13 changes: 9 additions & 4 deletions Sources/TimeCompactor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,15 @@ public class TimeCompactor: NumberFormatter {

switch style {
case .short:
return "\(prefix)\(scaleSymbol.abbreviation)"
case .full:
let isPlural = prefix != "1"
let unit = isPlural ? scaleSymbol.plural : scaleSymbol.singular
return "\(prefix)\(scaleSymbol.shortAbbreviation)"
case .medium, .full:
let unit: String = {
if prefix != "1" {
return style == .medium ? scaleSymbol.mediumPlural : scaleSymbol.fullPlural
} else {
return style == .medium ? scaleSymbol.mediumSingular : scaleSymbol.fullSingular
}
}()
return "\(prefix) \(unit)"
}
}
Expand Down
90 changes: 90 additions & 0 deletions Tests/TimeCompactorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,29 @@ class TimeCompactorTests: XCTestCase {
XCTAssertEqual("-12.0s", c.string(from: -12.050))
}

func testWholeNumberMedium() {
let c = TimeCompactor(ifZero: nil, style: .medium, roundSmallToWhole: true)

XCTAssertEqual("59 secs", c.string(from: 59))
XCTAssertEqual("59 secs", c.string(from: 59.499))
XCTAssertEqual("1 min", c.string(from: 59.500))
XCTAssertEqual("1 min", c.string(from: 59.899))
XCTAssertEqual("1 min", c.string(from: 59.9))
XCTAssertEqual("1 min", c.string(from: 60))
XCTAssertEqual("1 min", c.string(from: 61))
XCTAssertEqual("1 min", c.string(from: 89.499))
XCTAssertEqual("1 min", c.string(from: 89.999))
XCTAssertEqual("2 mins", c.string(from: 90))

XCTAssertEqual("1 sec", c.string(from: 1))
XCTAssertEqual("1 sec", c.string(from: 1.49))
XCTAssertEqual("2 secs", c.string(from: 1.50))

XCTAssertEqual("1 hr", c.string(from: 3600))
XCTAssertEqual("1 hr", c.string(from: 5399)) // <1.5 hours
XCTAssertEqual("2 hrs", c.string(from: 5400)) // 1.5 hours
}

func testWholeNumberFull() {
let c = TimeCompactor(ifZero: nil, style: .full, roundSmallToWhole: true)

Expand Down Expand Up @@ -93,6 +116,24 @@ class TimeCompactorTests: XCTestCase {
XCTAssertEqual("2h", c.string(from: 5400)) // 1.5 hours
}

func testPluralMedium() {
let c = TimeCompactor(ifZero: nil, style: .medium)

XCTAssertEqual("1.0 secs", c.string(from: 1))
XCTAssertEqual("1.1 secs", c.string(from: 1.09))

XCTAssertEqual("59.0 secs", c.string(from: 59))
XCTAssertEqual("59.9 secs", c.string(from: 59.94))
XCTAssertEqual("1.0 mins", c.string(from: 59.95))
XCTAssertEqual("1.0 mins", c.string(from: 60))
XCTAssertEqual("1.0 mins", c.string(from: 61))
XCTAssertEqual("1.5 mins", c.string(from: 89))

XCTAssertEqual("1.0 hrs", c.string(from: 3600))
XCTAssertEqual("1.5 hrs", c.string(from: 5400))
XCTAssertEqual("2.0 hrs", c.string(from: 7200))
}

func testPluralFull() {
let c = TimeCompactor(ifZero: nil, style: .full)

Expand Down Expand Up @@ -167,6 +208,55 @@ class TimeCompactorTests: XCTestCase {
XCTAssertEqual("3818ky", c.string(from: 120_500_000_000_000))
}

func testMedium() {
let c = TimeCompactor(ifZero: nil, style: .medium)

XCTAssertEqual("-3818 kys", c.string(from: -120_500_000_000_000))
XCTAssertEqual("-3.8 kys", c.string(from: -120_500_000_000))
XCTAssertEqual("-3.3 cents", c.string(from: -10_500_000_000))
XCTAssertEqual("-3.8 yrs", c.string(from: -120_500_000))
XCTAssertEqual("-1.4 days", c.string(from: -120_500))
XCTAssertEqual("-3.3 hrs", c.string(from: -12050))
XCTAssertEqual("-2.0 mins", c.string(from: -120.50))
XCTAssertEqual("-12.0 secs", c.string(from: -12.050))

XCTAssertEqual("-1.5 secs", c.string(from: -1.5))
XCTAssertEqual("-1.5 secs", c.string(from: -1.49))
XCTAssertEqual("-1.2 secs", c.string(from: -1.250))

XCTAssertEqual("-0.3 secs", c.string(from: -0.251))
XCTAssertEqual("-0.2 secs", c.string(from: -0.250))
XCTAssertEqual("-0.1 secs", c.string(from: -0.051))
XCTAssertEqual("0.0 secs", c.string(from: -0.050))
XCTAssertEqual("0.0 secs", c.string(from: 0.000))
XCTAssertEqual("0.0 secs", c.string(from: 0.050))
XCTAssertEqual("0.1 secs", c.string(from: 0.051))
XCTAssertEqual("0.2 secs", c.string(from: 0.250))
XCTAssertEqual("0.3 secs", c.string(from: 0.251))
XCTAssertEqual("0.5 secs", c.string(from: 0.499))
XCTAssertEqual("0.5 secs", c.string(from: 0.500))

XCTAssertEqual("0.5 secs", c.string(from: 0.501))
XCTAssertEqual("1.5 secs", c.string(from: 1.49))
XCTAssertEqual("1.5 secs", c.string(from: 1.5))

XCTAssertEqual("12.0 secs", c.string(from: 12.050))
XCTAssertEqual("12.1 secs", c.string(from: 12.051))

XCTAssertEqual("2.0 mins", c.string(from: 120.50))
XCTAssertEqual("2.0 mins", c.string(from: 120.51))

XCTAssertEqual("3.3 hrs", c.string(from: 12050))

XCTAssertEqual("1.4 days", c.string(from: 120_500))

XCTAssertEqual("3.8 yrs", c.string(from: 120_500_000))

XCTAssertEqual("3.8 kys", c.string(from: 120_500_000_000))

XCTAssertEqual("3818 kys", c.string(from: 120_500_000_000_000))
}

func testFull() {
let c = TimeCompactor(ifZero: nil, style: .full)

Expand Down

0 comments on commit 5caf0b3

Please sign in to comment.