util.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. package util
  2. import (
  3. "fmt"
  4. "math"
  5. "math/rand"
  6. "time"
  7. "gitee.com/xuyiping_admin/pkg/xerr"
  8. )
  9. const (
  10. LayoutTime = "2006-01-02 15:04:05"
  11. Layout = "2006-01-02"
  12. LayoutMonth = "2006-01"
  13. )
  14. // GenerateRandomNumberString 生成指定长度的数字串
  15. func GenerateRandomNumberString(length int) string {
  16. const charset = "0123456789"
  17. seededRand := rand.New(rand.NewSource(time.Now().UnixNano()))
  18. result := make([]byte, length)
  19. for i := range result {
  20. result[i] = charset[seededRand.Intn(len(charset))]
  21. }
  22. return string(result)
  23. }
  24. // TimeParseLocalUnix 获取当天零点的时间戳
  25. // eg 2023-02-22 => 1676995200
  26. func TimeParseLocalUnix(DayTime string) int64 {
  27. value := DayTime
  28. if len(DayTime) <= 11 {
  29. value = fmt.Sprintf("%s 00:00:00", DayTime)
  30. }
  31. loc, _ := time.LoadLocation("Local")
  32. theTime, _ := time.ParseInLocation(LayoutTime, value, loc)
  33. return theTime.Unix()
  34. }
  35. // TimeParseLocalEndUnix 获取当天24点的时间戳
  36. // eg 2023-02-22 => 1676995200
  37. func TimeParseLocalEndUnix(DayTime string) int64 {
  38. value := DayTime
  39. if len(DayTime) <= 11 {
  40. value = fmt.Sprintf("%s 23:59:59", DayTime)
  41. }
  42. loc, _ := time.LoadLocation("Local")
  43. theTime, _ := time.ParseInLocation(LayoutTime, value, loc)
  44. return theTime.Unix()
  45. }
  46. // ConvertParseLocalUnix 字符串转换当天时间戳
  47. // eg 15:04:05 => 1676998245
  48. func ConvertParseLocalUnix(timeParse string) (int64, error) {
  49. loc, err := time.LoadLocation("Local")
  50. if err != nil {
  51. return 0, err
  52. }
  53. value := fmt.Sprintf("%s %s", time.Now().Format(Layout), timeParse)
  54. theTime, err := time.ParseInLocation(LayoutTime, value, loc)
  55. if err != nil {
  56. return 0, err
  57. }
  58. return theTime.Unix(), nil
  59. }
  60. // GetMonthRemainDay 获取当前月还剩几天
  61. func GetMonthRemainDay() int {
  62. now := time.Now()
  63. lastDayOfMonth := time.Date(now.Year(), now.Month()+1, 0, 23, 59, 59, 999999999, now.Location())
  64. return int(lastDayOfMonth.Sub(now).Hours()/24) + 1
  65. }
  66. // Ceil 向上取整函数
  67. func Ceil(x float64) float64 {
  68. // 使用 math.Floor 计算小于或等于 x 的最大整数
  69. // 然后检查 x 是否为整数,如果不是,则结果加 1
  70. // 注意:math.Floor 返回的是 float64 类型,所以我们需要进行比较
  71. // 来确定是否需要加 1
  72. intPart := math.Floor(x)
  73. if x-intPart > 0 {
  74. return intPart + 1
  75. }
  76. return intPart
  77. }
  78. // GetLastDayOfMonth
  79. // 接受一个字符串形式的月份(如 "2024-12"),
  80. // 并返回该月份的最后一天的日期(2024-12-31)
  81. func GetLastDayOfMonth(month string) (string, error) {
  82. t, err := time.Parse(LayoutMonth, month)
  83. if err != nil {
  84. return "", err // 如果解析失败,返回错误
  85. }
  86. // 获取下个月的第一天
  87. nextMonth := t.AddDate(0, 1, 0)
  88. // 返回上个月的最后一天
  89. lastDay := nextMonth.AddDate(0, 0, -1)
  90. return lastDay.Format(Layout), nil
  91. }
  92. // GetMonthsInRange
  93. // 接受两个字符串形式的月份(如 "2024-01" 到 "2024-12"),
  94. // 并返回一个包含这两个月份之间所有月份的字符串切片。
  95. func GetMonthsInRange(startMonth, endMonth string) ([]string, error) {
  96. // 解析起始月份
  97. startTime, err := time.Parse(LayoutMonth, startMonth)
  98. if err != nil {
  99. return nil, err
  100. }
  101. // 解析结束月份
  102. endTime, err := time.Parse(LayoutMonth, endMonth)
  103. if err != nil {
  104. return nil, err
  105. }
  106. // 初始化结果切片
  107. var months []string
  108. // 循环添加每个月份直到达到或超过结束月份
  109. for curr := startTime; curr.Before(endTime) || curr.Equal(endTime); curr = curr.AddDate(0, 1, 0) {
  110. months = append(months, curr.Format(LayoutMonth))
  111. }
  112. return months, nil
  113. }
  114. // RoundToTwoDecimals 四舍五入并保留两位小数
  115. func RoundToTwoDecimals(num float64) float64 {
  116. // 使用 math.Round 函数进行四舍五入
  117. // 先乘以 100,然后四舍五入,最后除以 100
  118. return math.Round(num*100) / 100
  119. }
  120. // Get21DayPeriods 获取范围时间内21天周期的切片
  121. // 从结束时间开始往前推算,超过开始时间,继续向前推算,直至凑整21天
  122. func Get21DayPeriods(startDay, endDay string) ([][]string, error) {
  123. startDate, err := time.Parse(Layout, startDay)
  124. if err != nil {
  125. return nil, err
  126. }
  127. endDate, err := time.Parse(Layout, endDay)
  128. if err != nil {
  129. return nil, err
  130. }
  131. if startDate.After(endDate) {
  132. return nil, xerr.Custom("start date is after end date")
  133. }
  134. var periods [][]string
  135. for date := endDate; date.After(startDate); {
  136. // Calculate the end of the current period
  137. periodEnd := date.AddDate(0, 0, -20)
  138. // Append the current period to the result slice
  139. periods = append(periods, []string{periodEnd.Format(Layout), date.Format(Layout)})
  140. // Move on to the next day
  141. date = periodEnd.AddDate(0, 0, -1)
  142. }
  143. reverseRows(periods)
  144. return periods, nil
  145. }
  146. func reverseRows(matrix [][]string) {
  147. // 获取矩阵的行数
  148. rows := len(matrix)
  149. if rows == 0 {
  150. return // 如果矩阵为空,则直接返回
  151. }
  152. // 初始化两个指针,一个指向开始,一个指向末尾
  153. for i, j := 0, rows-1; i < j; i, j = i+1, j-1 {
  154. // 交换当前行和对应行
  155. matrix[i], matrix[j] = matrix[j], matrix[i]
  156. }
  157. }
  158. // GetRangeDayMiddleDay 获取指定日期范围中间的某一天
  159. func GetRangeDayMiddleDay(dateRange []string, middleDay int32) (string, error) {
  160. if len(dateRange) < 2 {
  161. return "", xerr.Custom("date range is not enough")
  162. }
  163. if middleDay < 0 {
  164. return "", xerr.Custom("middle day is not enough")
  165. }
  166. startDate, _ := time.Parse(Layout, dateRange[0])
  167. return startDate.AddDate(0, 0, int(middleDay)-1).Format(Layout), nil
  168. }
  169. // GetRangeDayByDays 获取指定范围日期内按照指定天数来切割
  170. // (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]]
  171. func GetRangeDayByDays(startDay, endDay string, days int32) ([][]string, error) {
  172. var res [][]string
  173. if days <= 0 {
  174. return res, nil
  175. }
  176. startDate, err := time.Parse(Layout, startDay)
  177. if err != nil {
  178. return nil, err
  179. }
  180. endDate, err := time.Parse(Layout, endDay)
  181. if err != nil {
  182. return nil, err
  183. }
  184. if startDate.After(endDate) {
  185. return nil, xerr.Custom("start date is after end date")
  186. }
  187. if startDate == endDate {
  188. return [][]string{{startDay, endDay}}, nil
  189. }
  190. for date := startDate; date.Before(endDate) || date.Equal(endDate); date = date.AddDate(0, 0, int(days)) {
  191. if date.AddDate(0, 0, int(days)-1).After(endDate) {
  192. res = append(res, []string{date.Format(Layout), endDate.Format(Layout)})
  193. break
  194. }
  195. res = append(res, []string{date.Format(Layout), date.AddDate(0, 0, int(days)-1).Format(Layout)})
  196. }
  197. return res, nil
  198. }
  199. // 计算样本均值
  200. func mean(data []float64) float64 {
  201. sum := 0.0
  202. for _, v := range data {
  203. sum += v
  204. }
  205. return sum / float64(len(data))
  206. }
  207. // 计算样本标准差
  208. func stddev(data []float64, mean float64) float64 {
  209. sum := 0.0
  210. for _, v := range data {
  211. sum += (v - mean) * (v - mean)
  212. }
  213. variance := sum / float64(len(data)-1)
  214. return math.Sqrt(variance)
  215. }
  216. // ConfidenceInterval 计算95%置信区间
  217. func ConfidenceInterval(data []float64) (float64, float64) {
  218. n := float64(len(data))
  219. meanVal := mean(data)
  220. stdDev := stddev(data, meanVal)
  221. z := 1.96 // 95%置信水平对应的Z值
  222. marginOfError := z * (stdDev / math.Sqrt(n))
  223. lowerBound := meanVal - marginOfError
  224. upperBound := meanVal + marginOfError
  225. return lowerBound, upperBound
  226. }
  227. // ConfidenceInterval2 计算95%置信区间
  228. func ConfidenceInterval2(p float64, total float64) (min, max float64) {
  229. if p <= 0 || total <= 0 {
  230. return 0, 0
  231. }
  232. z := 1.96 // 95%置信水平对应的Z值
  233. marginOf := z * math.Sqrt(p*(1-p)/total) * 100
  234. return math.Max(0, p*100-math.Ceil(marginOf)), math.Max(1, p*100+math.Ceil(marginOf))
  235. }
  236. // RemoveDuplicates 去除切片中的重复元素
  237. func RemoveDuplicates(slice []string) []string {
  238. if len(slice) <= 0 {
  239. return slice
  240. }
  241. // 创建一个map来跟踪已经遇到的元素
  242. seen := make(map[string]struct{})
  243. // 创建一个新的切片来存储不重复的元素
  244. var result []string
  245. // 遍历原始切片
  246. for _, v := range slice {
  247. // 如果元素尚未在map中,则将其添加到结果切片和map中
  248. if _, exists := seen[v]; !exists {
  249. seen[v] = struct{}{}
  250. result = append(result, v)
  251. }
  252. }
  253. // 返回不重复的切片
  254. return result
  255. }