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

HarmonyOS 鸿蒙Next中如何根据当前位置获取日出时间和日落时间 上一篇帖子只写了获取日落时间,所本次增加日出时间

代码如下

/**
 * 日出日落时间计算工具类(纯算法实现)
 * 需传入已获取的经纬度,无需处理位置权限和获取逻辑
 */
interface BaseParams{
  n: number,
  g: number,
  sunDeclination: number,
  equationOfTime: number
}

export class SunAlgorithm {
  /**
   * 计算日落时间
   * @param latitude 纬度(度)
   * @param longitude 经度(度)
   * @param date 日期(默认当前日期)
   * @returns 日落时间(格式:HH:mm,本地时间,基于东八区)
   */


  static calculateSunset(
    latitude: number,
    longitude: number,
    date: Date = new Date()
  ): string | null {
    try {
      // 1. 准备计算所需参数(不使用解构赋值,兼容ArkTS)
      const baseParams = SunAlgorithm.calculateBaseParameters(date);
      const n = baseParams.n;
      const g = baseParams.g;
      const sunDeclination = baseParams.sunDeclination;
      const equationOfTime = baseParams.equationOfTime;

      // 2. 计算日落时角(度)- 正值
      const hourAngle = SunAlgorithm.calculateHourAngle(latitude, sunDeclination);
      if (hourAngle === null) {
        return "极昼/极夜区域";
      }

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

      // 4. 转换为东八区时间并格式化
      return SunAlgorithm.convertAndFormatTime(utcHours);
    } catch (error) {
      console.error("日落时间计算失败:", error);
      return null;
    }
  }

  /**
   * 计算日出时间
   * @param latitude 纬度(度)
   * @param longitude 经度(度)
   * @param date 日期(默认当前日期)
   * @returns 日出时间(格式:HH:mm,本地时间,基于东八区)
   */
  static calculateSunrise(
    latitude: number,
    longitude: number,
    date: Date = new Date()
  ): string | null {
    try {
      // 1. 准备计算所需参数(不使用解构赋值,兼容ArkTS)
      const baseParams = SunAlgorithm.calculateBaseParameters(date);
      const n = baseParams.n;
      const g = baseParams.g;
      const sunDeclination = baseParams.sunDeclination;
      const equationOfTime = baseParams.equationOfTime;

      // 2. 计算日出时角(度)- 负值
      const hourAngle = SunAlgorithm.calculateHourAngle(latitude, sunDeclination);
      if (hourAngle === null) {
        return "极昼/极夜区域";
      }

      // 3. 计算当地日出时间(UTC小时)- 使用负时角
      let utcHours = 12 - (hourAngle / 15) - (longitude / 15) - (equationOfTime / 60);

      // 4. 转换为东八区时间并格式化
      return SunAlgorithm.convertAndFormatTime(utcHours);
    } catch (error) {
      console.error("日出时间计算失败:", error);
      return null;
    }
  }

  /**
   * 计算日出日落共需的基础参数
   */
  private static calculateBaseParameters(date: Date): BaseParams {
    // 1. 将日期转换为儒略日
    let julianDay = SunAlgorithm.dateToJulianDay(date);

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

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

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

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

    // 极夜区域返回null
    if (sunDeclination === null) {
      return null;
    }

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

    return { n, g, sunDeclination, equationOfTime };
  }

  // 其余方法保持不变...
  /**
   * 日期转换为儒略日
   */
  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(SunAlgorithm.degToRad(anomaly)) +
      0.019994643 * Math.sin(SunAlgorithm.degToRad(2 * anomaly));

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

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

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

    // 日出日落时太阳中心低于地平线0.833度(考虑大气折射)
    let h0 = SunAlgorithm.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 SunAlgorithm.radToDeg(Math.acos(cosH));
  }

  /**
   * 计算时差(分钟)
   */
  private static calculateEquationOfTime(anomaly: number): number {
    let gRad = SunAlgorithm.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)
    );
  }

  /**
   * 转换UTC时间到东八区并格式化
   */
  private static convertAndFormatTime(utcHours: number): string {
    // 转换为东八区时间(UTC+8)
    let localHours = utcHours + 8;

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

    // 格式化输出
    return SunAlgorithm.formatTime(localHours);
  }

  /**
   * 规范化角度到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 getSunriseTime(latLng: LatLng) {
  let sunrise = SunAlgorithm.calculateSunrise(latLng.latitude, latLng.longitude);
  return sunrise;
}

// 获取日落时间
export function getSunsetTime(latLng: LatLng) {
  // 贵阳的经纬度示例值
  let sunset = SunAlgorithm.calculateSunset(latLng.latitude, latLng.longitude);
  return sunset;
}

export interface LatLng {
  latitude: number
  longitude: number
}

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

4 回复

学到了

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


在HarmonyOS Next中,可通过@ohos.geoLocationManager获取设备位置坐标,再使用@ohos.sunDate计算日出日落时间。调用getSunTime方法,传入经纬度及日期参数,返回结果为时间戳,需转换为本地时间格式。注意申请位置权限并处理异步回调。

代码实现完整,通过SunAlgorithm类封装了日出日落时间的计算逻辑。计算基于天文算法,包括儒略日转换、太阳赤纬、时角等关键参数。需要注意:

  1. 时角计算中区分日出(负值)和日落(正值)
  2. 包含极昼/极夜区域判断(返回"极昼/极夜区域")
  3. 结果已转换为东八区时间(UTC+8)
  4. 大气折射修正(-0.833度)和时差计算提高了精度

使用时只需传入经纬度坐标即可获取对应时间的日出日落时间,格式为HH:mm。代码兼容ArkTS,可直接在HarmonyOS Next项目中使用。

回到顶部