Bugfix/reading time format issue 451 (#456)

* Fix reading time display affected by 12/24-hour system setting (#451)

Reading time was incorrectly displayed as time-of-day (e.g., "12:45:00 AM" on 12-hour format devices) instead of as a duration. This occurred because DateFormatter was being used to format what should be a duration value, causing it to apply system time format preferences.

Replaced DateFormatter with simple duration calculation that formats as HH:MM:SS regardless of device settings. Added comprehensive unit tests covering basic durations, hour boundaries, fractional minutes, and edge cases.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Add GitHub Action to run SharedLib tests

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Joseph Radford
2025-11-05 18:17:25 +11:00
committed by GitHub
parent 467b132089
commit 0c182f2eb1
5 changed files with 99 additions and 10 deletions
+33
View File
@@ -0,0 +1,33 @@
name: SharedLib Tests
on:
push:
branches: [ main ]
paths:
- 'SharedLib/**'
- '.github/workflows/sharedlib-tests.yml'
pull_request:
branches: [ main ]
paths:
- 'SharedLib/**'
- '.github/workflows/sharedlib-tests.yml'
jobs:
test:
name: Run SharedLib Tests
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Select Xcode version
run: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
- name: Show Swift version
run: swift --version
- name: Run SharedLib tests
run: |
cd SharedLib
swift test
@@ -2,11 +2,11 @@ import Foundation
public extension Double {
var readingTime: String {
let date = Date(timeIntervalSince1970: TimeInterval(self * 60))
let dayTimePeriodFormatter = DateFormatter()
dayTimePeriodFormatter.timeZone = TimeZone(secondsFromGMT: 0)
dayTimePeriodFormatter.dateFormat = "HH:mm:ss"
let totalSeconds = Int(self * 60)
let hours = totalSeconds / 3600
let minutes = (totalSeconds % 3600) / 60
let seconds = totalSeconds % 60
return dayTimePeriodFormatter.string(from: date as Date)
return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
}
}
@@ -2,12 +2,12 @@ import Foundation
public extension Int {
var readingTime: String {
let date = Date(timeIntervalSince1970: TimeInterval(self * 60))
let dayTimePeriodFormatter = DateFormatter()
dayTimePeriodFormatter.timeZone = TimeZone(secondsFromGMT: 0)
dayTimePeriodFormatter.dateFormat = "HH:mm:ss"
let totalSeconds = self * 60
let hours = totalSeconds / 3600
let minutes = (totalSeconds % 3600) / 60
let seconds = totalSeconds % 60
return dayTimePeriodFormatter.string(from: date as Date)
return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
}
var bool: Bool {
@@ -0,0 +1,35 @@
import XCTest
class DoubleTests: XCTestCase {
func testReadingTime() {
// Basic minute tests
XCTAssertEqual("00:01:00", 1.0.readingTime)
XCTAssertEqual("00:02:00", 2.0.readingTime)
XCTAssertEqual("00:05:00", 5.0.readingTime)
XCTAssertEqual("00:10:00", 10.0.readingTime)
XCTAssertEqual("00:30:00", 30.0.readingTime)
XCTAssertEqual("00:45:00", 45.0.readingTime)
// Hour boundary tests
XCTAssertEqual("01:00:00", 60.0.readingTime)
XCTAssertEqual("01:01:00", 61.0.readingTime)
XCTAssertEqual("01:30:00", 90.0.readingTime)
// Multiple hours
XCTAssertEqual("02:00:00", 120.0.readingTime)
XCTAssertEqual("02:15:00", 135.0.readingTime)
XCTAssertEqual("03:45:00", 225.0.readingTime)
// Fractional minutes (should truncate seconds properly)
XCTAssertEqual("00:01:30", 1.5.readingTime)
XCTAssertEqual("00:02:15", 2.25.readingTime)
XCTAssertEqual("00:05:45", 5.75.readingTime)
// Edge cases
XCTAssertEqual("00:00:00", 0.0.readingTime)
// Long reading times
XCTAssertEqual("10:00:00", 600.0.readingTime)
XCTAssertEqual("24:00:00", 1440.0.readingTime)
}
}
@@ -2,9 +2,30 @@ import XCTest
class IntTests: XCTestCase {
func testReadingTime() {
// Basic minute tests
XCTAssertEqual("00:01:00", 1.readingTime)
XCTAssertEqual("00:02:00", 2.readingTime)
XCTAssertEqual("00:05:00", 5.readingTime)
XCTAssertEqual("00:10:00", 10.readingTime)
XCTAssertEqual("00:30:00", 30.readingTime)
XCTAssertEqual("00:45:00", 45.readingTime)
// Hour boundary tests
XCTAssertEqual("01:00:00", 60.readingTime)
XCTAssertEqual("01:01:00", 61.readingTime)
XCTAssertEqual("01:30:00", 90.readingTime)
// Multiple hours
XCTAssertEqual("02:00:00", 120.readingTime)
XCTAssertEqual("02:15:00", 135.readingTime)
XCTAssertEqual("03:45:00", 225.readingTime)
// Edge cases
XCTAssertEqual("00:00:00", 0.readingTime)
// Long reading times
XCTAssertEqual("10:00:00", 600.readingTime)
XCTAssertEqual("24:00:00", 1440.readingTime)
}
func testBool() {