关于NSTimeZone.secondsFromGMT

时间:2015-12-10 22:30:42

标签: ios nsdate core-location nscalendar nstimezone

我正在开发一款具有夜间自动进入暗夜模式功能的应用。该应用程序询问用户位置并使用this algorithm确定日出/日落时数(以世界时间计)。

唯一不明确的步骤是从UT转换为本地时间,因为算法中没有解释这一点。假设我的日出时间是8.5(早上8点30分)。如何将其转换为用户的当地时间以检查是白天还是晚上?或者等效地,我如何将用户的本地时间转换为UT以便能够比较它们?

到目前为止,我已尝试使用NSCalendar获取当前日期的NSDateComponentsNSDate())。其中一个组件是NSTimeZone?,我可以从secondsFromGMT获取let dateComponents = NSCalendar.currentCalendar().components([.TimeZone], fromDate: NSDate()) let localOffset = Double(dateComponents.timeZone?.secondsFromGMT ?? 0)/3600 。像这样:

localOffset

其中dateComponents.timeZone == nil应该是UT的时间差(以小时为单位)(即如果我是正确的GMT)到当地时间,如果localOffset则默认为0(我不知道在哪种情况下)这可能发生)。问题是我现在得到的daylightSavingTime比未来的6个月(当夏令时不同于我现在在西班牙的时候)。这是否意味着我需要将属性daylightSavingTimeOffset和/或secondsFromGMTsecondsFromGMT一起使用? 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 } 本身不会解释这个问题吗?

当我从算法中读取结果时,事情变得更加混乱。太阳下​​山时间(当地时间)正好是谷歌提供的时间,但是太阳升起的时间比Google说的要早一个小时(对于我的位置和日期)。我与你分享整个Swift算法的实现,希望它可以帮助别人发现我做错了什么。

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

这是我使用该功能确定是否是夜晚的方法:

$.onFileUpload(event);

1 个答案:

答案 0 :(得分:1)

我不确定为什么你的代码得到偏移不起作用(我得到了相同的结果)。但是有一个更简单的解决方案可行。只需使用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