Update/0.0.9 (#9)
* Made Coordinate, Aspect and Lunation conform to Codable * Remove TimeZone parameter from RiseTime and SetTime
This commit is contained in:
parent
0fb72e0a80
commit
cfb98b77a4
|
@ -8,7 +8,7 @@
|
|||
import Foundation
|
||||
|
||||
/// Models a geometric aspect between two bodies.
|
||||
public enum Aspect: Equatable, Hashable {
|
||||
public enum Aspect: Equatable, Hashable, Codable {
|
||||
|
||||
/// A 0° alignment.
|
||||
case conjunction(Double)
|
||||
|
|
|
@ -73,3 +73,43 @@ public struct Coordinate<T: CelestialBody> {
|
|||
extension Coordinate: ZodiacCoordinate {
|
||||
public var value: Double { longitude }
|
||||
}
|
||||
|
||||
// MARK: - Codable Conformance
|
||||
|
||||
extension Coordinate: Codable {
|
||||
|
||||
public enum CodingKeys: CodingKey {
|
||||
case body
|
||||
case date
|
||||
case longitude
|
||||
case latitude
|
||||
case distance
|
||||
case speedLongitude
|
||||
case speedLatitude
|
||||
case speedDistance
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
body = try container.decode(T.self, forKey: .body)
|
||||
date = try container.decode(Date.self, forKey: .date)
|
||||
longitude = try container.decode(Double.self, forKey: .longitude)
|
||||
latitude = try container.decode(Double.self, forKey: .latitude)
|
||||
distance = try container.decode(Double.self, forKey: .distance)
|
||||
speedLongitude = try container.decode(Double.self, forKey: .speedLongitude)
|
||||
speedLatitude = try container.decode(Double.self, forKey: .speedLatitude)
|
||||
speedDistance = try container.decode(Double.self, forKey: .speedDistance)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(body, forKey: .body)
|
||||
try container.encode(date, forKey: .date)
|
||||
try container.encode(longitude, forKey: .longitude)
|
||||
try container.encode(latitude, forKey: .latitude)
|
||||
try container.encode(distance, forKey: .distance)
|
||||
try container.encode(speedLongitude, forKey: .speedLongitude)
|
||||
try container.encode(speedLatitude, forKey: .speedLatitude)
|
||||
try container.encode(speedDistance, forKey: .speedDistance)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import CSwissEphemeris
|
|||
public struct Lunation {
|
||||
|
||||
/// Represents common phases of the moon.
|
||||
public enum Phase: Int {
|
||||
public enum Phase: Int, Codable {
|
||||
/// Less than one percent full.
|
||||
case new
|
||||
/// 1 to 50 percent towards full.
|
||||
|
@ -51,7 +51,7 @@ public struct Lunation {
|
|||
/// The percentage full.
|
||||
public let percentage: Double
|
||||
/// Lunation is moving towards full
|
||||
let isWaxing: Bool
|
||||
public let isWaxing: Bool
|
||||
/// The current `Phase`.
|
||||
public var phase: Phase { Phase(lunation: self) }
|
||||
/// The pointer that holds all values.
|
||||
|
@ -81,3 +81,30 @@ public struct Lunation {
|
|||
isWaxing = percentage > pointerFuture[1]
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Codable Conformance
|
||||
|
||||
extension Lunation: Codable {
|
||||
|
||||
public enum CodingKeys: CodingKey {
|
||||
case date
|
||||
case percentage
|
||||
case isWaxing
|
||||
case phase
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
date = try container.decode(Date.self, forKey: .date)
|
||||
percentage = try container.decode(Double.self, forKey: .percentage)
|
||||
isWaxing = try container.decode(Bool.self, forKey: .isWaxing)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(date, forKey: .date)
|
||||
try container.encode(percentage, forKey: .percentage)
|
||||
try container.encode(isWaxing, forKey: .isWaxing)
|
||||
try container.encode(phase, forKey: .phase)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public protocol BatchRequest {
|
|||
|
||||
// MARK: - Helper Methods
|
||||
|
||||
extension BatchRequest {
|
||||
public extension BatchRequest {
|
||||
|
||||
/// Helper method that prepares a collection of dates so that they can be mapped to the `EphemerisItem`.
|
||||
/// - Parameters:
|
||||
|
|
|
@ -10,6 +10,8 @@ import Foundation
|
|||
/// Models a sidereal coordinate on the Zodiac.
|
||||
public struct SiderealCoordinate<T: CelestialBody> {
|
||||
|
||||
///
|
||||
public let date: Date
|
||||
/// The coordinate to set
|
||||
private let coordinate: Coordinate<T>
|
||||
/// The ayanamsha value that determines the sidereal position
|
||||
|
@ -19,6 +21,7 @@ public struct SiderealCoordinate<T: CelestialBody> {
|
|||
/// - Parameter coordinate: The coordinate to set.
|
||||
/// - Parameter ayanamshaValue: The ayanamsha value that determines the sidereal position.
|
||||
public init(coordinate: Coordinate<T>, ayanamshaValue: Double = Ayanamsha.current) {
|
||||
self.date = coordinate.date
|
||||
self.coordinate = coordinate
|
||||
self.ayanamshaValue = ayanamshaValue
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ public struct RiseTime<T: CelestialBody> {
|
|||
|
||||
/// Creates a `RisingTime`.
|
||||
/// - Parameters:
|
||||
/// - timeZone: The `TimeZone` for the rise.
|
||||
/// - date: The date to set for the rise.
|
||||
/// - body: The celestial body that is rising.
|
||||
/// - longitude: The longitude of the location.
|
||||
|
@ -29,8 +28,7 @@ public struct RiseTime<T: CelestialBody> {
|
|||
/// - altitude: The height above sea level. The default value is zero.
|
||||
/// - atmosphericPressure: The level of atmospheric pressure. The default value is zero.
|
||||
/// - atmosphericTemperature: The atmospheric temperature. The default value is zero.
|
||||
public init(timeZone: TimeZone = TimeZone.current,
|
||||
date: Date,
|
||||
public init(date: Date,
|
||||
body: T,
|
||||
longitude: Double,
|
||||
latitude: Double,
|
||||
|
@ -56,6 +54,6 @@ public struct RiseTime<T: CelestialBody> {
|
|||
time,
|
||||
nil)
|
||||
}
|
||||
self.date = Date(julianDate: time[0]).addingTimeInterval(TimeInterval(timeZone.secondsFromGMT()))
|
||||
self.date = Date(julianDate: time[0])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ public struct SetTime<T: CelestialBody> {
|
|||
|
||||
/// Creates an instance of `SetTime`.
|
||||
/// - Parameters:
|
||||
/// - timeZone: The `TimeZone` for the set.
|
||||
/// - date: The date to set for the set.
|
||||
/// - body: The celestial body that is setting.
|
||||
/// - longitude: The longitude of the location.
|
||||
|
@ -29,8 +28,7 @@ public struct SetTime<T: CelestialBody> {
|
|||
/// - altitude: The height above sea level. The default value is zero.
|
||||
/// - atmosphericPressure: The level of atmospheric pressure. The default value is zero.
|
||||
/// - atmosphericTemperature: The atmospheric temperature. The default value is zero.
|
||||
public init(timeZone: TimeZone = TimeZone.current,
|
||||
date: Date,
|
||||
public init(date: Date,
|
||||
body: T,
|
||||
longitude: Double,
|
||||
latitude: Double,
|
||||
|
@ -56,6 +54,6 @@ public struct SetTime<T: CelestialBody> {
|
|||
time,
|
||||
nil)
|
||||
}
|
||||
self.date = Date(julianDate: time[0]).addingTimeInterval(TimeInterval(timeZone.secondsFromGMT()))
|
||||
self.date = Date(julianDate: time[0])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
//
|
||||
// LunationsRequest.swift
|
||||
//
|
||||
//
|
||||
// Created by Vincent on 6/29/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// A `BatchRequest` for a collection of `Lunation`.
|
||||
final public class LunationsRequest: BatchRequest {
|
||||
|
||||
public typealias EphemerisItem = Lunation
|
||||
public let datesThreshold = 478
|
||||
|
||||
/// Creates an instance of `LunationsRequest`.
|
||||
public init() {}
|
||||
|
||||
public func fetch(start: Date, end: Date, interval: TimeInterval = 60.0, _ closure: ([EphemerisItem]) -> Void) {
|
||||
var lunations = [EphemerisItem]()
|
||||
let group = DispatchGroup()
|
||||
func execute(batches: [[Date]], _ closure: ([EphemerisItem]) -> Void) {
|
||||
guard let batch = batches.first else {
|
||||
closure(lunations)
|
||||
return
|
||||
}
|
||||
group.enter()
|
||||
let c = batch.map { EphemerisItem(date: $0) }
|
||||
lunations.append(contentsOf: c)
|
||||
group.leave()
|
||||
execute(batches: Array(batches.dropFirst()), closure)
|
||||
}
|
||||
execute(batches: dates(for: start, end: end, interval: interval), closure)
|
||||
}
|
||||
}
|
|
@ -247,59 +247,44 @@ final class CelestialBodyTests: XCTestCase {
|
|||
let ayanamsha = Ayanamsha()(for: date)
|
||||
XCTAssertEqual((ayanamsha * 100).rounded() / 100, 25.04)
|
||||
}
|
||||
|
||||
func testPlanetRisingTime() throws {
|
||||
let timestamp = "2021-03-14"
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateFormat = "yyyy-MM-dd"
|
||||
let date = try XCTUnwrap(dateFormatter.date(from: timestamp))
|
||||
let timeZone = try XCTUnwrap(TimeZone(abbreviation: "CEST"))
|
||||
let sunrise = RiseTime<Planet>(timeZone: timeZone,
|
||||
date: date,
|
||||
body: .sun,
|
||||
longitude: 13.41053,
|
||||
latitude: 52.52437,
|
||||
altitude: 0)
|
||||
XCTAssertEqual(sunrise.date?.description, "2021-03-14 07:22:32 +0000")
|
||||
let californiaTimeZone = try XCTUnwrap(TimeZone(identifier: "America/Los_Angeles"))
|
||||
let sunriseSantaCruz = RiseTime<Planet>(timeZone: californiaTimeZone,
|
||||
date: date,
|
||||
body: .sun,
|
||||
longitude: -122.0297222,
|
||||
latitude: 36.9741667,
|
||||
altitude: 0)
|
||||
XCTAssertEqual(sunriseSantaCruz.date?.description, "2021-03-14 07:19:44 +0000")
|
||||
let dateB = try XCTUnwrap(dateFormatter.date(from: "2021-03-15"))
|
||||
let newYorkTimeZone = try XCTUnwrap(TimeZone(identifier: "America/New_York"))
|
||||
let moonRiseNYC = RiseTime<Planet>(timeZone: newYorkTimeZone,
|
||||
date: dateB,
|
||||
body: .moon,
|
||||
longitude: -73.935242,
|
||||
latitude: 40.730610,
|
||||
altitude: 0)
|
||||
XCTAssertEqual(moonRiseNYC.date?.description, "2021-03-15 08:25:55 +0000")
|
||||
}
|
||||
|
||||
func testPlanetRisingTime() throws {
|
||||
let timestamp = "2021-03-14"
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.timeZone = TimeZone(identifier: "America/Los_Angeles")
|
||||
dateFormatter.dateFormat = "yyyy-MM-dd"
|
||||
let date = try XCTUnwrap(dateFormatter.date(from: timestamp))
|
||||
let sunriseSantaCruz = RiseTime<Planet>(date: date,
|
||||
body: .sun,
|
||||
longitude: -122.0297222,
|
||||
latitude: 36.9741667,
|
||||
altitude: 0)
|
||||
XCTAssertEqual(sunriseSantaCruz.date?.description, "2021-03-14 14:19:44 +0000")
|
||||
let dateB = try XCTUnwrap(dateFormatter.date(from: "2021-03-15"))
|
||||
let moonRiseNYC = RiseTime<Planet>(date: dateB,
|
||||
body: .moon,
|
||||
longitude: -73.935242,
|
||||
latitude: 40.730610,
|
||||
altitude: 0)
|
||||
XCTAssertEqual(moonRiseNYC.date?.description, "2021-03-15 12:25:55 +0000")
|
||||
}
|
||||
|
||||
func testPlanetSettingTime() throws {
|
||||
let timestamp = "2021-03-15"
|
||||
let timestamp = "2021-03-15"
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateFormat = "yyyy-MM-dd"
|
||||
let date = try XCTUnwrap(dateFormatter.date(from: timestamp))
|
||||
let timeZone = try XCTUnwrap(TimeZone(abbreviation: "CEST"))
|
||||
let moonSet = SetTime<Planet>(timeZone: timeZone,
|
||||
date: date,
|
||||
body: .moon,
|
||||
longitude: 13.41053,
|
||||
latitude: 52.52437)
|
||||
XCTAssertEqual(moonSet.date?.description, "2021-03-15 21:25:58 +0000")
|
||||
let dateB = try XCTUnwrap(dateFormatter.date(from: "2021-03-16"))
|
||||
let tokyoTimeZone = try XCTUnwrap(TimeZone(identifier: "Asia/Tokyo"))
|
||||
let sunsetTokyo = SetTime<Planet>(timeZone: tokyoTimeZone,
|
||||
date: dateB,
|
||||
let date = try XCTUnwrap(dateFormatter.date(from: timestamp))
|
||||
let moonSet = SetTime<Planet>(date: date,
|
||||
body: .moon,
|
||||
longitude: 13.41053,
|
||||
latitude: 52.52437)
|
||||
XCTAssertEqual(moonSet.date?.description, "2021-03-15 19:25:58 +0000")
|
||||
let dateB = try XCTUnwrap(dateFormatter.date(from: "2021-03-16"))
|
||||
let sunsetTokyo = SetTime<Planet>(date: dateB,
|
||||
body: .sun,
|
||||
longitude: 139.69171,
|
||||
latitude: 35.6895)
|
||||
XCTAssertEqual(sunsetTokyo.date?.description, "2021-03-16 17:49:34 +0000")
|
||||
XCTAssertEqual(sunsetTokyo.date?.description, "2021-03-16 08:49:34 +0000")
|
||||
}
|
||||
|
||||
func testLunarPhase() throws {
|
||||
|
|
|
@ -17,7 +17,6 @@ final class PerformanceTests: XCTestCase {
|
|||
for day in 0...1065 {
|
||||
Planet.allCases.forEach {
|
||||
XCTAssertNotNil(Coordinate<Planet>(body: $0, date: date))
|
||||
print("x")
|
||||
if #available(iOS 13.0, *) {
|
||||
date = date.advanced(by: (60 * 60 * 24) * TimeInterval(day))
|
||||
}
|
||||
|
@ -131,15 +130,6 @@ final class PerformanceTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testBatchRequestLunations() {
|
||||
let lunationsRequest = LunationsRequest()
|
||||
measure {
|
||||
lunationsRequest.fetch(start: date, end: date.addingTimeInterval(60 * 60 * 24 * 30), interval: 60 * 60) {
|
||||
XCTAssertEqual($0.count, 720)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static var allTests = [
|
||||
("testCoordinatePerformance",testCoordinatePerformance,
|
||||
|
@ -150,7 +140,6 @@ final class PerformanceTests: XCTestCase {
|
|||
"testAspectPerformance", testAspectPerformance,
|
||||
"testSpringEquinoxDatePerformance", testSpringEquinoxDatePerformance,
|
||||
"testAutumnalEquinoxDatePerformance", testAutumnalEquinoxDatePerformance,
|
||||
"testBatchRequestPlanetCoordinates", testBatchRequestPlanetCoordinates,
|
||||
"testBatchRequestLunations", testBatchRequestLunations)
|
||||
"testBatchRequestPlanetCoordinates", testBatchRequestPlanetCoordinates)
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue