From ad59d05a3901fba7f1e6abb92925380f539bb1c8 Mon Sep 17 00:00:00 2001 From: Brandon Roehl Date: Wed, 2 May 2018 13:35:22 -0500 Subject: [PATCH 1/9] Update to use in day and night by sharing a singular instance in memory that will auto manage updates --- README.md | 7 +- Solar iOSTests/Solar_iOSTests.swift | 27 +++--- Solar.xcodeproj/project.pbxproj | 2 + .../xcshareddata/xcschemes/Solar iOS.xcscheme | 6 +- Solar/Solar.swift | 83 +++++++++++-------- 5 files changed, 76 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index a02ce00..14a9979 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,11 @@ Solar performs its calculations locally using an algorithm from the [United Stat ## Usage + Solar simply needs a date and a location specified as a latitude and longitude: ```swift -let solar = Solar(for: someDate, latitude: 51.528308, longitude: -0.1340267) +let solar = Solar(for: someDate, CLLocationCoordinate2D(latitude: 51.528308, longitude: -0.1340267)) let sunrise = solar.sunrise let sunset = solar.sunset ``` @@ -24,11 +25,13 @@ let sunset = solar.sunset We can also omit providing a date if we just need the sunrise and sunset for today: ```swift -let solar = Solar(latitude: 51.528308, longitude: -0.1340267) +let solar = Solar(CLLocationCoordinate2D(latitude: 51.528308, longitude: -0.1340267)) let sunrise = solar.sunrise let sunset = solar.sunset ``` +Solar with then cache the calculation and update it as the time moves when you ask. + Note that all dates are UTC. Don't forget to format your date into the appropriate timezone if required. ### Types of sunrise and sunset diff --git a/Solar iOSTests/Solar_iOSTests.swift b/Solar iOSTests/Solar_iOSTests.swift index fca0ef5..5aa7814 100644 --- a/Solar iOSTests/Solar_iOSTests.swift +++ b/Solar iOSTests/Solar_iOSTests.swift @@ -86,8 +86,8 @@ final class Solar_iOSTests: XCTestCase { return } - XCTAssertTrue(solar.isDaytime, "isDaytime is false for date: \(daytime) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") - XCTAssertFalse(solar.isNighttime, "isNighttime is true for date: \(daytime) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertTrue(solar.isDayTime, "isDaytime is false for date: \(daytime) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertFalse(solar.isNightTime, "isNighttime is true for date: \(daytime) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") } func testIsDayTime_isTrue_exactlyAtSunrise() { @@ -101,8 +101,8 @@ final class Solar_iOSTests: XCTestCase { return } - XCTAssertTrue(solar.isDaytime, "isDaytime is false for date: \(sunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") - XCTAssertFalse(solar.isNighttime, "isNighttime is true for date: \(sunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertTrue(solar.isDayTime, "isDaytime is false for date: \(sunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertFalse(solar.isNightTime, "isNighttime is true for date: \(sunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") } func testIsDayTime_isFalse_exactlyAtSunset() { @@ -116,8 +116,8 @@ final class Solar_iOSTests: XCTestCase { return } - XCTAssertFalse(solar.isDaytime, "isDaytime is false for date: \(sunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") - XCTAssertTrue(solar.isNighttime, "isNighttime is true for date: \(sunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertFalse(solar.isDayTime, "isDaytime is false for date: \(sunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertTrue(solar.isNightTime, "isNighttime is true for date: \(sunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") } func testIsDayTime_isFalse_beforeSunrise() { @@ -131,8 +131,8 @@ final class Solar_iOSTests: XCTestCase { return } - XCTAssertFalse(solar.isDaytime, "isDaytime is true for date: \(beforeSunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") - XCTAssertTrue(solar.isNighttime, "isNighttime is false for date: \(beforeSunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertFalse(solar.isDayTime, "isDaytime is true for date: \(beforeSunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertTrue(solar.isNightTime, "isNighttime is false for date: \(beforeSunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") } func testIsDayTime_isFalse_afterSunset() { @@ -146,8 +146,8 @@ final class Solar_iOSTests: XCTestCase { return } - XCTAssertFalse(solar.isDaytime, "isDaytime is true for date: \(afterSunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") - XCTAssertTrue(solar.isNighttime, "isNighttime is false for date: \(afterSunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertFalse(solar.isDayTime, "isDaytime is true for date: \(afterSunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertTrue(solar.isNightTime, "isNighttime is false for date: \(afterSunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") } func testSolar_ShouldReturnNilOnInit_GivenInvalidcoordinate() { @@ -162,4 +162,11 @@ final class Solar_iOSTests: XCTestCase { let solar2 = Solar(for: testDate, coordinate: invalidCoordinate2) XCTAssertNil(solar2) } + + func testSolar_implicit_creation_for_currentTime() { + let city = cities.first(where: { $0.name == "London" })! + let solar = Solar(coordinate: city.coordinate) + + XCTAssertNotNil(solar, "Solar creation work without time") + } } diff --git a/Solar.xcodeproj/project.pbxproj b/Solar.xcodeproj/project.pbxproj index 6e68f73..2edaf17 100644 --- a/Solar.xcodeproj/project.pbxproj +++ b/Solar.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ 14456B861EF96ACA00D76A4D /* Solar_iOSTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Solar_iOSTests.swift; path = "Solar iOSTests/Solar_iOSTests.swift"; sourceTree = ""; }; 14456B891EF96AD900D76A4D /* CorrectResults.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = CorrectResults.json; path = "Solar iOSTests/CorrectResults.json"; sourceTree = ""; }; 14456B8A1EF96AD900D76A4D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = "Solar iOSTests/Info.plist"; sourceTree = ""; }; + 55C04150209A25A100A642BC /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 97837EAB1E4BB1DE000FEF64 /* Solar_iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Solar_iOSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; F7FC5B5A1D469B2700C4D3EB /* Solar.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Solar.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F7FC5B651D469B4E00C4D3EB /* Solar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Solar.swift; sourceTree = ""; }; @@ -97,6 +98,7 @@ F7FC5B5C1D469B2700C4D3EB /* Solar */, 14456B801EF96A8F00D76A4D /* Solar iOSTests */, F7FC5B5B1D469B2700C4D3EB /* Products */, + 55C04150209A25A100A642BC /* README.md */, ); sourceTree = ""; }; diff --git a/Solar.xcodeproj/xcshareddata/xcschemes/Solar iOS.xcscheme b/Solar.xcodeproj/xcshareddata/xcschemes/Solar iOS.xcscheme index 8579a27..afa0cd5 100644 --- a/Solar.xcodeproj/xcshareddata/xcschemes/Solar iOS.xcscheme +++ b/Solar.xcodeproj/xcshareddata/xcschemes/Solar iOS.xcscheme @@ -40,9 +40,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" - shouldUseLaunchSchemeArgsEnv = "YES" - codeCoverageEnabled = "YES"> + codeCoverageEnabled = "YES" + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -71,7 +70,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Solar/Solar.swift b/Solar/Solar.swift index d2d67e6..8feb2b9 100644 --- a/Solar/Solar.swift +++ b/Solar/Solar.swift @@ -27,27 +27,49 @@ import Foundation import CoreLocation -public struct Solar { +public class Solar { /// The coordinate that is used for the calculation public let coordinate: CLLocationCoordinate2D /// The date to generate sunrise / sunset times for - public fileprivate(set) var date: Date - - public fileprivate(set) var sunrise: Date? - public fileprivate(set) var sunset: Date? - public fileprivate(set) var civilSunrise: Date? - public fileprivate(set) var civilSunset: Date? - public fileprivate(set) var nauticalSunrise: Date? - public fileprivate(set) var nauticalSunset: Date? - public fileprivate(set) var astronomicalSunrise: Date? - public fileprivate(set) var astronomicalSunset: Date? + public var date: Date? { + didSet { + self.calculate() + } + } + public var zenith: Zenith { + didSet { + self.calculate() + } + } + + private var _sunrise: Date? + public var sunrise: Date? { + let date = self.date == nil ? Date() : self.date! + + if self._sunrise == nil || (self.date == nil && self._sunrise! < Date()) { + self._sunrise = calculate(.sunrise, for: date, and: zenith) + } + + return self._sunrise; + } + private var _sunset: Date? + public var sunset: Date? { + let date = self.date == nil ? Date() : self.date! + + if self._sunset == nil || (self.date == nil && self._sunset! < Date()) { + self._sunset = calculate(.sunset, for: date, and: zenith) + } + + return self._sunset; + } // MARK: Init - public init?(for date: Date = Date(), coordinate: CLLocationCoordinate2D) { + public init?(for date: Date? = nil, coordinate: CLLocationCoordinate2D, and zenith: Zenith = .official) { self.date = date + self.zenith = zenith guard CLLocationCoordinate2DIsValid(coordinate) else { return nil @@ -63,26 +85,20 @@ public struct Solar { /// Sets all of the Solar object's sunrise / sunset variables, if possible. /// - Note: Can return `nil` objects if sunrise / sunset does not occur on that day. - public mutating func calculate() { - sunrise = calculate(.sunrise, for: date, and: .official) - sunset = calculate(.sunset, for: date, and: .official) - civilSunrise = calculate(.sunrise, for: date, and: .civil) - civilSunset = calculate(.sunset, for: date, and: .civil) - nauticalSunrise = calculate(.sunrise, for: date, and: .nautical) - nauticalSunset = calculate(.sunset, for: date, and: .nautical) - astronomicalSunrise = calculate(.sunrise, for: date, and: .astronimical) - astronomicalSunset = calculate(.sunset, for: date, and: .astronimical) + public func calculate() { + self._sunrise = nil + self._sunrise = nil } // MARK: - Private functions - fileprivate enum SunriseSunset { + public enum SunriseSunset { case sunrise case sunset } /// Used for generating several of the possible sunrise / sunset times - fileprivate enum Zenith: Double { + public enum Zenith: Double { case official = 90.83 case civil = 96 case nautical = 102 @@ -90,6 +106,10 @@ public struct Solar { } fileprivate func calculate(_ sunriseSunset: SunriseSunset, for date: Date, and zenith: Zenith) -> Date? { + return Solar.calculate(sunriseSunset, at: coordinate, for: date, and: zenith) + } + + public static func calculate(_ sunriseSunset: SunriseSunset, at coordinate: CLLocationCoordinate2D, for date: Date, and zenith: Zenith) -> Date? { guard let utcTimezone = TimeZone(identifier: "UTC") else { return nil } // Get the day of the year @@ -157,7 +177,7 @@ public struct Solar { var UT = T - lngHour // Normalise UT into [0, 24] range - UT = normalise(UT, withMaximum: 24) + UT = Solar.normalise(UT, withMaximum: 24) // Calculate all of the sunrise's / sunset's date components let hour = floor(UT) @@ -186,7 +206,7 @@ public struct Solar { } /// Normalises a value between 0 and `maximum`, by adding or subtracting `maximum` - fileprivate func normalise(_ value: Double, withMaximum maximum: Double) -> Double { + fileprivate static func normalise(_ value: Double, withMaximum maximum: Double) -> Double { var value = value if value < 0 { @@ -206,17 +226,14 @@ extension Solar { /// Whether the location specified by the `latitude` and `longitude` is in daytime on `date` /// - Complexity: O(1) - public var isDaytime: Bool { - guard - let sunrise = sunrise, - let sunset = sunset - else { + public var isDayTime: Bool { + guard let sunrise = sunrise, let sunset = sunset else { return false } let beginningOfDay = sunrise.timeIntervalSince1970 let endOfDay = sunset.timeIntervalSince1970 - let currentTime = self.date.timeIntervalSince1970 + let currentTime = (self.date == nil ? Date() : self.date!).timeIntervalSince1970 let isSunriseOrLater = currentTime >= beginningOfDay let isBeforeSunset = currentTime < endOfDay @@ -226,8 +243,8 @@ extension Solar { /// Whether the location specified by the `latitude` and `longitude` is in nighttime on `date` /// - Complexity: O(1) - public var isNighttime: Bool { - return !isDaytime + public var isNightTime: Bool { + return !self.isDayTime } } From 6f5b3736e348e417e8f10bbeb0d16ff06fefa930 Mon Sep 17 00:00:00 2001 From: Brandon Roehl Date: Wed, 2 May 2018 13:42:56 -0500 Subject: [PATCH 2/9] MacOS Framework --- Solar.podspec | 6 +- Solar.xcodeproj/project.pbxproj | 138 +++++++++++++++++++++++++++++++- Solar/Info-iOS.plist | 2 +- Solar/Info-macOS.plist | 24 ++++++ Solar/Info-watchOS.plist | 2 +- 5 files changed, 164 insertions(+), 8 deletions(-) create mode 100644 Solar/Info-macOS.plist diff --git a/Solar.podspec b/Solar.podspec index f91c124..8914757 100644 --- a/Solar.podspec +++ b/Solar.podspec @@ -1,16 +1,16 @@ Pod::Spec.new do |s| s.name = "Solar" - s.version = "2.1.0" + s.version = "3.1.0" s.summary = "A Swift library for generating Sunrise and Sunset times." s.description = "A Swift library for generating Sunrise and Sunset times. All calculations take place locally without the need for a network request." s.homepage = "http://github.com/ceek/solar" s.license = { :type => "MIT", :file => "LICENSE" } - s.author = { "Chris Howell" => "chris.kevin.howell@gmail.com" } + s.author = { "Chris Howell" => "chris.kevin.howell@gmail.com" } s.ios.deployment_target = '8.0' s.watchos.deployment_target = '3.0' s.tvos.deployment_target = '9.0' s.osx.deployment_target = '10.9' - s.source = { :git => "https://github.com/ceek/Solar.git", :tag => "#{s.version}" } + s.source = { :git => "https://github.com/ceek/Solar.git", :tag => "#{s.version}" } s.source_files = "Solar/*.{swift}" s.requires_arc = true end diff --git a/Solar.xcodeproj/project.pbxproj b/Solar.xcodeproj/project.pbxproj index 2edaf17..8182424 100644 --- a/Solar.xcodeproj/project.pbxproj +++ b/Solar.xcodeproj/project.pbxproj @@ -34,6 +34,9 @@ 14456B891EF96AD900D76A4D /* CorrectResults.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = CorrectResults.json; path = "Solar iOSTests/CorrectResults.json"; sourceTree = ""; }; 14456B8A1EF96AD900D76A4D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = "Solar iOSTests/Info.plist"; sourceTree = ""; }; 55C04150209A25A100A642BC /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 55D65083209A3D1800D69A50 /* Solar_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Solar_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 55D65093209A3D5D00D69A50 /* Info-macOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-macOS.plist"; sourceTree = ""; }; + 55D65098209A3DEF00D69A50 /* Solar.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = Solar.podspec; sourceTree = ""; }; 97837EAB1E4BB1DE000FEF64 /* Solar_iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Solar_iOSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; F7FC5B5A1D469B2700C4D3EB /* Solar.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Solar.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F7FC5B651D469B4E00C4D3EB /* Solar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Solar.swift; sourceTree = ""; }; @@ -47,6 +50,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 55D6507F209A3D1800D69A50 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97837EA81E4BB1DE000FEF64 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -99,6 +109,7 @@ 14456B801EF96A8F00D76A4D /* Solar iOSTests */, F7FC5B5B1D469B2700C4D3EB /* Products */, 55C04150209A25A100A642BC /* README.md */, + 55D65098209A3DEF00D69A50 /* Solar.podspec */, ); sourceTree = ""; }; @@ -108,6 +119,7 @@ F7FC5B5A1D469B2700C4D3EB /* Solar.framework */, 97837EAB1E4BB1DE000FEF64 /* Solar_iOSTests.xctest */, 1410E9C01EF12B5A001829A5 /* Solar.framework */, + 55D65083209A3D1800D69A50 /* Solar_macOS.framework */, ); name = Products; sourceTree = ""; @@ -117,6 +129,7 @@ children = ( F7FC5B651D469B4E00C4D3EB /* Solar.swift */, 1410E9B71EF12AD4001829A5 /* Info-iOS.plist */, + 55D65093209A3D5D00D69A50 /* Info-macOS.plist */, 1410E9B81EF12AD4001829A5 /* Info-watchOS.plist */, ); path = Solar; @@ -132,6 +145,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 55D65080209A3D1800D69A50 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; F7FC5B571D469B2700C4D3EB /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -160,6 +180,24 @@ productReference = 1410E9C01EF12B5A001829A5 /* Solar.framework */; productType = "com.apple.product-type.framework"; }; + 55D65082209A3D1800D69A50 /* Solar_macOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 55D6508A209A3D1900D69A50 /* Build configuration list for PBXNativeTarget "Solar_macOS" */; + buildPhases = ( + 55D6507E209A3D1800D69A50 /* Sources */, + 55D6507F209A3D1800D69A50 /* Frameworks */, + 55D65080209A3D1800D69A50 /* Headers */, + 55D65081209A3D1800D69A50 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Solar_macOS; + productName = Solar_macOS; + productReference = 55D65083209A3D1800D69A50 /* Solar_macOS.framework */; + productType = "com.apple.product-type.framework"; + }; 97837EAA1E4BB1DE000FEF64 /* Solar_iOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = 97837EB51E4BB1DE000FEF64 /* Build configuration list for PBXNativeTarget "Solar_iOSTests" */; @@ -210,9 +248,14 @@ CreatedOnToolsVersion = 8.3.3; ProvisioningStyle = Manual; }; + 55D65082209A3D1800D69A50 = { + CreatedOnToolsVersion = 9.3; + DevelopmentTeam = V7JGZY6Z4Z; + ProvisioningStyle = Automatic; + }; 97837EAA1E4BB1DE000FEF64 = { CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = 34J4G6G665; + DevelopmentTeam = V7JGZY6Z4Z; LastSwiftMigration = 0900; ProvisioningStyle = Automatic; }; @@ -236,6 +279,7 @@ targets = ( F7FC5B591D469B2700C4D3EB /* Solar_iOS */, 1410E9BF1EF12B5A001829A5 /* Solar_watchOS */, + 55D65082209A3D1800D69A50 /* Solar_macOS */, 97837EAA1E4BB1DE000FEF64 /* Solar_iOSTests */, ); }; @@ -249,6 +293,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 55D65081209A3D1800D69A50 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97837EA91E4BB1DE000FEF64 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -275,6 +326,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 55D6507E209A3D1800D69A50 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97837EA71E4BB1DE000FEF64 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -356,11 +414,76 @@ }; name = Release; }; + 55D65088209A3D1900D69A50 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = V7JGZY6Z4Z; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = "$(SRCROOT)/Solar/Info-macOS.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.13; + PRODUCT_BUNDLE_IDENTIFIER = "me.chrishowell.Solar-macOS"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 55D65089209A3D1900D69A50 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = V7JGZY6Z4Z; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = "$(SRCROOT)/Solar/Info-macOS.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.13; + PRODUCT_BUNDLE_IDENTIFIER = "me.chrishowell.Solar-macOS"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; 97837EB31E4BB1DE000FEF64 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - DEVELOPMENT_TEAM = 34J4G6G665; + DEVELOPMENT_TEAM = V7JGZY6Z4Z; INFOPLIST_FILE = "Solar iOSTests/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = me.chrishowell.SolarTests; @@ -375,7 +498,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - DEVELOPMENT_TEAM = 34J4G6G665; + DEVELOPMENT_TEAM = V7JGZY6Z4Z; INFOPLIST_FILE = "Solar iOSTests/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = me.chrishowell.SolarTests; @@ -552,6 +675,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 55D6508A209A3D1900D69A50 /* Build configuration list for PBXNativeTarget "Solar_macOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 55D65088209A3D1900D69A50 /* Debug */, + 55D65089209A3D1900D69A50 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 97837EB51E4BB1DE000FEF64 /* Build configuration list for PBXNativeTarget "Solar_iOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Solar/Info-iOS.plist b/Solar/Info-iOS.plist index f69838d..4c70e90 100644 --- a/Solar/Info-iOS.plist +++ b/Solar/Info-iOS.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.1.0 + 3.1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass diff --git a/Solar/Info-macOS.plist b/Solar/Info-macOS.plist new file mode 100644 index 0000000..4c70e90 --- /dev/null +++ b/Solar/Info-macOS.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 3.1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Solar/Info-watchOS.plist b/Solar/Info-watchOS.plist index f69838d..4c70e90 100644 --- a/Solar/Info-watchOS.plist +++ b/Solar/Info-watchOS.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.1.0 + 3.1.0 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass From c6303eaa5837515742da6afb14edd25f6094e35c Mon Sep 17 00:00:00 2001 From: Brandon Roehl Date: Wed, 2 May 2018 13:47:55 -0500 Subject: [PATCH 3/9] Update header --- Solar/Solar.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Solar/Solar.swift b/Solar/Solar.swift index 8feb2b9..44bbfc5 100644 --- a/Solar/Solar.swift +++ b/Solar/Solar.swift @@ -3,7 +3,7 @@ // SolarExample // // Created by Chris Howell on 16/01/2016. -// Copyright © 2016 Chris Howell. All rights reserved. +// Changed by Brandon Roehl on 02/05/2018. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the “Software”), to deal From 028a1af20c8778803686416ee95eba66c2cf041d Mon Sep 17 00:00:00 2001 From: Brandon Roehl Date: Wed, 2 May 2018 15:59:29 -0500 Subject: [PATCH 4/9] Update to now be self contained and overridable --- Solar/Solar.swift | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/Solar/Solar.swift b/Solar/Solar.swift index 44bbfc5..166dd05 100644 --- a/Solar/Solar.swift +++ b/Solar/Solar.swift @@ -30,19 +30,9 @@ import CoreLocation public class Solar { /// The coordinate that is used for the calculation - public let coordinate: CLLocationCoordinate2D - - /// The date to generate sunrise / sunset times for - public var date: Date? { - didSet { - self.calculate() - } - } - public var zenith: Zenith { - didSet { - self.calculate() - } - } + private let coordinate: CLLocationCoordinate2D + private var date: Date? + private var zenith: Zenith private var _sunrise: Date? public var sunrise: Date? { @@ -219,39 +209,44 @@ public class Solar { return value } - -} -extension Solar { - + public enum Cycle { + case day + case night + } + /// Whether the location specified by the `latitude` and `longitude` is in daytime on `date` /// - Complexity: O(1) - public var isDayTime: Bool { + public var currentCycle: Cycle { guard let sunrise = sunrise, let sunset = sunset else { - return false + return .day } - + let beginningOfDay = sunrise.timeIntervalSince1970 let endOfDay = sunset.timeIntervalSince1970 let currentTime = (self.date == nil ? Date() : self.date!).timeIntervalSince1970 - + let isSunriseOrLater = currentTime >= beginningOfDay let isBeforeSunset = currentTime < endOfDay - - return isSunriseOrLater && isBeforeSunset + + return isSunriseOrLater && isBeforeSunset ? .day : .night + } + + public var isDayTime: Bool { + return self.currentCycle == .day } /// Whether the location specified by the `latitude` and `longitude` is in nighttime on `date` /// - Complexity: O(1) public var isNightTime: Bool { - return !self.isDayTime + return self.currentCycle == .night } } // MARK: - Helper extensions -private extension Double { +fileprivate extension Double { var degreesToRadians: Double { return Double(self) * (Double.pi / 180.0) } From c6e40a6d02835e484508622c3b1c4981fb85d71e Mon Sep 17 00:00:00 2001 From: Brandon Roehl Date: Wed, 2 May 2018 16:04:29 -0500 Subject: [PATCH 5/9] Realized I didn't know that it was one word --- Solar iOSTests/Solar_iOSTests.swift | 20 ++++++++++---------- Solar/Solar.swift | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Solar iOSTests/Solar_iOSTests.swift b/Solar iOSTests/Solar_iOSTests.swift index 5aa7814..ab8fbee 100644 --- a/Solar iOSTests/Solar_iOSTests.swift +++ b/Solar iOSTests/Solar_iOSTests.swift @@ -86,8 +86,8 @@ final class Solar_iOSTests: XCTestCase { return } - XCTAssertTrue(solar.isDayTime, "isDaytime is false for date: \(daytime) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") - XCTAssertFalse(solar.isNightTime, "isNighttime is true for date: \(daytime) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertTrue(solar.isDaytime, "isDaytime is false for date: \(daytime) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertFalse(solar.isNighttime, "isNighttime is true for date: \(daytime) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") } func testIsDayTime_isTrue_exactlyAtSunrise() { @@ -101,8 +101,8 @@ final class Solar_iOSTests: XCTestCase { return } - XCTAssertTrue(solar.isDayTime, "isDaytime is false for date: \(sunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") - XCTAssertFalse(solar.isNightTime, "isNighttime is true for date: \(sunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertTrue(solar.isDaytime, "isDaytime is false for date: \(sunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertFalse(solar.isNighttime, "isNighttime is true for date: \(sunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") } func testIsDayTime_isFalse_exactlyAtSunset() { @@ -116,8 +116,8 @@ final class Solar_iOSTests: XCTestCase { return } - XCTAssertFalse(solar.isDayTime, "isDaytime is false for date: \(sunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") - XCTAssertTrue(solar.isNightTime, "isNighttime is true for date: \(sunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertFalse(solar.isDaytime, "isDaytime is false for date: \(sunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertTrue(solar.isNighttime, "isNighttime is true for date: \(sunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") } func testIsDayTime_isFalse_beforeSunrise() { @@ -131,8 +131,8 @@ final class Solar_iOSTests: XCTestCase { return } - XCTAssertFalse(solar.isDayTime, "isDaytime is true for date: \(beforeSunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") - XCTAssertTrue(solar.isNightTime, "isNighttime is false for date: \(beforeSunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertFalse(solar.isDaytime, "isDaytime is true for date: \(beforeSunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertTrue(solar.isNighttime, "isNighttime is false for date: \(beforeSunrise) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") } func testIsDayTime_isFalse_afterSunset() { @@ -146,8 +146,8 @@ final class Solar_iOSTests: XCTestCase { return } - XCTAssertFalse(solar.isDayTime, "isDaytime is true for date: \(afterSunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") - XCTAssertTrue(solar.isNightTime, "isNighttime is false for date: \(afterSunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertFalse(solar.isDaytime, "isDaytime is true for date: \(afterSunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") + XCTAssertTrue(solar.isNighttime, "isNighttime is false for date: \(afterSunset) with sunrise: \(solar.sunrise!), sunset: \(solar.sunset!)") } func testSolar_ShouldReturnNilOnInit_GivenInvalidcoordinate() { diff --git a/Solar/Solar.swift b/Solar/Solar.swift index 166dd05..b3b507e 100644 --- a/Solar/Solar.swift +++ b/Solar/Solar.swift @@ -232,13 +232,13 @@ public class Solar { return isSunriseOrLater && isBeforeSunset ? .day : .night } - public var isDayTime: Bool { + public var isDaytime: Bool { return self.currentCycle == .day } /// Whether the location specified by the `latitude` and `longitude` is in nighttime on `date` /// - Complexity: O(1) - public var isNightTime: Bool { + public var isNighttime: Bool { return self.currentCycle == .night } From 25aedf835bc4e963eb3354039d5ab1021053b5fe Mon Sep 17 00:00:00 2001 From: Brandon Roehl Date: Sat, 19 May 2018 11:49:27 -0500 Subject: [PATCH 6/9] Fix for a very just before sunset if you init one in Minnesota it will move to the next day when it is actually the previous and incorrectly state it is night. --- .../project.xcworkspace/contents.xcworkspacedata | 5 ++++- Solar/Solar.swift | 15 ++++++++------- Test.playground/Contents.swift | 16 ++++++++++++++++ Test.playground/contents.xcplayground | 4 ++++ 4 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 Test.playground/Contents.swift create mode 100644 Test.playground/contents.xcplayground diff --git a/Solar.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Solar.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 211a933..4fe62dd 100644 --- a/Solar.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/Solar.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,9 @@ + location = "group:../Test.playground"> + + diff --git a/Solar/Solar.swift b/Solar/Solar.swift index b3b507e..18f713a 100644 --- a/Solar/Solar.swift +++ b/Solar/Solar.swift @@ -68,7 +68,7 @@ public class Solar { self.coordinate = coordinate // Fill this Solar object with relevant data - calculate() + self.calculate() } // MARK: - Public functions @@ -218,18 +218,19 @@ public class Solar { /// Whether the location specified by the `latitude` and `longitude` is in daytime on `date` /// - Complexity: O(1) public var currentCycle: Cycle { + guard let sunrise = sunrise, let sunset = sunset else { return .day } - let beginningOfDay = sunrise.timeIntervalSince1970 - let endOfDay = sunset.timeIntervalSince1970 - let currentTime = (self.date == nil ? Date() : self.date!).timeIntervalSince1970 + // Get the seconds of the begining of the day + let beginningOfDay = sunrise.timeIntervalSince1970.truncatingRemainder(dividingBy: 86400) - let isSunriseOrLater = currentTime >= beginningOfDay - let isBeforeSunset = currentTime < endOfDay + // Set the beginging of the day to zero + let endOfDay = sunset.timeIntervalSince1970.advanced(by: -(beginningOfDay)).truncatingRemainder(dividingBy: 86400) + let currentTime = (self.date == nil ? Date() : self.date!).timeIntervalSince1970.advanced(by: -(beginningOfDay)).truncatingRemainder(dividingBy: 86400) - return isSunriseOrLater && isBeforeSunset ? .day : .night + return currentTime < endOfDay ? .day : .night } public var isDaytime: Bool { diff --git a/Test.playground/Contents.swift b/Test.playground/Contents.swift new file mode 100644 index 0000000..464a92b --- /dev/null +++ b/Test.playground/Contents.swift @@ -0,0 +1,16 @@ +//: Playground - noun: a place where people can play + +import Cocoa +import CoreLocation + +var str = "Hello, playground" + +//var s: Solar! + +//var zeniths = [Solar.Zenith.astronimical, Solar.Zenith.civil, Solar.Zenith.nautical, Solar.Zenith.official] + +//for z in zeniths { +// s = Solar(coordinate: CLLocationCoordinate2D(latitude: 44.797484778259694, longitude: -91.501051055183325), and: z) +// s?.sunrise +// s?.sunset +//} diff --git a/Test.playground/contents.xcplayground b/Test.playground/contents.xcplayground new file mode 100644 index 0000000..63b6dd8 --- /dev/null +++ b/Test.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 9e1e6136ba77d37a0271cd3d13764b7a1c7ced67 Mon Sep 17 00:00:00 2001 From: Brandon Roehl Date: Sat, 21 Jul 2018 19:29:08 -0500 Subject: [PATCH 7/9] else if to reduce the secondary check --- Solar/Solar.swift | 4 +--- Test.playground/Sources/Solar.swift | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) create mode 120000 Test.playground/Sources/Solar.swift diff --git a/Solar/Solar.swift b/Solar/Solar.swift index 18f713a..7e772aa 100644 --- a/Solar/Solar.swift +++ b/Solar/Solar.swift @@ -201,9 +201,7 @@ public class Solar { if value < 0 { value += maximum - } - - if value > maximum { + } else if value > maximum { value -= maximum } diff --git a/Test.playground/Sources/Solar.swift b/Test.playground/Sources/Solar.swift new file mode 120000 index 0000000..0412c1b --- /dev/null +++ b/Test.playground/Sources/Solar.swift @@ -0,0 +1 @@ +../../Solar/Solar.swift \ No newline at end of file From 1f0f0dca04a43e6df4e1077dc86951b9e54a5967 Mon Sep 17 00:00:00 2001 From: Brandon Roehl Date: Fri, 14 Sep 2018 12:27:14 -0500 Subject: [PATCH 8/9] Abstract out const --- Solar/Solar.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Solar/Solar.swift b/Solar/Solar.swift index 7e772aa..5dbf538 100644 --- a/Solar/Solar.swift +++ b/Solar/Solar.swift @@ -28,6 +28,7 @@ import Foundation import CoreLocation public class Solar { + public static let lengthOfDay: TimeInterval = 86400 /// The coordinate that is used for the calculation private let coordinate: CLLocationCoordinate2D @@ -222,11 +223,11 @@ public class Solar { } // Get the seconds of the begining of the day - let beginningOfDay = sunrise.timeIntervalSince1970.truncatingRemainder(dividingBy: 86400) + let beginningOfDay = sunrise.timeIntervalSince1970.truncatingRemainder(dividingBy: Solar.lengthOfDay) // Set the beginging of the day to zero - let endOfDay = sunset.timeIntervalSince1970.advanced(by: -(beginningOfDay)).truncatingRemainder(dividingBy: 86400) - let currentTime = (self.date == nil ? Date() : self.date!).timeIntervalSince1970.advanced(by: -(beginningOfDay)).truncatingRemainder(dividingBy: 86400) + let endOfDay = sunset.timeIntervalSince1970.advanced(by: -(beginningOfDay)).truncatingRemainder(dividingBy: Solar.lengthOfDay) + let currentTime = (self.date == nil ? Date() : self.date!).timeIntervalSince1970.advanced(by: -(beginningOfDay)).truncatingRemainder(dividingBy: Solar.lengthOfDay) return currentTime < endOfDay ? .day : .night } From a8ae202fe039b9108b13eae1c6991f66f5ccbcd2 Mon Sep 17 00:00:00 2001 From: Brandon Roehl Date: Fri, 14 Sep 2018 12:28:10 -0500 Subject: [PATCH 9/9] Removed the playground --- Test.playground/Contents.swift | 16 ---------------- Test.playground/Sources/Solar.swift | 1 - Test.playground/contents.xcplayground | 4 ---- 3 files changed, 21 deletions(-) delete mode 100644 Test.playground/Contents.swift delete mode 120000 Test.playground/Sources/Solar.swift delete mode 100644 Test.playground/contents.xcplayground diff --git a/Test.playground/Contents.swift b/Test.playground/Contents.swift deleted file mode 100644 index 464a92b..0000000 --- a/Test.playground/Contents.swift +++ /dev/null @@ -1,16 +0,0 @@ -//: Playground - noun: a place where people can play - -import Cocoa -import CoreLocation - -var str = "Hello, playground" - -//var s: Solar! - -//var zeniths = [Solar.Zenith.astronimical, Solar.Zenith.civil, Solar.Zenith.nautical, Solar.Zenith.official] - -//for z in zeniths { -// s = Solar(coordinate: CLLocationCoordinate2D(latitude: 44.797484778259694, longitude: -91.501051055183325), and: z) -// s?.sunrise -// s?.sunset -//} diff --git a/Test.playground/Sources/Solar.swift b/Test.playground/Sources/Solar.swift deleted file mode 120000 index 0412c1b..0000000 --- a/Test.playground/Sources/Solar.swift +++ /dev/null @@ -1 +0,0 @@ -../../Solar/Solar.swift \ No newline at end of file diff --git a/Test.playground/contents.xcplayground b/Test.playground/contents.xcplayground deleted file mode 100644 index 63b6dd8..0000000 --- a/Test.playground/contents.xcplayground +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file