首页 » 技术分享 » 计算日出日落算法实现

计算日出日落算法实现

 

首先感谢帮我算题的小玉玉~

算了一周的日出日落,倍觉痛苦,写下来防止下次再算。

根据经纬度和UTC计算日出日落的思路、算法及scala代码如下~

日出和日落的计算思路:

  • 一天的日出和日落可以根据正午时刻平分昼长得到。
  • 正午时刻可以根据所在时区和经度得到。
  • 根据经度可以知道所在时区。
  • 昼长可以根据太阳赤角和所在纬度计算得到。

符号说明:

rc:日出

rl:日落

zw:正午

day:昼长

zone:时区

δ:太阳赤纬

lon:经度

lat:纬度

N:每年一月一日到当前的天数

b:弧度制

计算公式:

time_{rc} = time_{zw} - time_{day}/2

time_{rl} = time_{zw} + time_{day}/2

time_{zw} = 12 + (time_{zone}*15 - lon)/15 

time_{zone} = (lon -7.5)/15\pm 1   当lon大于7.5时加一,小于7.5时减一

time_{day} = 24 - 24*\cos ^{^{-1}}(tan\Phi *tan(lat))/\pi

 δ=0.006918-0.399912*cos(b)+0.070257*sin(b)-0.006758*cos(2*b)+0.000907*sin(2*b)-0.002697*cos(3*b)+0.00148*sin(3*b)

b = 2*\pi *(N-1)/365  

例子: 

2018年3月1日上海(121.07,31.03)的日出日落。

所在时区 = (121.07 - 7.5)/15 +1 = 8

正午时刻 = 12 +(8*15 - 121.07)/15 = 11.93

距离年初的天数为59天

弧度b:1.0156381729413577
太阳赤纬delta:-0.13752063172367998

昼长:11.706427291331444

日出:1551391471

日落:1551433614

代码:

object TimeUtil {
  def main(args: Array[String]): Unit = {
      println(getDay(121.07,31.03,1551424419))
  }

  /**
    * 计算当地日出日落UTC
    */
  def getDay(lon: Double, lat: Double, utc: Int): (Int, Int) = {
    var day = 0;
    var rc = 0;
    var rl = 0;
    val lon_pai = Math.PI * (lon / 360)
    val lat_pai = Math.PI * (lat / 360)
    val time_zone = getTimeZone(lon) //时区

    val time_real = utc + time_zone * 3600 // 真实时间,计算出所在时区的本地时间
    println(time_real)
    val yearTimeStamp = getUtcYearStart(time_zone, time_real.toString) // 获取所在时区年份的UTC
    val N = (utc - yearTimeStamp) / 86400 // 一年中的第几天
    val b = (2 * Math.PI * N) / 365
    val delta = 0.006918 - 0.399912 * math.cos(b) + 0.070257 * math.sin(b) - 0.006758 * math.cos(2 * b) + 0.000907 * math.sin(2 * b) - 0.002697 * math.cos(3 * b) + 0.00148 * math.sin(3 * b)
    val gama = Math.PI / 2 - math.abs(delta)

    // 判断极昼、极夜
    if (delta >= 0) {
      if (lat_pai > gama) {
        rc = 1
      } else if (lat_pai < -gama) {
        rl = 1
      }
    } else if (delta < 0) {
      if (lat_pai > gama) {
        rl = 1
      } else if (lat_pai < -gama) {
        rc = 1
      }
    }
    if (lat_pai >= -gama && lat_pai <= gama) {
      var time_day = 24 - 24 * Math.acos(Math.tan(delta) * Math.tan(lat_pai)) / Math.PI //昼长
      var time_z = 12 + (time_zone * 15 - lon) / 15 //太阳正午时间
      var time_days = time_real / 86400 // 计算当地天数
      var time_rc = ((time_z - time_day / 2) * 3600 + time_days * 86400).toInt - time_zone * 3600
      var time_rl = ((time_z + time_day / 2) * 3600 + time_days * 86400).toInt - time_zone * 3600
      rc = time_rc
      rl = time_rl
    }
    (rc, rl)
  }

  /**
    * 计算时区
    */
  def getTimeZone(lon: Double): Int = {
    var time_zone = 0
    if (lon > 0) {
      if (lon > 7.5) {
        time_zone = ((lon - 7.5) / 15 + 1).toInt
      }
    } else if (lon < 0) {
      if (lon < -7.5) {
        time_zone = ((lon + 7.5) / 15 - 1).toInt
      }
    }
    (time_zone)
  }

  /**
    * 获取所在时区当天开始时间的UTC
    * (获取所在时区的当天日期,补全开始时间,并转化为UTC)
    */
  def getUtcNightStart(lon: Double, rc: String): Long = {
    val time_zone = getTimeZone(lon)
    val fm = new SimpleDateFormat("yyyy-MM-dd")
    val timeDay = fm.format(new Date((rc.toLong - 8 * 3600 + time_zone * 3600) * 1000)) // 所在时区的当天日期
    val date = fm.parse(timeDay)
    val timeHour = date.getTime / 1000 // 所在时区的当天日期在东八区的当天日期的时间戳
    val nightStart = timeHour + 8 * 3600 - time_zone * 3600 // 所在时区的当天日期开始时间所对应的UTC
    nightStart
  }

  /**
    * 计算所在时区当年的开始UTC
    */
  def getUtcYearStart(time_zone: Int, tm: String): Long = {
    val fm = new SimpleDateFormat("yyyy")
    val timeYear = fm.format(new Date((tm.toLong - 8 * 3600 + time_zone * 3600) * 1000)) // 所在时区的年份
    val dt = fm.parse(timeYear)
    val timeHour = dt.getTime() / 1000
    val yearStart = timeHour + 8 * 3600 - time_zone * 3600
    yearStart
  }
}

 

转载自原文链接, 如需删除请联系管理员。

原文链接:计算日出日落算法实现,转载请注明来源!

0