-
Notifications
You must be signed in to change notification settings - Fork 82
/
solar.go
192 lines (164 loc) · 4.23 KB
/
solar.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package calendar
import (
"fmt"
"time"
)
//Solar structure
type Solar struct {
time.Time
}
// NewSolarNow creates current solar time.
func NewSolarNow() *Solar {
return &Solar{time.Now().In(CST)}
}
// NewSolarTime creates a solar time from time.Time.
func NewSolarTime(t time.Time) *Solar {
return &Solar{t.In(CST)}
}
// NewSolar creates a solar time.
func NewSolar(year, month, day, hour, min, sec int, nsec int, loc *time.Location) *Solar {
if !isYearValid(year) {
return nil
}
t := time.Date(year, time.Month(month), day, hour, min, sec, nsec, loc)
return &Solar{t.In(CST)}
}
// DiffWithYMD returns the number of days past the current time.
func (s *Solar) DiffWithYMD(year, month, day int) int {
return int((time.Date(year, time.Month(month), day, 0, 0, 0, 0, CST).Unix() - s.Time.Unix()) / 86400)
}
// DiffYMD returns the number of days that the target time exceeds the specified time.
func DiffYMD(year, month, day, targetYear, targetMonth, targetDay int) int {
return int((time.Date(targetYear, time.Month(targetMonth), targetDay, 0, 0, 0, 0, CST).Unix() - time.Date(year, time.Month(month), day, 0, 0, 0, 0, CST).Unix()) / 86400)
}
// GetTime returns the time.Time
func (s *Solar) GetTime() time.Time {
return s.Time
}
// String formats time.
func (s *Solar) String() string {
return fmt.Sprintf("%d年%02d月%02d日 %2d时%2d分%2d秒",
s.Year(), s.Month(), s.Day(), s.Hour(), s.Minute(), s.Second())
}
// Equal returns whether it is equal to the solar time.
func (s *Solar) Equal(solar *Solar) bool {
return s.Time.Equal(solar.Time)
}
// Festival returns festival.
func (s *Solar) Festival(fm FestivalMap) (string, error) {
m := fmt.Sprintf("%2d", int(s.Month()))
d := fmt.Sprintf("%2d", s.Day())
return fm.Get(m + d)
}
// GanzhiYMD returns the year, month and day of "天干地支".
func (s *Solar) GanzhiYMD() (year, month, day string) {
year, month, day = GanZhiYMD(s.Year(), int(s.Month()), s.Day())
return
}
// Convert converts to a lunar calendar time.
func (s *Solar) Convert() *Lunar {
var i int
var leap int
var isLeap bool
var temp int
var day int
var month int
var year int
//offset days
offset := int(s.Sub(base).Seconds() / 86400)
for i = MinYear; i < MaxYear && offset > 0; i++ {
temp = LunarYearDays(i)
offset -= temp
}
if offset < 0 {
offset += temp
i--
}
year = i
leap = LeapMonth(i)
isLeap = false
for i = 1; i < 13 && offset > 0; i++ {
//leap month
if leap > 0 && i == (leap+1) && isLeap == false {
i--
isLeap = true
temp = LeapDays(year)
} else {
temp = LunarMonthDays(year, i)
}
//reset leap month
if isLeap == true && i == (leap+1) {
isLeap = false
}
offset -= temp
}
if offset == 0 && leap > 0 && i == (leap+1) {
if isLeap {
isLeap = false
} else {
isLeap = true
i--
}
}
if offset < 0 {
offset += temp
i--
}
month = i
day = offset + 1
return &Lunar{year, month, day, s.Hour(), s.Minute(), s.Second(), s.Nanosecond(), LeapMonth(year), isLeap}
}
// Truncate returns the result of rounding t down to a multiple of d (since the zero time).
// If d <= 0, Truncate returns t unchanged.
//
// Truncate operates on the time as an absolute duration since the
// zero time; it does not operate on the presentation form of the
// time. Thus, Truncate(Hour) may return a time with a non-zero
// minute, depending on the time's Location.
func (s Solar) Truncate(d time.Duration) *Solar {
return &Solar{s.Time.Truncate(d)}
}
// AddMonth add months
func (s Solar) AddMonth(months int) *Solar {
if months == 0 {
return &s
}
y, m, d := s.Date()
m = m + time.Month(months)
y += int(m) / 12
if m < 0 {
y -= 1
}
if m > 12 {
m = m % 12
} else if m < 1 {
m = 12 + m%12
}
n := SolarMonthDays(y, int(m))
if d > n {
d = n
}
return &Solar{time.Date(y, m, d, s.Hour(), s.Minute(), s.Second(), s.Nanosecond(), s.Location())}
}
// IsLeapYear determines whether it is a leap year.
func IsLeapYear(year int) bool {
if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
return true
}
return false
}
// SolarMonthDays the days of the m-th month of this year.
func SolarMonthDays(year int, month int) int {
switch month {
case 1, 3, 5, 7, 8, 10, 12:
return 31
case 2:
if IsLeapYear(year) {
return 29
}
return 28
case 4, 6, 9, 11:
return 30
}
return 0
}