All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m33s
**变更说明**: - 删除所有 *_test.go 文件(单元测试、集成测试、验收测试、流程测试) - 删除整个 tests/ 目录 - 更新 CLAUDE.md:用"测试禁令"章节替换所有测试要求 - 删除测试生成 Skill (openspec-generate-acceptance-tests) - 删除测试生成命令 (opsx:gen-tests) - 更新 tasks.md:删除所有测试相关任务 **新规范**: - ❌ 禁止编写任何形式的自动化测试 - ❌ 禁止创建 *_test.go 文件 - ❌ 禁止在任务中包含测试相关工作 - ✅ 仅当用户明确要求时才编写测试 **原因**: 业务系统的正确性通过人工验证和生产环境监控保证,测试代码维护成本高于价值。 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
113 lines
3.5 KiB
Go
113 lines
3.5 KiB
Go
package packagepkg
|
||
|
||
import (
|
||
"time"
|
||
|
||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||
)
|
||
|
||
// CalculateExpiryTime 计算套餐过期时间
|
||
// calendarType: 套餐周期类型(natural_month=自然月,by_day=按天)
|
||
// activatedAt: 激活时间
|
||
// durationMonths: 套餐时长(月数,calendar_type=natural_month 时使用)
|
||
// durationDays: 套餐天数(calendar_type=by_day 时使用)
|
||
// 返回:过期时间(当天 23:59:59)
|
||
func CalculateExpiryTime(calendarType string, activatedAt time.Time, durationMonths, durationDays int) time.Time {
|
||
var expiryDate time.Time
|
||
|
||
if calendarType == constants.PackageCalendarTypeNaturalMonth {
|
||
// 自然月套餐:activated_at 月份 + N 个月,月末 23:59:59
|
||
// 计算目标年月
|
||
targetYear := activatedAt.Year()
|
||
targetMonth := activatedAt.Month() + time.Month(durationMonths)
|
||
|
||
// 处理月份溢出
|
||
for targetMonth > 12 {
|
||
targetMonth -= 12
|
||
targetYear++
|
||
}
|
||
|
||
// 获取目标月份的最后一天(下个月的第0天就是本月最后一天)
|
||
expiryDate = time.Date(targetYear, targetMonth+1, 0, 23, 59, 59, 0, activatedAt.Location())
|
||
} else {
|
||
// 按天套餐:activated_at + N 天,23:59:59
|
||
expiryDate = activatedAt.AddDate(0, 0, durationDays)
|
||
expiryDate = time.Date(expiryDate.Year(), expiryDate.Month(), expiryDate.Day(), 23, 59, 59, 0, expiryDate.Location())
|
||
}
|
||
|
||
return expiryDate
|
||
}
|
||
|
||
// CalculateNextResetTime 计算下次流量重置时间
|
||
// dataResetCycle: 流量重置周期(daily/monthly/yearly/none)
|
||
// currentTime: 当前时间
|
||
// billingDay: 计费日(月重置时使用,联通=27,其他=1)
|
||
// 返回:下次重置时间(00:00:00)
|
||
func CalculateNextResetTime(dataResetCycle string, currentTime time.Time, billingDay int) *time.Time {
|
||
if dataResetCycle == constants.PackageDataResetNone {
|
||
// 不重置
|
||
return nil
|
||
}
|
||
|
||
var nextResetTime time.Time
|
||
|
||
switch dataResetCycle {
|
||
case constants.PackageDataResetDaily:
|
||
// 日重置:明天 00:00:00
|
||
nextResetTime = time.Date(
|
||
currentTime.Year(),
|
||
currentTime.Month(),
|
||
currentTime.Day()+1,
|
||
0, 0, 0, 0,
|
||
currentTime.Location(),
|
||
)
|
||
|
||
case constants.PackageDataResetMonthly:
|
||
// 月重置:下月 billingDay 号 00:00:00
|
||
year := currentTime.Year()
|
||
month := currentTime.Month()
|
||
|
||
// 检查 billingDay 是否为当前月的最后一天(月末计费的特殊情况)
|
||
currentMonthLastDay := time.Date(year, month+1, 0, 0, 0, 0, 0, currentTime.Location()).Day()
|
||
isBillingDayMonthEnd := billingDay >= currentMonthLastDay
|
||
|
||
// 如果当前日期 >= billingDay,则重置时间为下个月的 billingDay
|
||
// 否则,重置时间为本月的 billingDay
|
||
// 特殊情况:如果 billingDay 是月末,并且当前日期已接近月末,则跳到下个月
|
||
shouldUseNextMonth := currentTime.Day() >= billingDay || (isBillingDayMonthEnd && currentTime.Day() >= currentMonthLastDay-1)
|
||
|
||
if shouldUseNextMonth {
|
||
// 下个月
|
||
month++
|
||
if month > 12 {
|
||
month = 1
|
||
year++
|
||
}
|
||
}
|
||
|
||
// 计算目标月份的最后一天(处理月末情况)
|
||
lastDayOfMonth := time.Date(year, month+1, 0, 0, 0, 0, 0, currentTime.Location()).Day()
|
||
resetDay := billingDay
|
||
if billingDay > lastDayOfMonth {
|
||
// 如果 billingDay 超过该月天数,使用月末
|
||
resetDay = lastDayOfMonth
|
||
}
|
||
|
||
nextResetTime = time.Date(year, month, resetDay, 0, 0, 0, 0, currentTime.Location())
|
||
|
||
case constants.PackageDataResetYearly:
|
||
// 年重置:明年 1 月 1 日 00:00:00
|
||
nextResetTime = time.Date(
|
||
currentTime.Year()+1,
|
||
1, 1,
|
||
0, 0, 0, 0,
|
||
currentTime.Location(),
|
||
)
|
||
|
||
default:
|
||
return nil
|
||
}
|
||
|
||
return &nextResetTime
|
||
}
|