Skip to content

Commit

Permalink
Merge pull request #2 from drekka/develop
Browse files Browse the repository at this point in the history
More functions
  • Loading branch information
drekka committed Jan 16, 2024
2 parents 7067c5b + d75f320 commit fcdfdc8
Show file tree
Hide file tree
Showing 15 changed files with 306 additions and 115 deletions.
54 changes: 47 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,6 @@ init(components: DayComponents)
init(_ year: Int, _ month: Int, _ day: Int)
init(year: Int, month: Int, day: Int)
```

# Codable

`Day` is fully `Codable`.

It's base value is an `Int` representing the number of days since 1 January 1970 which can accessed via the `.daysSince1970` property.

# Properties

## .daysSince1970
Expand Down Expand Up @@ -181,12 +174,59 @@ Day(2000,1,10) - Day(2000,1,5) // -> 5 days duration.

Similar to the way `Date` has a matching `DateComponents`, `Day` has a matching `DayComponents`. In this case mostly as a convenient wrapper for passing the individual values for a year, month and day.

# Conformance

## Codable

`Day` is fully `Codable`.

It's base value is an `Int` representing the number of days since 1 January 1970 which can accessed via the `.daysSince1970` property.


## Equatable

`Day` is `Equatable` so

```swift
Day(2001,2,3) == Day(2001,2,3) // true
```

## Comparable

`Day` is `Comparable` which lets you use all the comparable operators to compare dates. ie. `>`, `<`, `>=` and `<=`.

## Hashable

`Day` is `Hashable` so it can be used as dictionary keys and in sets.

## Stridable

`Day` is `Stridable` which means you can use it in for loops as well as with the `stride(from:to:by:)` function.

```swift
for day in Day(2000,1,1)...Day(2000,1,5) {
/// do something with the 1st, 2nd, 3rd, 4th and 5th.
}

for day in Day(2000,1,1)..<Day(2000,1,5) {
/// do something with the 1st, 2nd, 3rd and 4th.
}

for day in stride(from: Day(2000,1,1), to: Day(2000,1,5), by: 2) {
/// do something with the 1st and 3rd.
}
```

# Other Day functions

## .date(inCalendar:timeZone:) -> Date

Using a passed `Calendar` and `TimeZone`, this function coverts a `Day` to a Swift `Date` with the `Day`'s year, month and day, and a time of `00:00` (midnight). With no arguments this function uses the current calendar and time zone.

## .day(byAdding:, value:) -> Day

Lets you add any number of years, months or days to a `Day` and get a new `day` back. This is convenient for doing things like producing a sequence of dates for the same day on each month.

## .formatted(_:) -> String

Wrapping `Date.formatted(date:time:)` this function formats a day using the standard formatting specified by the `Date.FormatStyle.DateStyle` styles. The time component of `Date.formatted(date:time:)` is omitted.
Expand Down
26 changes: 26 additions & 0 deletions Sources/Day+Core.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// Day+Hashable.swift
//
//
// Created by Derek Clarkson on 10/1/2024.
//

import Foundation

extension Day: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(daysSince1970)
}
}

extension Day: Equatable {
public static func == (lhs: Day, rhs: Day) -> Bool {
lhs.daysSince1970 == rhs.daysSince1970
}
}

extension Day: Comparable {
public static func < (lhs: Day, rhs: Day) -> Bool {
lhs.daysSince1970 < rhs.daysSince1970
}
}
14 changes: 14 additions & 0 deletions Sources/Day+CustomStringConvertable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// Day+CustomStringConvertable.swift
//
//
// Created by Derek Clarkson on 15/1/2024.
//

import Foundation

extension Day: CustomStringConvertible {
public var description: String {
self.formatted()
}
}
24 changes: 24 additions & 0 deletions Sources/Day+Functions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// Day+Functions.swift
//
//
// Created by Derek Clarkson on 16/1/2024.
//

import Foundation

public extension Day {

/// Adds the specific value to the current `Day` and returns a new `Day`.
///
/// This is convenient for doing things like generating dates for the same day of each month. Note though that
/// if the added value would produce an invaid date, the actual `Day` returned contains a valid date produced by
/// rolling the values through the subsequent days and months. ie. if you do `Day(2001,2,3).day(byAdding: .day, value: 55)` you will get
///
func day(byAdding component: Day.Component, value: Int) -> Day {
let components = self.dayComponents()
return Day(components.year + (component == .year ? value : 0), components.month + (component == .month ? value : 0), components.day + (component == .day ? value : 0))
}


}
15 changes: 0 additions & 15 deletions Sources/Day+Hashable.swift

This file was deleted.

11 changes: 0 additions & 11 deletions Sources/Day+Operations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,3 @@ public extension Day {
}
}

extension Day: Equatable {
public static func == (lhs: Day, rhs: Day) -> Bool {
lhs.daysSince1970 == rhs.daysSince1970
}
}

extension Day: Comparable {
public static func < (lhs: Day, rhs: Day) -> Bool {
lhs.daysSince1970 < rhs.daysSince1970
}
}
19 changes: 19 additions & 0 deletions Sources/Day+Strideable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Day+Stridable.swift
//
//
// Created by Derek Clarkson on 15/1/2024.
//

import Foundation

extension Day: Strideable {

public func distance(to other: Day) -> Int {
other.daysSince1970 - self.daysSince1970
}

public func advanced(by n: Int) -> Day {
self + n
}
}
7 changes: 7 additions & 0 deletions Sources/Day.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ public typealias DayInterval = Int
/// day is consistent for that timezone.
public struct Day {

/// Used by functions to modify days.
public enum Component {
case year
case month
case day
}

public let daysSince1970: Int

// MARK: - Initialisers
Expand Down
68 changes: 68 additions & 0 deletions Tests/DayCoreTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// DayOperationsTests.swift
//
//
// Created by Derek Clarkson on 12/12/2023.
//

import DayType
import Nimble
import XCTest

class DayHashableTests: XCTestCase {

func testHash() {
var days: Set = [Day(2020, 01, 11), Day(2020, 01, 12)]
expect(days.contains(Day(2020, 01, 13))) == false
expect(days.contains(Day(2020, 01, 12))) == true

// Modify and try again.
days.insert(Day(2020, 01, 13))
expect(days.contains(Day(2020, 01, 13))) == true
expect(days.contains(Day(2020, 01, 12))) == true

// Duplicate check.
days.insert(Day(2020, 01, 11))
expect(days.count) == 3
}
}

class DayEquatableTests: XCTestCase {

func testEquals() {
expect(Day(2020, 3, 12) == Day(2020, 3, 12)) == true
expect(Day(2020, 3, 12) == Day(2001, 1, 5)) == false
}

func testNotEquals() {
expect(Day(2020, 3, 12) != Day(2001, 1, 5)) == true
expect(Day(2020, 3, 12) != Day(2020, 3, 12)) == false
}
}

class DayComparableTests: XCTestCase {

func testGreaterThan() {
expect(Day(2020, 3, 12) > Day(2020, 3, 11)) == true
expect(Day(2020, 3, 12) > Day(2020, 3, 12)) == false
expect(Day(2020, 3, 12) > Day(2020, 3, 13)) == false
}

func testGreaterThanEquals() {
expect(Day(2020, 3, 12) >= Day(2020, 3, 11)) == true
expect(Day(2020, 3, 12) >= Day(2020, 3, 12)) == true
expect(Day(2020, 3, 12) >= Day(2020, 3, 13)) == false
}

func testLessThan() {
expect(Day(2020, 3, 12) < Day(2020, 3, 11)) == false
expect(Day(2020, 3, 12) < Day(2020, 3, 12)) == false
expect(Day(2020, 3, 12) < Day(2020, 3, 13)) == true
}

func testLessThanEquals() {
expect(Day(2020, 3, 12) <= Day(2020, 3, 11)) == false
expect(Day(2020, 3, 12) <= Day(2020, 3, 12)) == true
expect(Day(2020, 3, 12) <= Day(2020, 3, 13)) == true
}
}
17 changes: 17 additions & 0 deletions Tests/DayCustomStringConvertableTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// DayCustomStringConvertableTests.swift
//
//
// Created by Derek Clarkson on 15/1/2024.
//

import DayType
import Nimble
import XCTest

class DayCustomStringConvertableTests: XCTestCase {
func testyDescription() {
let date = DateComponents(calendar: .current, year: 2001, month: 2, day: 3).date!
expect(Day(2001, 2, 3).description) == date.formatted(date: .abbreviated, time: .omitted)
}
}
24 changes: 24 additions & 0 deletions Tests/DayFunctionsTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// DayFunctionsTests.swift
//
//
// Created by Derek Clarkson on 16/1/2024.
//

import DayType
import Nimble
import XCTest

class DayFunctionsTests: XCTestCase {

func testDayByAdding() {
expect(Day(2001, 2, 3).day(byAdding: .day, value: 3)) == Day(2001, 2, 6)
expect(Day(2001, 2, 3).day(byAdding: .month, value: 3)) == Day(2001, 5, 3)
expect(Day(2001, 2, 3).day(byAdding: .year, value: 3)) == Day(2004, 2, 3)
}

func testDayByAddingRolling() {
expect(Day(2001, 2, 3).day(byAdding: .day, value: 55)) == Day(2001, 3, 30)
expect(Day(2001, 2, 3).day(byAdding: .month, value: 55)) == Day(2005, 9, 10)
}
}
28 changes: 0 additions & 28 deletions Tests/DayHashableTests.swift

This file was deleted.

43 changes: 1 addition & 42 deletions Tests/DayOperationsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,47 +32,6 @@ class DayOperationTests: XCTestCase {
}

func testDayDiff() {
expect(Day(2020, 3, 12) - Day(2020, 3, 6)) == 6
expect(Day(2020, 3, 12) - Day(2020, 3, 6)) == 6
}
}

class DayEquatableTests: XCTestCase {

func testEquals() {
expect(Day(2020, 3, 12) == Day(2020, 3, 12)) == true
expect(Day(2020, 3, 12) == Day(2001, 1, 5)) == false
}

func testNotEquals() {
expect(Day(2020, 3, 12) != Day(2001, 1, 5)) == true
expect(Day(2020, 3, 12) != Day(2020, 3, 12)) == false
}
}

class DayComparableTests: XCTestCase {

func testGreaterThan() {
expect(Day(2020, 3, 12) > Day(2020, 3, 11)) == true
expect(Day(2020, 3, 12) > Day(2020, 3, 12)) == false
expect(Day(2020, 3, 12) > Day(2020, 3, 13)) == false
}

func testGreaterThanEquals() {
expect(Day(2020, 3, 12) >= Day(2020, 3, 11)) == true
expect(Day(2020, 3, 12) >= Day(2020, 3, 12)) == true
expect(Day(2020, 3, 12) >= Day(2020, 3, 13)) == false
}

func testLessThan() {
expect(Day(2020, 3, 12) < Day(2020, 3, 11)) == false
expect(Day(2020, 3, 12) < Day(2020, 3, 12)) == false
expect(Day(2020, 3, 12) < Day(2020, 3, 13)) == true
}

func testLessThanEquals() {
expect(Day(2020, 3, 12) <= Day(2020, 3, 11)) == false
expect(Day(2020, 3, 12) <= Day(2020, 3, 12)) == true
expect(Day(2020, 3, 12) <= Day(2020, 3, 13)) == true
}

}
Loading

0 comments on commit fcdfdc8

Please sign in to comment.