astro/sundial/sundial.go
starainrt c8dd777a7b
docs: 统一公开 API 的中英双语注释
- 补齐公开接口说明段的英文描述,保持签名注释和详细说明均为中英双语结构
- 规范农历、坐标、公式、轨道、日晷、太阳、恒星及行星事件等 API 的注释口径
2026-05-27 16:08:11 +08:00

124 lines
5.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package sundial
import (
"math"
"time"
"b612.me/astro/sun"
)
// TrueSolarTime 真太阳时 / apparent solar time.
//
// 返回 date 在经度 lon 处对应的真太阳时,口径沿用 `sun.ApparentSolarTime`。
// Returns the apparent solar time for date at longitude lon.
func TrueSolarTime(date time.Time, lon float64) time.Time {
return sun.ApparentSolarTime(date, lon)
}
// MeanSolarTime 地方平太阳时 / local mean solar time.
//
// 返回 date 在经度 lon 处对应的地方平太阳时,结果时区为按经度换算的地方平太阳时区。
// 该实现直接按“真太阳时 - 均时差”构造,以与本仓库的真太阳时和均时差口径保持一致。
// Returns the local mean solar time for date at longitude lon. The result uses
// a synthetic local-mean-solar time zone derived from longitude and is built as
// apparent solar time minus equation of time to keep the package's conventions aligned.
func MeanSolarTime(date time.Time, lon float64) time.Time {
return TrueSolarTime(date, lon).Add(time.Duration(-sun.EquationTime(date) * float64(time.Hour)))
}
// HourAngle 太阳时角 / solar hour angle.
//
// 返回经度 lon 处的有符号太阳时角,单位度。上午为负,下午为正,中午为 0°。
// Returns the signed apparent-solar hour angle at longitude lon, in degrees.
func HourAngle(date time.Time, lon float64) float64 {
return normalizeSigned180(sun.HourAngle(date, lon, 0))
}
// MeanSolarHourAngle 平太阳时对应的太阳时角 / hour angle for local mean solar time.
//
// date 负责提供地方平太阳时日期与时区,原有钟面时间会被 meanSolarHours 替换;
// meanSolarHours 为地方平太阳时钟面读数,单位小时,例如 9.5 表示地方平太阳时 09:30。
// 返回对应的视太阳时角,单位度,上午为负,下午为正。
// date provides the local mean-solar date and timezone, while its clock fields are replaced by meanSolarHours.
// meanSolarHours is the local mean-solar clock reading in hours, for example 9.5 for 09:30.
// Returns the corresponding apparent-solar hour angle in degrees, negative in the morning and positive in the afternoon.
func MeanSolarHourAngle(date time.Time, meanSolarHours float64) float64 {
if !isFinite(meanSolarHours) {
return math.NaN()
}
sampleTime := dateWithClockHours(date, meanSolarHours)
return normalizeSigned180(HourAngle(sampleTime, longitudeFromTimeZone(sampleTime)))
}
// ZoneTimeHourAngle 区时对应的太阳时角 / hour angle for zone time.
//
// zoneTimeHours 为 date 所在时区下的钟面读数单位小时lon 为当地经度,东正西负。
// 返回该区时在给定经度上对应的视太阳时角,单位度,上午为负,下午为正。
// date 提供民用日期和时区;其原有钟面时间会被 zoneTimeHours 替换。
// zoneTimeHours is the civil clock reading in the timezone carried by date, in hours; lon is east-positive longitude.
// Returns the apparent-solar hour angle for that civil time and longitude, in degrees, negative in the morning and positive in the afternoon.
// date provides the civil date and timezone, and its original clock fields are replaced by zoneTimeHours.
func ZoneTimeHourAngle(date time.Time, lon, zoneTimeHours float64) float64 {
if !isFinite(zoneTimeHours) || !isFinite(lon) {
return math.NaN()
}
return normalizeSigned180(HourAngle(dateWithClockHours(date, zoneTimeHours), lon))
}
// HorizontalHourLineAngle 水平日晷时线角 / horizontal sundial hour-line angle.
//
// lat 为纬度北正南负hourAngle 为有符号太阳时角,单位度。返回值是相对午线的时线角,
// 上午在东侧为负,下午在西侧为正。
// lat is the observer latitude in degrees and hourAngle is the signed solar
// hour angle in degrees. The result is the hour-line angle from the noon line:
// east/morning is negative and west/afternoon is positive.
func HorizontalHourLineAngle(lat, hourAngle float64) float64 {
if !isFinite(hourAngle) || !isFinite(lat) {
return math.NaN()
}
hourAngle = normalizeSigned180(hourAngle)
latRad := lat * math.Pi / 180
hourAngleRad := hourAngle * math.Pi / 180
return math.Atan2(math.Sin(latRad)*math.Sin(hourAngleRad), math.Cos(hourAngleRad)) * 180 / math.Pi
}
// HorizontalHourLineAngleAt 水平日晷时线角 / horizontal sundial hour-line angle.
//
// 先按给定时刻和经度求瞬时视太阳时角,再结合纬度返回水平日晷的时线角。
// First derives the apparent-solar hour angle for the supplied instant and longitude, then returns the horizontal-dial hour-line angle for the given latitude.
func HorizontalHourLineAngleAt(date time.Time, lon, lat float64) float64 {
return HorizontalHourLineAngle(lat, HourAngle(date, lon))
}
func dateWithClockHours(date time.Time, hours float64) time.Time {
startOfDay := time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location())
return startOfDay.Add(time.Duration(hours * float64(time.Hour)))
}
func longitudeFromTimeZone(date time.Time) float64 {
_, offsetSeconds := date.Zone()
return float64(offsetSeconds) / 240.0
}
func clockHours(date time.Time) float64 {
return float64(date.Hour()) +
float64(date.Minute())/60 +
float64(date.Second())/3600 +
float64(date.Nanosecond())/3.6e12
}
func normalizeSigned180(value float64) float64 {
value = math.Mod(value, 360)
if value < -180 {
value += 360
}
if value >= 180 {
value -= 360
}
return value
}
func isFinite(value float64) bool {
return !math.IsNaN(value) && !math.IsInf(value, 0)
}