1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-04 12:52:28 +08:00

feat: add AddDaySafe, AddMonthSafe, AddYearSafe

This commit is contained in:
dudaodong
2025-02-18 15:37:56 +08:00
parent a09f5623d6
commit 4181c42805
5 changed files with 293 additions and 61 deletions

View File

@@ -100,6 +100,61 @@ func AddYear(t time.Time, year int64) time.Time {
return t.AddDate(int(year), 0, 0)
}
// AddDaySafe add or sub days to the time and ensure that the returned date does not exceed the valid date of the target year and month.
// Play: todo
func AddDaySafe(t time.Time, days int) time.Time {
t = t.AddDate(0, 0, days)
year, month, day := t.Date()
lastDayOfMonth := time.Date(year, month+1, 0, 0, 0, 0, 0, t.Location()).Day()
if day > lastDayOfMonth {
t = time.Date(year, month, lastDayOfMonth, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location())
}
return t
}
// AddMonthSafe add or sub months to the time and ensure that the returned date does not exceed the valid date of the target year and month.
// Play: todo
func AddMonthSafe(t time.Time, months int) time.Time {
year := t.Year()
month := int(t.Month()) + months
for month > 12 {
month -= 12
year++
}
for month < 1 {
month += 12
year--
}
daysInMonth := time.Date(year, time.Month(month+1), 0, 0, 0, 0, 0, time.UTC).Day()
day := t.Day()
if day > daysInMonth {
day = daysInMonth
}
return time.Date(year, time.Month(month), day, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location())
}
// AddYearSafe add or sub years to the time and ensure that the returned date does not exceed the valid date of the target year and month.
// Play: todo
func AddYearSafe(t time.Time, years int) time.Time {
year, month, day := t.Date()
year += years
if month == time.February && day == 29 {
if !IsLeapYear(year) {
day = 28
}
}
return time.Date(year, month, day, t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location())
}
// GetNowDate return format yyyy-mm-dd of current date.
// Play: https://go.dev/play/p/PvfkPpcpBBf
func GetNowDate() string {

View File

@@ -90,6 +90,60 @@ func ExampleAddYear() {
// 2019-01-01
}
func ExampleAddDaySafe() {
leapYearDate1, _ := time.Parse("2006-01-02", "2024-02-29")
result1 := AddDaySafe(leapYearDate1, 1)
leapYearDate2, _ := time.Parse("2006-01-02", "2024-03-01")
result2 := AddDaySafe(leapYearDate2, -1)
nonLeapYearDate1, _ := time.Parse("2006-01-02", "2025-02-28")
result3 := AddDaySafe(nonLeapYearDate1, 1)
nonLeaYearDate2, _ := time.Parse("2006-01-02", "2025-03-01")
result4 := AddDaySafe(nonLeaYearDate2, -1)
fmt.Println(result1.Format("2006-01-02"))
fmt.Println(result2.Format("2006-01-02"))
fmt.Println(result3.Format("2006-01-02"))
fmt.Println(result4.Format("2006-01-02"))
// Output:
// 2024-03-01
// 2024-02-29
// 2025-03-01
// 2025-02-28
}
func ExampleAddMonthSafe() {
date1, _ := time.Parse("2006-01-02", "2025-01-31")
result1 := AddMonthSafe(date1, 1)
date2, _ := time.Parse("2006-01-02", "2024-02-29")
result2 := AddMonthSafe(date2, -1)
fmt.Println(result1.Format("2006-01-02"))
fmt.Println(result2.Format("2006-01-02"))
// Output:
// 2025-02-28
// 2024-01-29
}
func ExampleAddYearSafe() {
date, _ := time.Parse("2006-01-02", "2020-02-29")
result1 := AddYearSafe(date, 1)
result2 := AddYearSafe(date, -1)
fmt.Println(result1.Format("2006-01-02"))
fmt.Println(result2.Format("2006-01-02"))
// Output:
// 2021-02-28
// 2019-02-28
}
func ExampleGetNowDate() {
result := GetNowDate()

View File

@@ -309,6 +309,129 @@ func TestAddMonth(t *testing.T) {
}
func TestAddDaySafe(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddDaySafe")
tests := []struct {
inputDate string
days int
expected string
}{
{"2025-01-31", 10, "2025-02-10"},
{"2025-01-01", 30, "2025-01-31"},
{"2025-01-31", 1, "2025-02-01"},
{"2025-02-28", 1, "2025-03-01"},
{"2024-02-29", 1, "2024-03-01"},
{"2024-02-29", 365, "2025-02-28"},
{"2025-01-31", -10, "2025-01-21"},
{"2025-01-01", -30, "2024-12-02"},
{"2025-02-01", -1, "2025-01-31"},
{"2025-03-01", -1, "2025-02-28"},
{"2024-03-01", -1, "2024-02-29"},
{"2025-01-31", -31, "2024-12-31"},
{"2025-12-31", 1, "2026-01-01"},
}
for _, tt := range tests {
date, _ := time.Parse("2006-01-02", tt.inputDate)
result := AddDaySafe(date, tt.days)
assert.Equal(tt.expected, result.Format("2006-01-02"))
}
}
func TestAddMonthSafe(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddMonthSafe")
tests := []struct {
inputDate string
months int
expected string
}{
{
inputDate: "2025-01-31",
months: 1,
expected: "2025-02-28",
},
{
inputDate: "2025-01-31",
months: -1,
expected: "2024-12-31",
},
{
inputDate: "2025-12-31",
months: 1,
expected: "2026-01-31",
},
{
inputDate: "2025-01-31",
months: -1,
expected: "2024-12-31",
},
{
inputDate: "2024-02-29",
months: 1,
expected: "2024-03-29",
},
{
inputDate: "2024-02-29",
months: -1,
expected: "2024-01-29",
},
}
for _, tt := range tests {
date, _ := time.Parse("2006-01-02", tt.inputDate)
result := AddMonthSafe(date, tt.months)
assert.Equal(tt.expected, result.Format("2006-01-02"))
}
}
func TestAddYearSafe(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestAddYearSafe")
tests := []struct {
inputDate string
years int
expected string
}{
{
inputDate: "2020-02-29",
years: 1,
expected: "2021-02-28",
},
{
inputDate: "2020-02-29",
years: 2,
expected: "2022-02-28",
},
{
inputDate: "2020-02-29",
years: -1,
expected: "2019-02-28",
},
{
inputDate: "2020-02-29",
years: -2,
expected: "2018-02-28",
},
}
for _, tt := range tests {
date, _ := time.Parse("2006-01-02", tt.inputDate)
result := AddYearSafe(date, tt.years)
assert.Equal(tt.expected, result.Format("2006-01-02"))
}
}
func TestGetNowDate(t *testing.T) {
t.Parallel()