关于NSTimeZone.seconds的混淆从谷歌
我正在开发一个应用程序,该应用程序具有在夜间自动进入黑暗/夜间模式的功能。该应用程序要求用户的位置,并使用this algorithm确定日出/日落时间(在世界时)。关于NSTimeZone.seconds的混淆从谷歌
唯一不清楚的是从UT转换到本地时间,因为这在算法中没有解释。假设我的日出时间为8.5(早上UT为8:30)。我怎么能将它转换为用户当地的时间来检查它是白天还是夜晚?或者等价地,我如何将用户的本地时间转换为UT以便能够比较它们?
到目前为止,我已尝试使用NSCalendar
获取当前日期的NSDateComponents
(NSDate()
)。其中一个组件是NSTimeZone?
,我可以从中获得secondsFromGMT
。事情是这样的:
let dateComponents = NSCalendar.currentCalendar().components([.TimeZone], fromDate: NSDate())
let localOffset = Double(dateComponents.timeZone?.secondsFromGMT ?? 0)/3600
其中localOffset
应的时间差(以小时计)从UT(即格林尼治标准时间,如果我是正确的)本地时间,默认为0,如果dateComponents.timeZone == nil
(我不知道在哪些情况下这可能发生)。问题是,我现在比将来的6个月获得相同的localOffset
(夏令时与现在西班牙我的位置不同)。这是否意味着我需要使用属性daylightSavingTime
和/或daylightSavingTimeOffset
以及secondsFromGMT
? secondsFromGMT
本身是否占这个?
当我从算法中读取结果时,事情变得更加令人困惑。日落时间(当地时间)与Google给定的时间完全一致,但太阳升起时间比Google所说的(我的位置和日期)提前了一个小时。我与你分享了整个Swift算法的实现,希望能帮助别人发现我做错了什么。
import Foundation
import CoreLocation
enum SunriseSunsetZenith: Double {
case Official = 90.83
case Civil = 96
case Nautical = 102
case Astronomical = 108
}
func sunriseSunsetHoursForLocation(coordinate: CLLocationCoordinate2D, atDate date: NSDate = NSDate(), zenith: SunriseSunsetZenith = .Civil) -> (sunrise: Double, sunset: Double) {
// Initial values (will be changed later)
var sunriseTime = 7.5
var sunsetTime = 19.5
// Get the longitude and latitude
let latitude = coordinate.latitude
let longitude = coordinate.longitude
// Get the day, month, year and local offset
let dateComponents = NSCalendar.currentCalendar().components([.Day, .Month, .Year, .TimeZone], fromDate: date)
let day = Double(dateComponents.day)
let month = Double(dateComponents.month)
let year = Double(dateComponents.year)
let localOffset = Double(dateComponents.timeZone?.daylightSavingTimeOffset ?? 0)/3600
// Calculate the day of the year
let N1 = floor(275*month/9)
let N2 = floor((month + 9)/12)
let N3 = 1 + floor((year - 4*floor(year/4) + 2)/3)
let dayOfYear = N1 - N2*N3 + day - 30
for i in 0...1 {
// Convert the longitude to hour value and calculate an approximate time
let longitudeHour = longitude/15
let t = dayOfYear + ((i == 0 ? 6.0 : 18.0) - longitudeHour)/24
// Calculate the Sun's mean anomaly
let M = 0.9856*t - 3.289
// Calculate the Sun's true longitude
var L = M + 1.916*sind(M) + 0.020*sind(2*M) + 282.634
L %= 360
// Calculate the Sun's right ascension
var RA = atand(0.91764 * tand(L))
RA %= 360
let Lquadrant = (floor(L/90))*90
let RAquadrant = (floor(RA/90))*90
RA += Lquadrant - RAquadrant
RA /= 15
// Calculate the Sun's declination
let sinDec = 0.39782*sind(L)
let cosDec = cosd(asind(sinDec))
// Calculate the Sun's local hour angle
let cosH = (cosd(zenith.rawValue) - sinDec*sind(latitude))/(cosDec*cosd(latitude))
if cosH > 1 { // The sun never rises on this location (on the specified date)
sunriseTime = Double.infinity
sunsetTime = -Double.infinity
} else if cosH < -1 { // The sun never sets on this location (on the specified date)
sunriseTime = -Double.infinity
sunsetTime = Double.infinity
} else {
// Finish calculating H and convert into hours
var H = (i == 0 ? 360.0 : 0.0) + (i == 0 ? -1.0 : 1.0)*acosd(cosH)
H /= 15
// Calculate local mean time of rising/setting
let T = H + RA - 0.06571*t - 6.622
// Adjust back to UTC
let UT = T - longitudeHour
// Convert UT value to local time zone of latitude/longitude
let localT = UT + localOffset
if i == 0 { // Add 24 and modulo 24 to be sure that the results is between 0..<24
sunriseTime = (localT + 24)%24
} else {
sunsetTime = (localT + 24)%24
}
}
}
return (sunriseTime, sunsetTime)
}
func sind(valueInDegrees: Double) -> Double {
return sin(valueInDegrees*M_PI/180)
}
func cosd(valueInDegrees: Double) -> Double {
return cos(valueInDegrees*M_PI/180)
}
func tand(valueInDegrees: Double) -> Double {
return tan(valueInDegrees*M_PI/180)
}
func asind(valueInRadians: Double) -> Double {
return asin(valueInRadians)*180/M_PI
}
func acosd(valueInRadians: Double) -> Double {
return acos(valueInRadians)*180/M_PI
}
func atand(valueInRadians: Double) -> Double {
return atan(valueInRadians)*180/M_PI
}
答案这是我如何使用函数来确定,如果是晚上或者不:
let latitude = ...
let longitude = ...
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
let (sunriseHour, sunsetHour) = sunriseSunsetHoursForLocation(coordinate)
let componetns = NSCalendar.currentCalendar().components([.Hour, .Minute], fromDate: NSDate())
let currentHour = Double(componetns.hour) + Double(componetns.minute)/60
let isNight = currentHour < sunriseHour || currentHour > sunsetHour
我不知道为什么你的代码来获取偏移不工作(我得到了相同的结果)。但是有一个更简单的解决方案可以工作。只需询问当地时区,使用secondsFromGMTForDate
即可。日期相隔六个月,我得到了不同的结果:
let now = NSDate()
let future = NSCalendar.currentCalendar().dateByAddingUnit(NSCalendarUnit.Month, value: 6, toDate: now, options: NSCalendarOptions(rawValue: 0))!
let nowOffset = NSTimeZone.localTimeZone().secondsFromGMTForDate(now)/3600
let futureOffset = NSTimeZone.localTimeZone().secondsFromGMTForDate(future)/3600