因为有个业务需要算周别,且是按照周天到周六的算法,和常见的周一到周天,有些区别,所以ISOWeek函数就不好使了,找了下发现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
func weekStartEnd(year, week int) (time.Time, time.Time, error) {
if week < 1 {
return time.Time{}, time.Time{}, fmt.Errorf("week number must be greater than 0")
}

// 计算年份的1月1日
firstDayOfYear := time.Date(year, time.January, 1, 0, 0, 0, 0, time.UTC)

// 计算1月1日是周几 (0: 周日, 1: 周一, ..., 6: 周六)
dayOfWeek := int(firstDayOfYear.Weekday())

// 计算第一周的起始日期
var daysToFirstWeek int
if dayOfWeek == 0 {
daysToFirstWeek = 1
} else {
daysToFirstWeek = 8 - dayOfWeek
}
firstWeekStart := firstDayOfYear.AddDate(0, 0, daysToFirstWeek-1)

// 计算指定周的起始和结束日期
weekStart := firstWeekStart.AddDate(0, 0, 7*(week-1))
weekEnd := weekStart.AddDate(0, 0, 6)

return weekStart, weekEnd, nil
}

func TestTime(t *testing.T) {
year := 2022
week := 2

start, end, err := weekStartEnd(year, week)
if err != nil {
fmt.Println("Error:", err)
return
}

fmt.Printf("Year %d, week %d starts on %s and ends on %s\n", year, week, start.Format("2006-01-02"), end.Format("2006-01-02"))
}

以前的实现,直接上代码吧:

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
type timex struct {
time.Time
}

func newDate(year int, month time.Month, day int, hour int, min int, sec int, nsec int, loc *time.Location) timex {
return timex{time.Date(year, month, day, hour, min, sec, nsec, loc)}
}

// ISO Week 周一到周天
func (tx timex) whichWeek() int {
//tx := time.Now()

// https://weeknumber.com/?q=02%2F01%2F2022

// Thursday in current week decides the year.
tm1 := time.Date(tx.Year(), tx.Month(), tx.Day()+3-(int(tx.Weekday())+6)%7, 0, 0, 0, 0, time.UTC)
// January 4 is always in week 1.
week1 := time.Date(tm1.Year(), 1, 4, 0, 0, 0, 0, time.UTC)
// Adjust to Thursday in week 1 and count number of weeks from date to week1.
abs := 1 + math.Round((float64((tm1.Unix()-week1.Unix())/86400)-float64(3)+float64((int(week1.Weekday())+6)%7))/7)
return int(abs)
}

// 周天到周六
func (tx timex) whichWeek2() int {

tm1 := time.Date(tx.Year(), tx.Month(), tx.Day()+4-int(tx.Weekday()), 0, 0, 0, 0, time.UTC)
yearStart := time.Date(tm1.Year(), 1, 1, 0, 0, 0, 0, time.UTC)
sd := math.Ceil((float64((tm1.Unix()-yearStart.Unix())/86400) + 1) / 7)

return int(sd)
}

// 计算周开始的起始时间
func (tx timex) WeekStart(year, week int) time.Time {
if year == 0 || week == 0 {
year = tx.Year()
week = int(tx.Weekday())
}

// Start from the middle of the year:
t2 := newDate(year, 7, 1, 0, 0, 0, 0, time.UTC)

// Roll back to Monday:
if wd := t2.Weekday(); wd != time.Sunday {
t2.Time = t2.AddDate(0, 0, -int(wd))
}

// Difference in weeks:
w := t2.whichWeek2()
t2.Time = t2.AddDate(0, 0, (week-w)*7)

if wd := t2.Weekday(); wd != time.Sunday {
t2.Time = t2.AddDate(0, 0, -6)
}

return t2.Time
}

// 计算ISO周别的起始时间
func WeekStart(year, week int) time.Time {
// Start from the middle of the year:
t := time.Date(year, 7, 1, 0, 0, 0, 0, time.UTC)

// Roll back to Monday:
if wd := t.Weekday(); wd == time.Sunday {
t = t.AddDate(0, 0, -6)
} else {
t = t.AddDate(0, 0, -int(wd)+1)
}

// Difference in weeks:
_, w := t.ISOWeek()
t = t.AddDate(0, 0, (week-w)*7)

if wd := t.Weekday(); wd != time.Sunday {
t = t.AddDate(0, 0, -6)
} else {
t = t.AddDate(0, 0, -int(wd)+1)
}

return t
}

参考链接:

https://stackoverflow.com/questions/52300644/date-range-by-week-number-golang

https://stackoverflow.com/questions/45910292/get-week-number-with-week-starting-from-sunday