123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- package util
- import (
- "fmt"
- "math"
- "time"
- "gitee.com/xuyiping_admin/pkg/xerr"
- )
- const (
- LayoutTime = "2006-01-02 15:04:05"
- Layout = "2006-01-02"
- LayoutMonth = "2006-01"
- )
- // TimeParseLocalUnix 获取当天零点的时间戳
- // eg 2023-02-22 => 1676995200
- func TimeParseLocalUnix(DayTime string) int64 {
- value := DayTime
- if len(DayTime) <= 11 {
- value = fmt.Sprintf("%s 00:00:00", DayTime)
- }
- loc, _ := time.LoadLocation("Local")
- theTime, _ := time.ParseInLocation(LayoutTime, value, loc)
- return theTime.Unix()
- }
- // TimeParseLocalEndUnix 获取当天24点的时间戳
- // eg 2023-02-22 => 1676995200
- func TimeParseLocalEndUnix(DayTime string) int64 {
- value := DayTime
- if len(DayTime) <= 11 {
- value = fmt.Sprintf("%s 23:59:59", DayTime)
- }
- loc, _ := time.LoadLocation("Local")
- theTime, _ := time.ParseInLocation(LayoutTime, value, loc)
- return theTime.Unix()
- }
- // ConvertParseLocalUnix 字符串转换当天时间戳
- // eg 15:04:05 => 1676998245
- func ConvertParseLocalUnix(timeParse string) (int64, error) {
- loc, err := time.LoadLocation("Local")
- if err != nil {
- return 0, err
- }
- value := fmt.Sprintf("%s %s", time.Now().Format(Layout), timeParse)
- theTime, err := time.ParseInLocation(LayoutTime, value, loc)
- if err != nil {
- return 0, err
- }
- return theTime.Unix(), nil
- }
- // GetMonthRemainDay 获取当前月还剩几天
- func GetMonthRemainDay() int {
- now := time.Now()
- lastDayOfMonth := time.Date(now.Year(), now.Month()+1, 0, 23, 59, 59, 999999999, now.Location())
- return int(lastDayOfMonth.Sub(now).Hours()/24) + 1
- }
- // Ceil 向上取整函数
- func Ceil(x float64) float64 {
- // 使用 math.Floor 计算小于或等于 x 的最大整数
- // 然后检查 x 是否为整数,如果不是,则结果加 1
- // 注意:math.Floor 返回的是 float64 类型,所以我们需要进行比较
- // 来确定是否需要加 1
- intPart := math.Floor(x)
- if x-intPart > 0 {
- return intPart + 1
- }
- return intPart
- }
- // GetLastDayOfMonth
- // 接受一个字符串形式的月份(如 "2024-12"),
- // 并返回该月份的最后一天的日期(2024-12-31)
- func GetLastDayOfMonth(month string) (string, error) {
- t, err := time.Parse(LayoutMonth, month)
- if err != nil {
- return "", err // 如果解析失败,返回错误
- }
- // 获取下个月的第一天
- nextMonth := t.AddDate(0, 1, 0)
- // 返回上个月的最后一天
- lastDay := nextMonth.AddDate(0, 0, -1)
- return lastDay.Format(Layout), nil
- }
- // GetMonthsInRange
- // 接受两个字符串形式的月份(如 "2024-01" 到 "2024-12"),
- // 并返回一个包含这两个月份之间所有月份的字符串切片。
- func GetMonthsInRange(startMonth, endMonth string) ([]string, error) {
- // 解析起始月份
- startTime, err := time.Parse(LayoutMonth, startMonth)
- if err != nil {
- return nil, err
- }
- // 解析结束月份
- endTime, err := time.Parse(LayoutMonth, endMonth)
- if err != nil {
- return nil, err
- }
- // 初始化结果切片
- var months []string
- // 循环添加每个月份直到达到或超过结束月份
- for curr := startTime; curr.Before(endTime) || curr.Equal(endTime); curr = curr.AddDate(0, 1, 0) {
- months = append(months, curr.Format(LayoutMonth))
- }
- return months, nil
- }
- // RoundToTwoDecimals 四舍五入并保留两位小数
- func RoundToTwoDecimals(num float64) float64 {
- // 使用 math.Round 函数进行四舍五入
- // 先乘以 100,然后四舍五入,最后除以 100
- return math.Round(num*100) / 100
- }
- // Get21DayPeriods 获取范围时间内21天周期的切片
- // 从结束时间开始往前推算,超过开始时间,继续向前推算,直至凑整21天
- func Get21DayPeriods(startDay, endDay string) ([][]string, error) {
- startDate, err := time.Parse(Layout, startDay)
- if err != nil {
- return nil, err
- }
- endDate, err := time.Parse(Layout, endDay)
- if err != nil {
- return nil, err
- }
- if startDate.After(endDate) {
- return nil, xerr.Custom("start date is after end date")
- }
- var periods [][]string
- for date := endDate; date.After(startDate); {
- // Calculate the end of the current period
- periodEnd := date.AddDate(0, 0, -20)
- // Append the current period to the result slice
- periods = append(periods, []string{periodEnd.Format(Layout), date.Format(Layout)})
- // Move on to the next day
- date = periodEnd.AddDate(0, 0, -1)
- }
- reverseRows(periods)
- return periods, nil
- }
- func reverseRows(matrix [][]string) {
- // 获取矩阵的行数
- rows := len(matrix)
- if rows == 0 {
- return // 如果矩阵为空,则直接返回
- }
- // 初始化两个指针,一个指向开始,一个指向末尾
- for i, j := 0, rows-1; i < j; i, j = i+1, j-1 {
- // 交换当前行和对应行
- matrix[i], matrix[j] = matrix[j], matrix[i]
- }
- }
- // GetRangeDayMiddleDay 获取指定日期范围中间的某一天
- func GetRangeDayMiddleDay(dateRange []string, middleDay int32) (string, error) {
- if len(dateRange) < 2 {
- return "", xerr.Custom("date range is not enough")
- }
- if middleDay < 0 {
- return "", xerr.Custom("middle day is not enough")
- }
- startDate, _ := time.Parse(Layout, dateRange[0])
- return startDate.AddDate(0, 0, int(middleDay)-1).Format(Layout), nil
- }
- // GetRangeDayByDays 获取指定范围日期内按照指定天数来切割
- // (2024-10-01 ~ 2024-10-31,5)=> [[2024-10-01,2024-10-05], [2024-10-06,2024-10-10], [2024-10-11,2024-10-15], [2024-10-16,2024-10-20], [2024-10-21,2024-10-25], [2024-10-26,2024-10-30],[2024-10-31,2024-10-31]]
- func GetRangeDayByDays(startDay, endDay string, days int32) ([][]string, error) {
- var res [][]string
- if days <= 0 {
- return res, nil
- }
- startDate, err := time.Parse(Layout, startDay)
- if err != nil {
- return nil, err
- }
- endDate, err := time.Parse(Layout, endDay)
- if err != nil {
- return nil, err
- }
- if startDate.After(endDate) {
- return nil, xerr.Custom("start date is after end date")
- }
- if startDate == endDate {
- return [][]string{{startDay, endDay}}, nil
- }
- for date := startDate; date.Before(endDate) || date.Equal(endDate); date = date.AddDate(0, 0, int(days)) {
- if date.AddDate(0, 0, int(days)-1).After(endDate) {
- res = append(res, []string{date.Format(Layout), endDate.Format(Layout)})
- break
- }
- res = append(res, []string{date.Format(Layout), date.AddDate(0, 0, int(days)-1).Format(Layout)})
- }
- return res, nil
- }
- // 计算样本均值
- func mean(data []float64) float64 {
- sum := 0.0
- for _, v := range data {
- sum += v
- }
- return sum / float64(len(data))
- }
- // 计算样本标准差
- func stddev(data []float64, mean float64) float64 {
- sum := 0.0
- for _, v := range data {
- sum += (v - mean) * (v - mean)
- }
- variance := sum / float64(len(data)-1)
- return math.Sqrt(variance)
- }
- // ConfidenceInterval 计算95%置信区间
- func ConfidenceInterval(data []float64) (float64, float64) {
- n := float64(len(data))
- meanVal := mean(data)
- stdDev := stddev(data, meanVal)
- z := 1.96 // 95%置信水平对应的Z值
- marginOfError := z * (stdDev / math.Sqrt(n))
- lowerBound := meanVal - marginOfError
- upperBound := meanVal + marginOfError
- return lowerBound, upperBound
- }
- // ConfidenceInterval2 计算95%置信区间
- func ConfidenceInterval2(p float64, total float64) (min, max float64) {
- z := 1.96 // 95%置信水平对应的Z值
- marginOf := z * math.Sqrt(p*(1-p)/total) * 100
- return math.Max(0, p*100-math.Ceil(marginOf)), math.Max(1, p*100+math.Ceil(marginOf))
- }
|