diff --git a/Sources/DevFoundation/Documentation.docc/Documentation.md b/Sources/DevFoundation/Documentation.docc/Documentation.md index 028fbfb..04a3ef8 100644 --- a/Sources/DevFoundation/Documentation.docc/Documentation.md +++ b/Sources/DevFoundation/Documentation.docc/Documentation.md @@ -80,6 +80,7 @@ for paging through data, and essential utility types for building robust applica ### Working with Dates +- ``Foundation/Date`` - ``Swift/Duration`` - ``DateProvider`` - ``DateProviders`` diff --git a/Sources/DevFoundation/Extensions/Date+Unix.swift b/Sources/DevFoundation/Extensions/Date+Unix.swift new file mode 100644 index 0000000..3c588fa --- /dev/null +++ b/Sources/DevFoundation/Extensions/Date+Unix.swift @@ -0,0 +1,49 @@ +// +// Date+Unix.swift +// DevFoundation +// +// Created by Prachi Gauriar on 3/23/26. +// + +import Foundation + +extension Date { + /// Creates a date from the given number of whole seconds since January 1, 1970 at 00:00:00 UTC. + /// + /// - Parameter secondsSince1970: The number of whole seconds since the Unix epoch. + public init(secondsSince1970: Int64) { + self.init(timeIntervalSince1970: TimeInterval(secondsSince1970)) + } + + + /// Creates a date from the given number of whole milliseconds since January 1, 1970 at 00:00:00 UTC. + /// + /// - Parameter millisecondsSince1970: The number of whole milliseconds since the Unix epoch. + public init(millisecondsSince1970: Int64) { + self.init(millisecondsSince1970: Float64(millisecondsSince1970)) + } + + + /// Creates a date from the given number of fractional milliseconds since January 1, 1970 at 00:00:00 UTC. + /// + /// - Parameter millisecondsSince1970: The number of milliseconds since the Unix epoch. + public init(millisecondsSince1970: Float64) { + self.init(timeIntervalSince1970: millisecondsSince1970 / 1000) + } + + + /// The date represented as whole seconds since January 1, 1970 at 00:00:00 UTC. + /// + /// The fractional seconds component of the date's time interval is truncated. + public var secondsSince1970: Int64 { + return Int64(timeIntervalSince1970) + } + + + /// The date represented as whole milliseconds since January 1, 1970 at 00:00:00 UTC. + /// + /// The sub-millisecond component of the date's time interval is truncated. + public var millisecondsSince1970: Int64 { + return Int64(timeIntervalSince1970 * 1000) + } +} diff --git a/Tests/DevFoundationTests/Extensions/Date+UnixTests.swift b/Tests/DevFoundationTests/Extensions/Date+UnixTests.swift new file mode 100644 index 0000000..fa0d67c --- /dev/null +++ b/Tests/DevFoundationTests/Extensions/Date+UnixTests.swift @@ -0,0 +1,95 @@ +// +// Date+UnixTests.swift +// DevFoundation +// +// Created by Prachi Gauriar on 3/23/26. +// + +import DevFoundation +import DevTesting +import Foundation +import RealModule +import Testing + +struct Date_UnixTests: RandomValueGenerating { + var randomNumberGenerator = makeRandomNumberGenerator() + + + @Test + mutating func initWithSecondsSince1970SetsCorrectDate() { + for _ in 0 ..< 100 { + // set up + let seconds = random(Int64.self, in: -4_000_000 ... 4_000_000) + + // exercise + let date = Date(secondsSince1970: seconds) + + // expect + #expect(date.timeIntervalSince1970 == TimeInterval(seconds)) + } + } + + + @Test + mutating func initWithMillisecondsSince1970AsInt64SetsCorrectDate() { + for _ in 0 ..< 100 { + // set up + let milliseconds = random(Int64.self, in: -4_000_000 ... 4_000_000) + + // exercise + let date = Date(millisecondsSince1970: milliseconds) + + // expect + #expect( + date.timeIntervalSince1970.isApproximatelyEqual( + to: Float64(milliseconds) / 1000, + absoluteTolerance: 0.0001 + ) + ) + } + } + + + @Test + mutating func initWithMillisecondsSince1970AsFloat64SetsCorrectDate() { + for _ in 0 ..< 100 { + // set up + let milliseconds = randomFloat64(in: -4_000_000 ..< 4_000_000) + + // exercise + let date = Date(millisecondsSince1970: milliseconds) + + // expect + #expect( + date.timeIntervalSince1970.isApproximatelyEqual( + to: milliseconds / 1000, + absoluteTolerance: 0.0001 + ) + ) + } + } + + + @Test + mutating func secondsSince1970ReturnsCorrectValue() { + for _ in 0 ..< 100 { + // set up + let date = randomDate() + + // expect + #expect(date.secondsSince1970 == Int64(date.timeIntervalSince1970)) + } + } + + + @Test + mutating func millisecondsSince1970ReturnsCorrectValue() { + for _ in 0 ..< 100 { + // set up + let date = randomDate() + + // expect + #expect(date.millisecondsSince1970 == Int64(date.timeIntervalSince1970 * 1000)) + } + } +}