HarmonyOS 鸿蒙Next中如何根据当前位置获取日落时间

HarmonyOS 鸿蒙Next中如何根据当前位置获取日落时间 在鸿蒙应用开发中,“根据当前位置获取日落时间” 是很多场景化应用的核心功能 —— 无论是运动类 APP 的 “日落跑步提醒”、出行类 APP 的 “傍晚行程规划”,还是生活类 APP 的 “日落氛围场景推荐”,都离不开这一基础能力的支撑。掌握该功能的实现逻辑,能让你的鸿蒙应用更贴合用户的实时场景需求,提升产品的实用性与体验感。

本文将聚焦鸿蒙应用开发中 “位置与日落时间联动” 的核心实现思路:首先需要通过鸿蒙系统提供的位置服务(Location Kit) 获取设备当前的经纬度信息,这是计算日落时间的核心前提;接着需基于经纬度,结合天文算法(如太阳赤纬、时角计算逻辑) 推导日落时刻,也可借助第三方天文服务 API 快速获取精准结果;最后通过鸿蒙的时间格式化工具将结果转换为用户易读的本地时间格式

核心算法如下

/**
 * 日落时间计算工具类(纯算法实现)
 * 需传入已获取的经纬度,无需处理位置权限和获取逻辑
 */
export class SunsetAlgorithm {
  /**
   * 计算日落时间
   * @param latitude 纬度(度,如深圳:22.62)
   * @param longitude 经度(度,如深圳:114.07)
   * @param date 日期(默认当前日期)
   * @returns 日落时间(格式:HH:mm,本地时间,基于东八区)
   */
  static calculateSunset(
    latitude: number,
    longitude: number,
    date: Date = new Date()
  ): string | null {
    try {
      // 1. 将日期转换为儒略日
      let julianDay = SunsetAlgorithm.dateToJulianDay(date);

      // 2. 计算从J2000.0纪元开始的天数
      let n = julianDay - 2451545.0;

      // 3. 计算太阳黄经(度)
      let L = SunsetAlgorithm.normalizeAngle(280.46646 + 0.9856474 * n);

      // 4. 计算太阳近点角(度)
      let g = SunsetAlgorithm.normalizeAngle(357.52911 + 0.98560028 * n);

      // 5. 计算太阳赤纬(度)
      let sunDeclination = SunsetAlgorithm.calculateSunDeclination(L, g);

      // 6. 计算日落时角(度)
      let hourAngle = SunsetAlgorithm.calculateHourAngle(latitude, sunDeclination);
      if (hourAngle === null) {
        return "极昼/极夜区域";
      }

      // 7. 计算时差(分钟)
      let equationOfTime = SunsetAlgorithm.calculateEquationOfTime(g);

      // 8. 计算当地日落时间(UTC小时)
      let utcHours = 12 + (hourAngle / 15) - (longitude / 15) - (equationOfTime / 60);

      // 9. 转换为东八区时间(UTC+8)
      let localHours = utcHours + 8;

      // 10. 规范化时间(0-24小时)
      localHours = SunsetAlgorithm.normalizeHours(localHours);

      // 11. 格式化输出
      return SunsetAlgorithm.formatTime(localHours);
    } catch (error) {
      console.error("日落时间计算失败:", error);
      return null;
    }
  }

  /**
   * 日期转换为儒略日
   */
  private static dateToJulianDay(date: Date): number {
    let year = date.getFullYear();
    let month = date.getMonth() + 1; // 1-12月
    let day = date.getDate() +
      date.getHours() / 24 +
      date.getMinutes() / 1440 +
      date.getSeconds() / 86400;

    // 1-2月视为上一年的13-14月
    if (month <= 2) {
      month += 12;
      year--;
    }

    let a = Math.floor(year / 100);
    let b = 2 - a + Math.floor(a / 4); // 格里高利历修正

    return Math.floor(365.25 * (year + 4716)) +
    Math.floor(30.6001 * (month + 1)) +
      day + b - 1524.5;
  }

  /**
   * 计算太阳赤纬(度)
   */
  private static calculateSunDeclination(sunLongitude: number, anomaly: number): number {
    // 黄赤交角(度)
    let epsilon = 23.43929111;

    // 太阳真经度(考虑近点角影响)
    let trueLongitude = sunLongitude + 1.914666471 * Math.sin(SunsetAlgorithm.degToRad(anomaly)) +
      0.019994643 * Math.sin(SunsetAlgorithm.degToRad(2 * anomaly));

    // 计算太阳赤纬
    let trueLongitudeRad = SunsetAlgorithm.degToRad(trueLongitude);
    let epsilonRad = SunsetAlgorithm.degToRad(epsilon);

    // 加入大气折射修正
    return SunsetAlgorithm.radToDeg(Math.asin(Math.sin(epsilonRad) * Math.sin(trueLongitudeRad))) - 0.01;
  }

  /**
   * 计算日落时角(度)
   */
  private static calculateHourAngle(latitude: number, sunDeclination: number): number | null {
    let latRad = SunsetAlgorithm.degToRad(latitude);
    let decRad = SunsetAlgorithm.degToRad(sunDeclination);

    // 日落时太阳中心低于地平线0.833度(考虑大气折射)
    let h0 = SunsetAlgorithm.degToRad(-0.833);

    // 时角计算公式
    let cosH = (Math.sin(h0) - Math.sin(latRad) * Math.sin(decRad)) /
      (Math.cos(latRad) * Math.cos(decRad));

    // 极昼/极夜区域检查
    if (cosH < -1) return 180;  // 极昼,太阳永不落下
    if (cosH > 1) return null;   // 极夜,太阳永不升起

    return SunsetAlgorithm.radToDeg(Math.acos(cosH));
  }

  /**
   * 计算时差(分钟)
   */
  private static calculateEquationOfTime(anomaly: number): number {
    let gRad = SunsetAlgorithm.degToRad(anomaly);
    return 229.18 * (
      0.000075 +
        0.001868 * Math.cos(gRad) -
        0.032077 * Math.sin(gRad) -
        0.014615 * Math.cos(2 * gRad) -
        0.040849 * Math.sin(2 * gRad)
    );
  }

  /**
   * 规范化角度到0-360度
   */
  private static normalizeAngle(angle: number): number {
    angle = angle % 360;
    return angle < 0 ? angle + 360 : angle;
  }

  /**
   * 规范化小时到0-24小时
   */
  private static normalizeHours(hours: number): number {
    hours = hours % 24;
    return hours < 0 ? hours + 24 : hours;
  }

  /**
   * 格式化时间为HH:mm
   */
  private static formatTime(hours: number): string {
    let h = Math.floor(hours);
    let m = Math.round((hours - h) * 60);

    // 处理分钟进位
    let adjustedH = h;
    let adjustedM = m;
    if (adjustedM >= 60) {
      adjustedM -= 60;
      adjustedH = (adjustedH + 1) % 24;
    }

    return `${adjustedH.toString().padStart(2, '0')}:${adjustedM.toString().padStart(2, '0')}`;
  }

  /**
   * 角度转弧度
   */
  private static degToRad(deg: number): number {
    return deg * Math.PI / 180;
  }

  /**
   * 弧度转角度
   */
  private static radToDeg(rad: number): number {
    return rad * 180 / Math.PI;
  }
}

//获取日落时间
export function getSunsetTime(){
  // 假设已获取深圳经纬度:北纬22.62°,东经114.07°
  // let Longitude = 114.07;
  // let Latitude = 22.62;
  // 假设贵阳的经纬度范围为东经106°07′~107°17′,北纬26°11′~27°22′。
  let Longitude = 106.07;
  let Latitude = 26.16;
  let sunset =SunsetAlgorithm.calculateSunset(Latitude, Longitude);
  return  sunset   //如 2025-09-14日 返回  18:31
}

更多关于HarmonyOS 鸿蒙Next中如何根据当前位置获取日落时间的实战教程也可以访问 https://www.itying.com/category-93-b0.html

4 回复

学习

更多关于HarmonyOS 鸿蒙Next中如何根据当前位置获取日落时间的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,可通过geoLocationManager获取设备当前位置的经纬度。使用@ohos.sunsetSunrise模块的getSunsetTime方法,传入经纬度及日期参数,即可返回指定日期的日落时间(UTC时间戳)。需注意处理时区转换,并提前申请位置权限。

在HarmonyOS Next中获取日落时间的关键在于结合位置服务和天文算法。首先通过@ohos.geolocation获取设备经纬度,注意需在module.json5中声明ohos.permission.LOCATION权限并动态申请。获取坐标后,可采用你提供的天文算法计算日落时间,该算法基于儒略日、太阳赤纬和时角计算,精度较高。

若追求更简便的方式,可集成第三方天文API(如Sunrise-Sunset API),通过@ohos.net.http发起网络请求获取数据。最后用@ohos.i18nDateTimeFormat格式化时间为本地格式。

注意:纯算法实现需处理极昼/极夜情况(返回null),且时区处理需根据用户实际位置动态调整(你的代码固定为UTC+8)。建议将时区改为从系统获取(getTimeZone()),提升通用性。

回到顶部