115 lines
3.1 KiB
Go
115 lines
3.1 KiB
Go
|
|
package internal
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"errors"
|
|||
|
|
"math"
|
|||
|
|
"time"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// ErrInvalidCivilDate 日期非法 / invalid civil date.
|
|||
|
|
var ErrInvalidCivilDate = errors.New("invalid civil date")
|
|||
|
|
|
|||
|
|
// Date2JD 日期转儒略日 / Julian day from a civil time.
|
|||
|
|
func Date2JD(date time.Time) float64 {
|
|||
|
|
day := float64(date.Day()) + float64(date.Hour())/24.0 + float64(date.Minute())/1440.0 + float64(date.Second())/86400.0 + float64(date.Nanosecond())/86400000000000.0
|
|||
|
|
return JDCalc(date.Year(), int(date.Month()), day)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// JDCalc 由公历年月日计算儒略日 / Julian day from a civil date.
|
|||
|
|
func JDCalc(year, month int, day float64) float64 {
|
|||
|
|
if !validCivilDate(year, month, day) {
|
|||
|
|
return math.NaN()
|
|||
|
|
}
|
|||
|
|
effectiveYear, effectiveMonth, effectiveDay := year, month, int(math.Floor(day))
|
|||
|
|
if month == 1 || month == 2 {
|
|||
|
|
year--
|
|||
|
|
month += 12
|
|||
|
|
}
|
|||
|
|
correction := 0
|
|||
|
|
if effectiveYear > 1582 || (effectiveYear == 1582 && (effectiveMonth > 10 || (effectiveMonth == 10 && effectiveDay >= 15))) {
|
|||
|
|
century := int(year / 100)
|
|||
|
|
correction = 2 - century + int(century/4)
|
|||
|
|
}
|
|||
|
|
return math.Floor(365.25*(float64(year)+4716.0)) + math.Floor(30.6001*float64(month+1)) + day + float64(correction) - 1524.5
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func validCivilDate(year, month int, day float64) bool {
|
|||
|
|
if math.IsNaN(day) || math.IsInf(day, 0) || month < 1 || month > 12 || day < 1 {
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
dayInt := int(math.Floor(day))
|
|||
|
|
if dayInt > daysInCivilMonth(year, month) {
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
return !(year == 1582 && month == 10 && day >= 5 && day < 15)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func daysInCivilMonth(year, month int) int {
|
|||
|
|
switch month {
|
|||
|
|
case 1, 3, 5, 7, 8, 10, 12:
|
|||
|
|
return 31
|
|||
|
|
case 4, 6, 9, 11:
|
|||
|
|
return 30
|
|||
|
|
case 2:
|
|||
|
|
if isCivilLeapYear(year, month, 1) {
|
|||
|
|
return 29
|
|||
|
|
}
|
|||
|
|
return 28
|
|||
|
|
default:
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func isCivilLeapYear(year, month int, day float64) bool {
|
|||
|
|
if year < 1582 || (year == 1582 && (month < 10 || (month == 10 && day <= 4))) {
|
|||
|
|
return year%4 == 0
|
|||
|
|
}
|
|||
|
|
if year%400 == 0 {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
if year%100 == 0 {
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
return year%4 == 0
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// JD2DateByZone 儒略日转目标时区日期 / convert a Julian day to a target timezone.
|
|||
|
|
func JD2DateByZone(jd float64, tz *time.Location, byZone bool) time.Time {
|
|||
|
|
jd += 0.5
|
|||
|
|
z := float64(int(jd))
|
|||
|
|
fraction := jd - z
|
|||
|
|
a := z
|
|||
|
|
if z >= 2299161.0 {
|
|||
|
|
alpha := math.Floor((z - 1867216.25) / 36524.25)
|
|||
|
|
a = z + 1 + alpha - math.Floor(alpha/4)
|
|||
|
|
}
|
|||
|
|
b := a + 1524
|
|||
|
|
c := math.Floor((b - 122.1) / 365.25)
|
|||
|
|
d := math.Floor(365.25 * c)
|
|||
|
|
e := math.Floor((b - d) / 30.6001)
|
|||
|
|
days := b - d - math.Floor(30.6001*e) + fraction
|
|||
|
|
month := e - 1
|
|||
|
|
if e >= 14 {
|
|||
|
|
month = e - 13
|
|||
|
|
}
|
|||
|
|
year := c - 4716
|
|||
|
|
if month <= 2 {
|
|||
|
|
year = c - 4715
|
|||
|
|
}
|
|||
|
|
seconds := (days - math.Floor(days)) * 86400
|
|||
|
|
day := math.Floor(days)
|
|||
|
|
date := time.Date(int(year), time.Month(int(month)), int(day), 0, 0, 0, 0, time.UTC).
|
|||
|
|
Add(time.Duration(int64(1000000000 * seconds)))
|
|||
|
|
if !byZone {
|
|||
|
|
return date.In(tz)
|
|||
|
|
}
|
|||
|
|
y, m, dayInt := date.Date()
|
|||
|
|
h, minute, second := date.Clock()
|
|||
|
|
return time.Date(y, m, dayInt, h, minute, second, date.Nanosecond(), tz)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UTC2UT1 轻量民用时转世界时,忽略 DUT1(|UT1−UTC| < 0.9 s) / lightweight UTC to UT1, DUT1 ignored.
|
|||
|
|
func UTC2UT1(jd float64) float64 {
|
|||
|
|
return jd
|
|||
|
|
}
|