package utils import ( "bufio" "bytes" "crypto/hmac" "crypto/md5" "crypto/sha1" "crypto/sha256" "encoding/base64" "encoding/hex" "encoding/json" "errors" "fmt" "html" "image" "image/png" "io" "math" "math/rand" "net" "net/http" "net/url" "os" "os/exec" "path" "reflect" "regexp" "sort" "strconv" "strings" "time" "unicode" "gorm.io/gorm" "github.com/PuerkitoBio/goquery" "github.com/microcosm-cc/bluemonday" "github.com/shopspring/decimal" xhtml "golang.org/x/net/html" ) func GetRandString(size int) string { allLetterDigit := []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "!", "@", "#", "$", "%", "^", "&", "*"} randomSb := "" digitSize := len(allLetterDigit) // 随机数种子 rnd := rand.New(rand.NewSource(time.Now().UnixNano())) for i := 0; i < size; i++ { randomSb += allLetterDigit[rnd.Intn(digitSize)] } return randomSb } func GetRandStringNoSpecialChar(size int) string { allLetterDigit := []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"} randomSb := "" digitSize := len(allLetterDigit) // 随机数种子 rnd := rand.New(rand.NewSource(time.Now().UnixNano())) for i := 0; i < size; i++ { randomSb += allLetterDigit[rnd.Intn(digitSize)] } return randomSb } func StringsToJSON(str string) string { rs := []rune(str) jsons := "" for _, r := range rs { rint := int(r) if rint < 128 { jsons += string(r) } else { jsons += "\\u" + strconv.FormatInt(int64(rint), 16) // json } } return jsons } // 序列化 func ToString(v interface{}) string { data, _ := json.Marshal(v) return string(data) } // md5加密 func MD5(data string) string { m := md5.Sum([]byte(data)) return hex.EncodeToString(m[:]) } // HmacMd5 HmacMd5加密 func HmacMd5(key, data string) string { h := hmac.New(md5.New, []byte(key)) h.Write([]byte(data)) return hex.EncodeToString(h.Sum([]byte(""))) } // 获取数字随机字符 func GetRandDigit(n int) string { // 随机数种子 rnd := rand.New(rand.NewSource(time.Now().UnixNano())) return fmt.Sprintf("%0"+strconv.Itoa(n)+"d", rnd.Intn(int(math.Pow10(n)))) } // 获取随机数 func GetRandNumber(n int) int { // 随机数种子 rnd := rand.New(rand.NewSource(time.Now().UnixNano())) return rnd.Intn(n) } func GetRandInt(min, max int) int { if min >= max || min == 0 || max == 0 { return max } return rand.Intn(max-min) + min } func GetToday(format string) string { today := time.Now().Format(format) return today } // 获取今天剩余秒数 func GetTodayLastSecond() time.Duration { today := GetToday(FormatDate) + " 23:59:59" end, _ := time.ParseInLocation(FormatDateTime, today, time.Local) return time.Duration(end.Unix()-time.Now().Local().Unix()) * time.Second } // 处理出生日期函数 func GetBrithDate(idcard string) string { l := len(idcard) var s string if l == 15 { s = "19" + idcard[6:8] + "-" + idcard[8:10] + "-" + idcard[10:12] return s } if l == 18 { s = idcard[6:10] + "-" + idcard[10:12] + "-" + idcard[12:14] return s } return GetToday(FormatDate) } // 处理性别 func WhichSexByIdcard(idcard string) string { var sexs = [2]string{"女", "男"} length := len(idcard) if length == 18 { sex, _ := strconv.Atoi(string(idcard[16])) return sexs[sex%2] } else if length == 15 { sex, _ := strconv.Atoi(string(idcard[14])) return sexs[sex%2] } return "男" } // SubFloatToString 截取小数点后几位 func SubFloatToString(f float64, m int) string { n := strconv.FormatFloat(f, 'f', -1, 64) if n == "" { return "" } if m >= len(n) { return n } newn := strings.Split(n, ".") if m == 0 { return newn[0] } if len(newn) < 2 || m >= len(newn[1]) { return n } return newn[0] + "." + newn[1][:m] } // 截取小数点后几位 func SubFloatToFloat(f float64, m int) float64 { newn := SubFloatToString(f, m) newf, _ := strconv.ParseFloat(newn, 64) return newf } // 截取小数点后几位 func SubFloatToFloatStr(f float64, m int) string { newn := SubFloatToString(f, m) return newn } // 获取相差时间-年 func GetYearDiffer(start_time, end_time string) int { t1, _ := time.ParseInLocation("2006-01-02", start_time, time.Local) t2, _ := time.ParseInLocation("2006-01-02", end_time, time.Local) age := t2.Year() - t1.Year() if t2.Month() < t1.Month() || (t2.Month() == t1.Month() && t2.Day() < t1.Day()) { age-- } return age } // 获取相差时间-秒 func GetSecondDifferByTime(start_time, end_time time.Time) int64 { diff := end_time.Unix() - start_time.Unix() return diff } func FixFloat(f float64, m int) float64 { newn := SubFloatToString(f+0.00000001, m) newf, _ := strconv.ParseFloat(newn, 64) return newf } // 将字符串数组转化为逗号分割的字符串形式 ["str1","str2","str3"] >>> "str1,str2,str3" func StrListToString(strList []string) (str string) { if len(strList) > 0 { for k, v := range strList { if k == 0 { str = v } else { str = str + "," + v } } return } return "" } // 数据没有记录 func ErrNoRow() string { return " no row found" } // IsErrNoRow // @Description: 判断是否是gorm的查询不到数据的报错 // @param err // @return bool func IsErrNoRow(err error) bool { if err == nil { return false } return errors.Is(err, gorm.ErrRecordNotFound) } // 校验邮箱格式 func ValidateEmailFormatat(email string) bool { reg := regexp.MustCompile(RegularEmail) return reg.MatchString(email) } // 验证是否是手机号 func ValidateMobileFormatat(mobileNum string) bool { reg := regexp.MustCompile(RegularMobile) return reg.MatchString(mobileNum) } // 判断文件是否存在 func FileIsExist(filePath string) bool { _, err := os.Stat(filePath) return err == nil || os.IsExist(err) } // 获取图片扩展名 func GetImgExt(file string) (ext string, err error) { var headerByte []byte headerByte = make([]byte, 8) fd, err := os.Open(file) if err != nil { return "", err } defer fd.Close() _, err = fd.Read(headerByte) if err != nil { return "", err } xStr := fmt.Sprintf("%x", headerByte) switch { case xStr == "89504e470d0a1a0a": ext = ".png" case xStr == "0000010001002020": ext = ".ico" case xStr == "0000020001002020": ext = ".cur" case xStr[:12] == "474946383961" || xStr[:12] == "474946383761": ext = ".gif" case xStr[:10] == "0000020000" || xStr[:10] == "0000100000": ext = ".tga" case xStr[:8] == "464f524d": ext = ".iff" case xStr[:8] == "52494646": ext = ".ani" case xStr[:4] == "4d4d" || xStr[:4] == "4949": ext = ".tiff" case xStr[:4] == "424d": ext = ".bmp" case xStr[:4] == "ffd8": ext = ".jpg" case xStr[:2] == "0a": ext = ".pcx" default: ext = "" } return ext, nil } // 保存图片 func SaveImage(path string, img image.Image) (err error) { //需要保持的文件 imgfile, err := os.Create(path) defer imgfile.Close() // 以PNG格式保存文件 err = png.Encode(imgfile, img) return err } // 下载图片 func DownloadImage(imgUrl string) (filePath string, err error) { imgPath := "./static/imgs/" fileName := path.Base(imgUrl) res, err := http.Get(imgUrl) if err != nil { fmt.Println("A error occurred!") return } defer res.Body.Close() // 获得get请求响应的reader对象 reader := bufio.NewReaderSize(res.Body, 32*1024) filePath = imgPath + fileName file, err := os.Create(filePath) if err != nil { return } defer func() { file.Close() }() // 获得文件的writer对象 writer := bufio.NewWriter(file) written, _ := io.Copy(writer, reader) fmt.Printf("Total length: %d \n", written) return } // DownloadFile 下载文件 func DownloadFile(fileUrl, fileDir string) (filePath string, err error) { filePathDir := "./static/imgs/" if fileDir != `` { err = os.MkdirAll(fileDir, DIR_MOD) if err != nil { return } filePathDir = fileDir } fileName := path.Base(fileUrl) res, err := http.Get(fileUrl) if err != nil { fmt.Println("A error occurred!") return } defer res.Body.Close() // 获得get请求响应的reader对象 reader := bufio.NewReaderSize(res.Body, 32*1024) filePath = filePathDir + GetRandString(4) + fileName file, err := os.Create(filePath) if err != nil { return } defer func() { file.Close() }() // 获得文件的writer对象 writer := bufio.NewWriter(file) _, _ = io.Copy(writer, reader) //fmt.Printf("Total length: %d \n", written) return } // 保存base64数据为文件 func SaveBase64ToFile(content, path string) error { data, err := base64.StdEncoding.DecodeString(content) if err != nil { return err } f, err := os.Create(path) defer f.Close() if err != nil { return err } f.Write(data) return nil } func SaveBase64ToFileBySeek(content, path string) (err error) { data, err := base64.StdEncoding.DecodeString(content) exist, err := PathExists(path) if err != nil { return } if !exist { f, err := os.Create(path) if err != nil { return err } n, _ := f.Seek(0, 2) // 从末尾的偏移量开始写入内容 _, err = f.WriteAt([]byte(data), n) defer f.Close() } else { f, err := os.OpenFile(path, os.O_WRONLY, 0644) if err != nil { return err } n, _ := f.Seek(0, 2) // 从末尾的偏移量开始写入内容 _, err = f.WriteAt([]byte(data), n) defer f.Close() } return nil } func PathExists(path string) (bool, error) { _, err := os.Stat(path) if err == nil { return true, nil } if os.IsNotExist(err) { return false, nil } return false, err } func StartIndex(page, pagesize int) int { if page > 1 { return (page - 1) * pagesize } return 0 } func PageCount(count, pagesize int) int { if count%pagesize > 0 { return count/pagesize + 1 } else { return count / pagesize } } func TrimHtml(src string) string { //将HTML标签全转换成小写 re, _ := regexp.Compile("\\<[\\S\\s]+?\\>") src = re.ReplaceAllStringFunc(src, strings.ToLower) re, _ = regexp.Compile("\\") src = re.ReplaceAllString(src, "") re, _ = regexp.Compile("class[\\S\\s]+?>") src = re.ReplaceAllString(src, "") re, _ = regexp.Compile("\\<[\\S\\s]+?\\>") src = re.ReplaceAllString(src, "") src = strings.ReplaceAll(src, " ", " ") return strings.TrimSpace(src) } //1556164246 -> 2019-04-25 03:50:46 +0000 //timestamp func TimeToTimestamp() { fmt.Println(time.Unix(1556164246, 0).Format("2006-01-02 15:04:05")) } func ToUnicode(text string) string { textQuoted := strconv.QuoteToASCII(text) textUnquoted := textQuoted[1 : len(textQuoted)-1] return textUnquoted } func VersionToInt(version string) int { version = strings.Replace(version, ".", "", -1) n, _ := strconv.Atoi(version) return n } func IsCheckInList(list []int, s int) bool { for _, v := range list { if v == s { return true } } return false } func round(num float64) int { return int(num + math.Copysign(0.5, num)) } func toFixed(num float64, precision int) float64 { output := math.Pow(10, float64(precision)) return float64(round(num*output)) / output } // GetWilsonScore returns Wilson Score func GetWilsonScore(p, n float64) float64 { if p == 0 && n == 0 { return 0 } return toFixed(((p+1.9208)/(p+n)-1.96*math.Sqrt(p*n/(p+n)+0.9604)/(p+n))/(1+3.8416/(p+n)), 2) } // 将中文数字转化成数字,比如 第三百四十五章,返回第345章 不支持一亿及以上 func ChangeWordsToNum(str string) (numStr string) { words := ([]rune)(str) num := 0 n := 0 for i := 0; i < len(words); i++ { word := string(words[i : i+1]) switch word { case "万": if n == 0 { n = 1 } n = n * 10000 num = num*10000 + n n = 0 case "千": if n == 0 { n = 1 } n = n * 1000 num += n n = 0 case "百": if n == 0 { n = 1 } n = n * 100 num += n n = 0 case "十": if n == 0 { n = 1 } n = n * 10 num += n n = 0 case "一": n += 1 case "二": n += 2 case "三": n += 3 case "四": n += 4 case "五": n += 5 case "六": n += 6 case "七": n += 7 case "八": n += 8 case "九": n += 9 case "零": default: if n > 0 { num += n n = 0 } if num == 0 { numStr += word } else { numStr += strconv.Itoa(num) + word num = 0 } } } if n > 0 { num += n n = 0 } if num != 0 { numStr += strconv.Itoa(num) } return } func Sha1(data string) string { sha1 := sha1.New() sha1.Write([]byte(data)) return hex.EncodeToString(sha1.Sum([]byte(""))) } func GetVideoPlaySeconds(videoPath string) (playSeconds float64, err error) { cmd := fmt.Sprintf(`ffmpeg -i %s 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//`, videoPath) out, err := exec.Command("bash", "-c", cmd).Output() if err != nil { return } outTimes := string(out) fmt.Println("outTimes:", outTimes) if outTimes != "" { timeArr := strings.Split(outTimes, ":") h := timeArr[0] m := timeArr[1] s := timeArr[2] hInt, err := strconv.Atoi(h) if err != nil { return playSeconds, err } mInt, err := strconv.Atoi(m) if err != nil { return playSeconds, err } s = strings.Trim(s, " ") s = strings.Trim(s, "\n") sInt, err := strconv.ParseFloat(s, 64) if err != nil { return playSeconds, err } playSeconds = float64(hInt)*3600 + float64(mInt)*60 + float64(sInt) } return } func GetMaxTradeCode(tradeCode string) (maxTradeCode string, err error) { tradeCode = strings.Replace(tradeCode, "W", "", -1) tradeCode = strings.Trim(tradeCode, " ") tradeCodeInt, err := strconv.Atoi(tradeCode) if err != nil { return } tradeCodeInt = tradeCodeInt + 1 maxTradeCode = fmt.Sprintf("W%06d", tradeCodeInt) return } func GetTradeCodeList(tradeCode string, num int) (tradeCodeList []string, err error) { tradeCode = strings.Replace(tradeCode, "W", "", -1) tradeCode = strings.Trim(tradeCode, " ") tradeCodeInt, err := strconv.Atoi(tradeCode) if err != nil { return } for i := 0; i < num; i++ { tradeCodeInt = tradeCodeInt + 1 tradeCodeList = append(tradeCodeList, fmt.Sprintf("W%06d", tradeCodeInt)) } return } // excel日期字段格式化 yyyy-mm-dd func ConvertToFormatDay(excelDaysString string) string { // 2006-01-02 距离 1900-01-01的天数 baseDiffDay := 38719 //在网上工具计算的天数需要加2天,什么原因没弄清楚 curDiffDay := excelDaysString b, _ := strconv.Atoi(curDiffDay) // 获取excel的日期距离2006-01-02的天数 realDiffDay := b - baseDiffDay //fmt.Println("realDiffDay:",realDiffDay) // 距离2006-01-02 秒数 realDiffSecond := realDiffDay * 24 * 3600 //fmt.Println("realDiffSecond:",realDiffSecond) // 2006-01-02 15:04:05距离1970-01-01 08:00:00的秒数 网上工具可查出 baseOriginSecond := 1136185445 resultTime := time.Unix(int64(baseOriginSecond+realDiffSecond), 0).Format("2006-01-02") return resultTime } // GetDaysDiff1900 计算日期距离1900-01-01的天数 func GetDaysDiff1900(date string) int { // 将字符串转换为时间类型 //从1899年12月30日开始是因为Excel的日期计算是基于1900年1月1日的,而1900年并不是闰年,因此Excel日期计算存在一个错误。为了修正这个错误, //我们将时间回溯到1899年12月30日,这样在进行日期计算时可以正确地处理Excel日期。 tStart, err := time.ParseInLocation(FormatDate, "1899-12-30", time.Local) if err != nil { return 0 } tEnd, err := time.ParseInLocation(FormatDate, date, time.Local) if err != nil { return 0 } // 计算两个日期之间的天数差值 duration := tEnd.Sub(tStart).Hours() / 24 days := int(duration) return days } func CheckPwd(pwd string) bool { compile := `([0-9a-z]+){6,12}|(a-z0-9]+){6,12}` reg := regexp.MustCompile(compile) flag := reg.MatchString(pwd) return flag } func GetMonthStartAndEnd(myYear string, myMonth string) (startDate, endDate string) { // 数字月份必须前置补零 if len(myMonth) == 1 { myMonth = "0" + myMonth } yInt, _ := strconv.Atoi(myYear) timeLayout := "2006-01-02 15:04:05" loc, _ := time.LoadLocation("Local") theTime, _ := time.ParseInLocation(timeLayout, myYear+"-"+myMonth+"-01 00:00:00", loc) newMonth := theTime.Month() t1 := time.Date(yInt, newMonth, 1, 0, 0, 0, 0, time.Local).Format("2006-01-02") t2 := time.Date(yInt, newMonth+1, 0, 0, 0, 0, 0, time.Local).Format("2006-01-02") return t1, t2 } // TrimStr 移除字符串中的空格 func TrimStr(str string) (str2 string) { if str == "" { return str } return strings.Replace(str, " ", "", -1) } // TrimLRStr 移除字符串前后的空格 func TrimLRStr(str string) (str2 string) { if str == "" { return str } str2 = strings.TrimLeft(str, " ") str2 = strings.TrimRight(str2, " ") return } // 字符串转换为time func StrTimeToTime(strTime string) time.Time { timeLayout := "2006-01-02 15:04:05" //转化所需模板 loc, _ := time.LoadLocation("Local") //重要:获取时区 resultTime, _ := time.ParseInLocation(timeLayout, strTime, loc) return resultTime } // TimeToStr time.Time 转 字符串 yyyy-MM-dd func TimeToStr(data time.Time, format string) string { return data.Format(format) } // 字符串类型时间转周几 func StrDateTimeToWeek(strTime string) string { var WeekDayMap = map[string]string{ "Monday": "周一", "Tuesday": "周二", "Wednesday": "周三", "Thursday": "周四", "Friday": "周五", "Saturday": "周六", "Sunday": "周日", } var ctime = StrTimeToTime(strTime).Format("2006-01-02") startday, _ := time.Parse("2006-01-02", ctime) staweek_int := startday.Weekday().String() return WeekDayMap[staweek_int] } // EnWeekToCnWeek 英文周几转中文周几 func EnWeekToCnWeek(enWeekStr string) string { var WeekDayMap = map[string]string{ "Monday": "周一", "Tuesday": "周二", "Wednesday": "周三", "Thursday": "周四", "Friday": "周五", "Saturday": "周六", "Sunday": "周日", } cnWeekStr, ok := WeekDayMap[enWeekStr] if !ok { cnWeekStr = `周一` } return cnWeekStr } // 时间格式转年月日字符串 func TimeToStrYmd(time2 time.Time) string { var Ymd string year := time2.Year() month := time2.Format("1") day1 := time.Now().Day() Ymd = strconv.Itoa(year) + "年" + month + "月" + strconv.Itoa(day1) + "日" return Ymd } // 时间格式去掉时分秒 func TimeRemoveHms(strTime string) string { var Ymd string var resultTime = StrTimeToTime(strTime) year := resultTime.Year() month := resultTime.Format("01") day1 := resultTime.Day() if day1 < 10 { Ymd = strconv.Itoa(year) + "." + month + ".0" + strconv.Itoa(day1) } else { Ymd = strconv.Itoa(year) + "." + month + "." + strconv.Itoa(day1) } return Ymd } // 时间格式去掉时分秒 func TimeRemoveHms2(strTime string) string { var Ymd string var resultTime = StrTimeToTime(strTime) year := resultTime.Year() month := resultTime.Format("01") day1 := resultTime.Day() if day1 < 10 { Ymd = strconv.Itoa(year) + "-" + month + "-0" + strconv.Itoa(day1) } else { Ymd = strconv.Itoa(year) + "-" + month + "-" + strconv.Itoa(day1) } return Ymd } // 文章上一次编辑时间 func ArticleLastTime(strTime string) string { var newTime string stamp, _ := time.ParseInLocation("2006-01-02 15:04:05", strTime, time.Local) diffTime := time.Now().Unix() - stamp.Unix() if diffTime <= 60 { newTime = "当前" } else if diffTime < 60*60 { newTime = strconv.FormatInt(diffTime/60, 10) + "分钟前" } else if diffTime < 24*60*60 { newTime = strconv.FormatInt(diffTime/(60*60), 10) + "小时前" } else if diffTime < 30*24*60*60 { newTime = strconv.FormatInt(diffTime/(24*60*60), 10) + "天前" } else if diffTime < 12*30*24*60*60 { newTime = strconv.FormatInt(diffTime/(30*24*60*60), 10) + "月前" } else { newTime = "1年前" } return newTime } // 人民币小写转大写 func ConvertNumToCny(num float64) (str string, err error) { strNum := strconv.FormatFloat(num*100, 'f', 0, 64) sliceUnit := []string{"仟", "佰", "拾", "亿", "仟", "佰", "拾", "万", "仟", "佰", "拾", "元", "角", "分"} // log.Println(sliceUnit[:len(sliceUnit)-2]) s := sliceUnit[len(sliceUnit)-len(strNum):] upperDigitUnit := map[string]string{"0": "零", "1": "壹", "2": "贰", "3": "叁", "4": "肆", "5": "伍", "6": "陆", "7": "柒", "8": "捌", "9": "玖"} for k, v := range strNum[:] { str = str + upperDigitUnit[string(v)] + s[k] } reg, err := regexp.Compile(`零角零分$`) str = reg.ReplaceAllString(str, "整") reg, err = regexp.Compile(`零角`) str = reg.ReplaceAllString(str, "零") reg, err = regexp.Compile(`零分$`) str = reg.ReplaceAllString(str, "整") reg, err = regexp.Compile(`零[仟佰拾]`) str = reg.ReplaceAllString(str, "零") reg, err = regexp.Compile(`零{2,}`) str = reg.ReplaceAllString(str, "零") reg, err = regexp.Compile(`零亿`) str = reg.ReplaceAllString(str, "亿") reg, err = regexp.Compile(`零万`) str = reg.ReplaceAllString(str, "万") reg, err = regexp.Compile(`零*元`) str = reg.ReplaceAllString(str, "元") reg, err = regexp.Compile(`亿零{0, 3}万`) str = reg.ReplaceAllString(str, "^元") reg, err = regexp.Compile(`零元`) str = reg.ReplaceAllString(str, "零") return } // GetNowWeekMonday 获取本周周一的时间 func GetNowWeekMonday() time.Time { offset := int(time.Monday - time.Now().Weekday()) if offset == 1 { //正好是周日,但是按照中国人的理解,周日是一周最后一天,而不是一周开始的第一天 offset = -6 } mondayTime := time.Now().AddDate(0, 0, offset) mondayTime = time.Date(mondayTime.Year(), mondayTime.Month(), mondayTime.Day(), 0, 0, 0, 0, mondayTime.Location()) return mondayTime } // GetNowWeekLastDay 获取本周最后一天的时间 func GetNowWeekLastDay() time.Time { offset := int(time.Monday - time.Now().Weekday()) if offset == 1 { //正好是周日,但是按照中国人的理解,周日是一周最后一天,而不是一周开始的第一天 offset = -6 } firstDayTime := time.Now().AddDate(0, 0, offset) firstDayTime = time.Date(firstDayTime.Year(), firstDayTime.Month(), firstDayTime.Day(), 0, 0, 0, 0, firstDayTime.Location()).AddDate(0, 0, 6) lastDayTime := time.Date(firstDayTime.Year(), firstDayTime.Month(), firstDayTime.Day(), 23, 59, 59, 0, firstDayTime.Location()) return lastDayTime } // GetNowMonthFirstDay 获取本月第一天的时间 func GetNowMonthFirstDay() time.Time { nowMonthFirstDay := time.Date(time.Now().Year(), time.Now().Month(), 1, 0, 0, 0, 0, time.Now().Location()) return nowMonthFirstDay } // GetNowMonthLastDay 获取本月最后一天的时间 func GetNowMonthLastDay() time.Time { nowMonthLastDay := time.Date(time.Now().Year(), time.Now().Month(), 1, 0, 0, 0, 0, time.Now().Location()).AddDate(0, 1, -1) nowMonthLastDay = time.Date(nowMonthLastDay.Year(), nowMonthLastDay.Month(), nowMonthLastDay.Day(), 23, 59, 59, 0, nowMonthLastDay.Location()) return nowMonthLastDay } // GetNowQuarterFirstDay 获取本季度第一天的时间 func GetNowQuarterFirstDay() time.Time { month := int(time.Now().Month()) var nowQuarterFirstDay time.Time if month >= 1 && month <= 3 { //1月1号 nowQuarterFirstDay = time.Date(time.Now().Year(), 1, 1, 0, 0, 0, 0, time.Now().Location()) } else if month >= 4 && month <= 6 { //4月1号 nowQuarterFirstDay = time.Date(time.Now().Year(), 4, 1, 0, 0, 0, 0, time.Now().Location()) } else if month >= 7 && month <= 9 { nowQuarterFirstDay = time.Date(time.Now().Year(), 7, 1, 0, 0, 0, 0, time.Now().Location()) } else { nowQuarterFirstDay = time.Date(time.Now().Year(), 10, 1, 0, 0, 0, 0, time.Now().Location()) } return nowQuarterFirstDay } // GetNowQuarterLastDay 获取本季度最后一天的时间 func GetNowQuarterLastDay() time.Time { month := int(time.Now().Month()) var nowQuarterLastDay time.Time if month >= 1 && month <= 3 { //03-31 23:59:59 nowQuarterLastDay = time.Date(time.Now().Year(), 3, 31, 23, 59, 59, 0, time.Now().Location()) } else if month >= 4 && month <= 6 { //06-30 23:59:59 nowQuarterLastDay = time.Date(time.Now().Year(), 6, 30, 23, 59, 59, 0, time.Now().Location()) } else if month >= 7 && month <= 9 { //09-30 23:59:59 nowQuarterLastDay = time.Date(time.Now().Year(), 9, 30, 23, 59, 59, 0, time.Now().Location()) } else { //12-31 23:59:59 nowQuarterLastDay = time.Date(time.Now().Year(), 12, 31, 23, 59, 59, 0, time.Now().Location()) } return nowQuarterLastDay } // GetNowHalfYearFirstDay 获取当前半年的第一天的时间 func GetNowHalfYearFirstDay() time.Time { month := int(time.Now().Month()) var nowHalfYearLastDay time.Time if month >= 1 && month <= 6 { //03-31 23:59:59 nowHalfYearLastDay = time.Date(time.Now().Year(), 1, 1, 0, 0, 0, 0, time.Now().Location()) } else { //12-31 23:59:59 nowHalfYearLastDay = time.Date(time.Now().Year(), 7, 1, 0, 0, 0, 0, time.Now().Location()) } return nowHalfYearLastDay } // GetNowHalfYearLastDay 获取当前半年的最后一天的时间 func GetNowHalfYearLastDay() time.Time { month := int(time.Now().Month()) var nowHalfYearLastDay time.Time if month >= 1 && month <= 6 { //03-31 23:59:59 nowHalfYearLastDay = time.Date(time.Now().Year(), 6, 30, 23, 59, 59, 0, time.Now().Location()) } else { //12-31 23:59:59 nowHalfYearLastDay = time.Date(time.Now().Year(), 12, 31, 23, 59, 59, 0, time.Now().Location()) } return nowHalfYearLastDay } // GetNowYearFirstDay 获取当前年的最后一天的时间 func GetNowYearFirstDay() time.Time { //12-31 23:59:59 nowYearFirstDay := time.Date(time.Now().Year(), 1, 1, 0, 0, 0, 0, time.Now().Location()) return nowYearFirstDay } // GetNowYearLastDay 获取当前年的最后一天的时间 func GetNowYearLastDay() time.Time { //12-31 23:59:59 nowYearLastDay := time.Date(time.Now().Year(), 12, 31, 23, 59, 59, 0, time.Now().Location()) return nowYearLastDay } // CalculationDate 计算两个日期之间相差n年m月y天 func CalculationDate(startDate, endDate time.Time) (beetweenDay string, err error) { //startDate := time.Date(2021, 3, 28, 0, 0, 0, 0, time.Now().Location()) //endDate := time.Date(2022, 3, 31, 0, 0, 0, 0, time.Now().Location()) numYear := endDate.Year() - startDate.Year() numMonth := int(endDate.Month()) - int(startDate.Month()) numDay := 0 //获取截止月的总天数 endDateDays := getMonthDay(endDate.Year(), int(endDate.Month())) //获取截止月的前一个月 endDatePrevMonthDate := endDate.AddDate(0, -1, 0) //获取截止日期的上一个月的总天数 endDatePrevMonthDays := getMonthDay(endDatePrevMonthDate.Year(), int(endDatePrevMonthDate.Month())) //获取开始日期的的月份总天数 startDateMonthDays := getMonthDay(startDate.Year(), int(startDate.Month())) //判断,截止月是否完全被选中,如果相等,那么代表截止月份全部天数被选择 if endDate.Day() == endDateDays { numDay = startDateMonthDays - startDate.Day() + 1 //如果剩余天数正好与开始日期的天数是一致的,那么月份加1 if numDay == startDateMonthDays { numMonth++ numDay = 0 //超过月份了,那么年份加1 if numMonth == 12 { numYear++ numMonth = 0 } } } else { numDay = endDate.Day() - startDate.Day() + 1 } //天数小于0,那么向月份借一位 if numDay < 0 { //向上一个月借一个月的天数 numDay += endDatePrevMonthDays //总月份减去一个月 numMonth = numMonth - 1 } //月份小于0,那么向年份借一位 if numMonth < 0 { //向上一个年借12个月 numMonth += 12 //总年份减去一年 numYear = numYear - 1 } if numYear < 0 { err = errors.New("日期异常") return } if numYear > 0 { beetweenDay += fmt.Sprint(numYear, "年") } if numMonth > 0 { beetweenDay += fmt.Sprint(numMonth, "个月") } if numDay > 0 { beetweenDay += fmt.Sprint(numDay, "天") } return } // FormatPrice 格式化展示金额数字(财务金额展示,小数点前,每三位用,隔开) 1,234,567,898.55 func FormatPrice(price float64) (str string) { str = decimal.NewFromFloat(price).String() length := len(str) if length < 4 { return str } arr := strings.Split(str, ".") //用小数点符号分割字符串,为数组接收 length1 := len(arr[0]) if length1 < 4 { return str } count := (length1 - 1) / 3 for i := 0; i < count; i++ { arr[0] = arr[0][:length1-(i+1)*3] + "," + arr[0][length1-(i+1)*3:] } return strings.Join(arr, ".") //将一系列字符串连接为一个字符串,之间用sep来分隔。 } // getMonthDay 获取某年某月有多少天 func getMonthDay(year, month int) (days int) { if month != 2 { if month == 4 || month == 6 || month == 9 || month == 11 { days = 30 } else { days = 31 } } else { if ((year%4) == 0 && (year%100) != 0) || (year%400) == 0 { days = 29 } else { days = 28 } } return } func SaveToFile(content, path string) error { f, err := os.Create(path) defer f.Close() if err != nil { return err } f.Write([]byte(content)) return nil } // 用户参会时间转换 func GetAttendanceDetailSeconds(secondNum int) string { var timeStr string if secondNum <= 60 { if secondNum < 10 { timeStr = "0" + strconv.Itoa(secondNum) + "''" } else { timeStr = strconv.Itoa(secondNum) + "''" } } else { var remainderStr string remainderNum := secondNum % 60 minuteNum := secondNum / 60 if remainderNum < 10 { remainderStr = "0" + strconv.Itoa(remainderNum) + "''" } else { remainderStr = strconv.Itoa(remainderNum) + "''" } if minuteNum < 10 { timeStr = "0" + strconv.Itoa(minuteNum) + "'" + remainderStr } else { timeStr = strconv.Itoa(minuteNum) + "'" + remainderStr } } return timeStr } // SubStr 截取字符串(中文) func SubStr(str string, subLen int) string { strRune := []rune(str) bodyRuneLen := len(strRune) if bodyRuneLen > subLen { bodyRuneLen = subLen } str = string(strRune[:bodyRuneLen]) return str } // HideString 给字段加***(从字符串中间替换,少于需要替换的长度,那么就补全*的长度) // src 待*字符串 // hideLen 需要加*的长度 func HideString(src string, hideLen int) string { if src == "" { return src } str := []rune(src) if hideLen == 0 { hideLen = 4 } hideStr := "" for i := 0; i < hideLen; i++ { hideStr += "*" } strLen := len(str) // 字符长度是1 if strLen == 1 { return string(str[:1]) + hideStr } //字符长度大于1,但是小于等于需要隐藏的字符长度,那么就隐藏中间,保留前后各一位字符 if strLen <= hideLen+2 { return string(str[:1]) + hideStr + string(str[strLen-1:]) } subLen := strLen - hideLen //剩余需要展示的字符长度 decimal.NewFromFloat(2) frontLenDecimal := decimal.NewFromInt(int64(subLen)).Div(decimal.NewFromInt(2)) //前面需要展示的字符的长度 frontLen := frontLenDecimal.Floor().IntPart() return string(str[:frontLen]) + hideStr + string(str[frontLen+int64(hideLen):]) } func GetLocalIP() (ip string, err error) { addrs, err := net.InterfaceAddrs() if err != nil { return } for _, addr := range addrs { ipAddr, ok := addr.(*net.IPNet) if !ok { continue } if ipAddr.IP.IsLoopback() { continue } if !ipAddr.IP.IsGlobalUnicast() { continue } return ipAddr.IP.String(), nil } return } // GetNowWeekMonday 获取上一周周一的时间 func GetPreWeekMonday() time.Time { nowMonday := GetNowWeekMonday() return nowMonday.AddDate(0, 0, -7) } // GetNowWeekLastDay 获取上一周最后一天的时间 func GetPreWeekLastDay() time.Time { nowSunday := GetNowWeekLastDay() return nowSunday.AddDate(0, 0, -7) } // GetNextWeekMonday 获取下一周周一的时间 func GetNextWeekMonday() time.Time { nowMonday := GetNowWeekMonday() return nowMonday.AddDate(0, 0, 7) } // GetNextWeekLastDay 获取下一周最后一天的时间 func GetNextWeekLastDay() time.Time { nowSunday := GetNowWeekLastDay() return nowSunday.AddDate(0, 0, 7) } // 处理真实姓名,隐藏中间的部分,如:张*,张*将 func DealRealName(realName string) string { if realName == "" { return "" } names := bytes.Runes([]byte(realName)) fistName := names[0] length := len(names) if length == 2 { return string(fistName) + "*" } else if length > 2 { lastName := names[length-1] return string(fistName) + "*" + string(lastName) } return realName } // Implode php中的implode(用来将int型的切片转为string) func Implode(idIntList []int) (str string) { for _, id := range idIntList { str += fmt.Sprint(id, ",") } str = str[:len(str)-1] return } // InArrayByInt php中的in_array(判断Int类型的切片中是否存在该int值) func InArrayByInt(idIntList []int, searchId int) (has bool) { for _, id := range idIntList { if id == searchId { has = true return } } return } // InArrayByStr php中的in_array(判断String类型的切片中是否存在该string值) func InArrayByStr(idStrList []string, searchId string) (has bool) { for _, id := range idStrList { if id == searchId { has = true return } } return } // Intersection 求两个切片的交集 func Intersection(a []string, b []string) (inter []string) { // interacting on the smallest list first can potentailly be faster...but not by much, worse case is the same low, high := a, b if len(a) > len(b) { low = b high = a } done := false for i, l := range low { for j, h := range high { // get future index values f1 := i + 1 f2 := j + 1 if l == h { inter = append(inter, h) if f1 < len(low) && f2 < len(high) { // if the future values aren't the same then that's the end of the intersection if low[f1] != high[f2] { done = true } } // we don't want to interate on the entire list everytime, so remove the parts we already looped on will make it faster each pass high = high[:j+copy(high[j:], high[j+1:])] break } } // nothing in the future so we are done if done { break } } return } // Minus 获取差集 func Minus(a []string, b []string) []string { //var inter []string inter := make([]string, 0) mp := make(map[string]bool) for _, s := range a { if _, ok := mp[s]; !ok { mp[s] = true } } for _, s := range b { if _, ok := mp[s]; ok { delete(mp, s) } } for key := range mp { inter = append(inter, key) } return inter } // IntArr2joinString []int转字符串 func IntArr2joinString(arr []int, sep string) string { if len(arr) == 0 { return "" } strArr := make([]string, 0) for _, v := range arr { strArr = append(strArr, strconv.Itoa(v)) } return strings.Join(strArr, sep) } // GetOneMonthFirstDay 获取某月的第一天的时间 func GetOneMonthFirstDay(time2 time.Time) time.Time { nowMonthFirstDay := time.Date(time2.Year(), time2.Month(), 1, 0, 0, 0, 0, time.Now().Location()) return nowMonthFirstDay } // GetOneMonthLastDay 获取某月最后一天的时间 func GetOneMonthLastDay(time2 time.Time) time.Time { nowMonthLastDay := time.Date(time2.Year(), time2.Month(), 1, 0, 0, 0, 0, time.Now().Location()).AddDate(0, 1, -1) nowMonthLastDay = time.Date(nowMonthLastDay.Year(), nowMonthLastDay.Month(), nowMonthLastDay.Day(), 23, 59, 59, 0, nowMonthLastDay.Location()) return nowMonthLastDay } func GetReportContentTextSub(content string) (contentSub string, err error) { content = html.UnescapeString(content) doc, err := goquery.NewDocumentFromReader(strings.NewReader(content)) docText := doc.Text() bodyRune := []rune(docText) bodyRuneLen := len(bodyRune) if bodyRuneLen > 200 { bodyRuneLen = 200 } body := string(bodyRune[:bodyRuneLen]) contentSub = body contentSub = strings.Replace(body, "Powered by Froala Editor", "", -1) return } // GetOrmInReplace 获取orm的in查询替换?的方法 func GetOrmInReplace(num int) string { //template := make([]string, num) //for i := 0; i < num; i++ { // template[i] = "?" //} //return strings.Join(template, ",") return "?" } // RevSlice 反转切片 func RevSlice(slice []int) []int { for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 { slice[i], slice[j] = slice[j], slice[i] } return slice } // ReplaceSpaceAndWrap 去除空格跟换行 func ReplaceSpaceAndWrap(str string) string { // 去除空格 str = strings.Replace(str, " ", "", -1) // 去除换行符 str = strings.Replace(str, "\n", "", -1) return str } // JoinStr2IntArr 拼接字符串转[]int func JoinStr2IntArr(str, sep string) (arr []int) { arr = make([]int, 0) if str == "" { return } if sep == "" { sep = "," } strArr := strings.Split(str, sep) if len(strArr) == 0 { return } for i := range strArr { v, e := strconv.Atoi(strArr[i]) // int2str此处过滤掉无效int if e != nil { continue } arr = append(arr, v) } return } // 字符串转换为time类型 func StrDateToDate(strTime string) time.Time { timeLayout := "2006-01-02" //转化所需模板 loc, _ := time.LoadLocation("Local") //重要:获取时区 resultTime, _ := time.ParseInLocation(timeLayout, strTime, loc) return resultTime } // GetTimeSubDay 计算两个时间的自然日期差(后面减去前面) func GetTimeSubDay(t1, t2 time.Time) int { var day int swap := false if t1.Unix() > t2.Unix() { t1, t2 = t2, t1 swap = true } t1_ := t1.Add(time.Duration(t2.Sub(t1).Milliseconds()%86400000) * time.Millisecond) day = int(t2.Sub(t1).Hours() / 24) // 计算在t1+两个时间的余数之后天数是否有变化 if t1_.Day() != t1.Day() { day += 1 } if swap { day = -day } return day } // 去除非中文字符串 func StrFilterNonChinese(src *string) { var hzRegexp = regexp.MustCompile("^[\u4e00-\u9fa5]$") strn := "" for _, c := range *src { if hzRegexp.MatchString(string(c)) { strn += string(c) } } *src = strn } // MinusInt 获取两个[]int差集 func MinusInt(a []int, b []int) []int { var diff []int mpA, mpB := make(map[int]bool), make(map[int]bool) for _, v := range a { mpA[v] = true } for _, v := range b { mpB[v] = true } for _, s := range a { if !mpB[s] { diff = append(diff, s) } } for _, s := range b { if !mpA[s] { diff = append(diff, s) } } return diff } // IntersectInt 获取两个[]int交集 func IntersectInt(nums1 []int, nums2 []int) []int { m := make(map[int]int) var res []int for _, num := range nums1 { m[num]++ } for _, num := range nums2 { if m[num] > 0 { res = append(res, num) m[num]-- } } return res } // MapSorter 对于map 排序 type MapSorter []Item type Item struct { Key int Val float64 } func NewMapSorter(m map[int]float64) MapSorter { ms := make(MapSorter, 0, len(m)) for k, v := range m { ms = append(ms, Item{k, v}) } return ms } func (ms MapSorter) Len() int { return len(ms) } func (ms MapSorter) Less(i, j int) bool { return ms[i].Val > ms[j].Val // 按值排序 //return ms[i].Key < ms[j].Key // 按键排序 } func (ms MapSorter) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] } // FormatFileSize 字节的单位转换 保留两位小数 func FormatFileSize(fileSize int64) (size string) { if fileSize < 1024 { return fmt.Sprintf("%.2fB", float64(fileSize)/float64(1)) } else if fileSize < (1024 * 1024) { return fmt.Sprintf("%.2fKB", float64(fileSize)/float64(1024)) } else if fileSize < (1024 * 1024 * 1024) { return fmt.Sprintf("%.2fMB", float64(fileSize)/float64(1024*1024)) } else if fileSize < (1024 * 1024 * 1024 * 1024) { return fmt.Sprintf("%.2fGB", float64(fileSize)/float64(1024*1024*1024)) } else if fileSize < (1024 * 1024 * 1024 * 1024 * 1024) { return fmt.Sprintf("%.2fTB", float64(fileSize)/float64(1024*1024*1024*1024)) } else { //if fileSize < (1024 * 1024 * 1024 * 1024 * 1024 * 1024) return fmt.Sprintf("%.2fPB", float64(fileSize)/float64(1024*1024*1024*1024*1024)) } } func GetDurationFormatBySecond(sec int) (formatString string) { if sec == 0 { formatString = "0分钟" return } else if sec <= 60 && sec > 0 { formatString = "1分钟" return } duration := time.Duration(int64(sec)) * time.Second h := int(duration.Hours()) m := int(duration.Minutes()) % 60 //s := int(duration.Seconds()) % 60 if h > 0 { formatString = fmt.Sprintf("%d小时", h) } if m > 0 { formatString += fmt.Sprintf("%d分钟", m) } //if s > 0 { // formatString += fmt.Sprintf("%d秒", s) //} return } // GetDaysBetween2Date 计算两个日期之间相差几天 func GetDaysBetween2Date(format, date1Str, date2Str string) (int, error) { // 将字符串转化为Time格式 date1, err := time.ParseInLocation(format, date1Str, time.Local) if err != nil { return 0, err } // 将字符串转化为Time格式 date2, err := time.ParseInLocation(format, date2Str, time.Local) if err != nil { return 0, err } //计算相差天数 return int(date1.Sub(date2).Hours() / 24), nil } // GetFrequencyEn 获取频度的英文版 func GetFrequencyEn(frequency string) (frequencyEn string) { switch frequency { case "日度": frequencyEn = "day" return case "周度": frequencyEn = "week" return case "旬度": frequencyEn = "ten days" return case "月度": frequencyEn = "month" return case "季度": frequencyEn = "quarter" return case "年度": frequencyEn = "year" return } return } // GetLeadUnitEn 获取移动单位的英文版 func GetLeadUnitEn(unit string) (unitEn string) { switch unit { case "天": unitEn = "day" return case "周": unitEn = "week" return case "月": unitEn = "month" return case "季": unitEn = "quarter" return case "年": unitEn = "year" return } return } // GetDateByDateType 通过dateType获取需要的开始/结束日期 // dateType 日期类型:1:00年至今,2:10年至今,3:15年至今,4:年初至今,5:自定义时间,6:起始日期至今 20:最近N年 func GetDateByDateType(dateType int, tmpStartDate, tmpEndDate string) (startDate, endDate string) { startDate = tmpStartDate endDate = tmpEndDate switch dateType { case 1: startDate = "2000-01-01" endDate = "" case 2: startDate = "2010-01-01" endDate = "" case 3: startDate = "2015-01-01" endDate = "" case 4: //startDate = strconv.Itoa(time.Now().Year()) + "-01-01" startDate = "2021-01-01" endDate = "" case 5: //startDate = startDate + "-01" //endDate = endDate + "-01" case 6: //startDate = startDate + "-01" endDate = "" case 7: startDate = "2018-01-01" endDate = "" case 8: startDate = "2019-01-01" endDate = "" case 9: startDate = "2020-01-01" endDate = "" case 11: startDate = "2022-01-01" endDate = "" } // 兼容日期错误 { if strings.Count(startDate, "-") == 1 { startDate = startDate + "-01" } if strings.Count(endDate, "-") == 1 { endDate = endDate + "-01" } } return } func GetDateByDateTypeV2(dateType int, tmpStartDate, tmpEndDate string, startYear, yearMax int) (startDate, endDate string) { startDate = tmpStartDate endDate = tmpEndDate switch dateType { case 1: startDate = "2000-01-01" endDate = "" case 2: startDate = "2010-01-01" endDate = "" case 3: startDate = "2015-01-01" endDate = "" case 4: //startDate = strconv.Itoa(time.Now().Year()) + "-01-01" startDate = "2021-01-01" endDate = "" case 5: //startDate = startDate + "-01" //endDate = endDate + "-01" case 6: //startDate = startDate + "-01" endDate = "" case 7: startDate = "2018-01-01" endDate = "" case 8: startDate = "2019-01-01" endDate = "" case 9: startDate = "2020-01-01" endDate = "" case 11: startDate = "2022-01-01" endDate = "" case DateTypeNYears: if startYear == 0 { //默认取最近5年 startYear = 5 } if yearMax == 0 { return } startYear = startYear - 1 baseDate, _ := time.Parse(FormatDate, fmt.Sprintf("%d-01-01", yearMax)) startDate = baseDate.AddDate(-startYear, 0, 0).Format(FormatDate) endDate = "" } // 兼容日期错误 { if strings.Count(startDate, "-") == 1 { startDate = startDate + "-01" } if strings.Count(endDate, "-") == 1 { endTime, err := time.Parse(FormatYearMonthDate, endDate) if err != nil { return } endDate = endTime.AddDate(0, 1, -1).Format(FormatDate) } } return } func TimeTransferString(format string, t time.Time) string { str := t.Format(format) if t.IsZero() { return "" } return str } // GetDateByDateType2 通过dateType获取需要的开始/结束日期(日期类型:1:最近3月;2:最近6月;3:最近1年;4:最近2年;5:最近3年;6:最近5年;7:最近10年,8:自定义时间) func GetDateByDateType2(dateType int, currDate time.Time) (startDate time.Time) { switch dateType { case 1: startDate = currDate.AddDate(0, -3, 0) case 2: startDate = currDate.AddDate(0, -6, 0) case 3: startDate = currDate.AddDate(-1, 0, 0) case 4: startDate = currDate.AddDate(-2, 0, 0) case 5: startDate = currDate.AddDate(-3, 0, 0) case 6: startDate = currDate.AddDate(-5, 0, 0) case 7: startDate = currDate.AddDate(-10, 0, 0) } return } // GetCeilNewNum 保留n位有效数字的向上取整 // @params num 实际数据 // @params baseLen 需要保留的有效位数 func GetCeilNewNum(num float64, baseLen int) (newNum float64) { if num >= 1 { tmpNum := int(math.Ceil(num)) // 向上取整 str := strconv.Itoa(tmpNum) lenStr := len(str) if lenStr > baseLen { newNumStr := str[0:baseLen] newNumInt, _ := strconv.Atoi(newNumStr) newNum = float64(newNumInt) * math.Pow(10, float64(lenStr-baseLen)) if newNum < num { newNumInt += 1 newNum = float64(newNumInt) * math.Pow(10, float64(lenStr-baseLen)) } } else { newNum = float64(tmpNum) } return } else if num > 0 { // 这是小数 str := strconv.FormatFloat(num, 'f', -1, 64) // 去除小数点和负号 str = removeDecimalPoint(str) // 计算字符串长度 lenStr := len(str) if lenStr > baseLen { newNumStr := str[0:baseLen] newNumInt, _ := strconv.Atoi(newNumStr) newNum, _ = decimal.NewFromInt(int64(newNumInt)).Div(decimal.NewFromFloat(math.Pow(10, float64(baseLen)))).Float64() if newNum < num { newNumInt += 1 newNum, _ = decimal.NewFromInt(int64(newNumInt)).Div(decimal.NewFromFloat(math.Pow(10, float64(baseLen)))).Float64() } } else { newNum = num } } else if num > -1 { // 这是小数 str := strconv.FormatFloat(num, 'f', -1, 64) // 去除小数点和负号 str = removeDecimalPoint(str) // 计算字符串长度 lenStr := len(str) if lenStr > baseLen { newNumStr := str[0:baseLen] newNumInt, _ := strconv.Atoi(newNumStr) newNum, _ = decimal.NewFromInt(int64(newNumInt)).Div(decimal.NewFromFloat(math.Pow(10, float64(baseLen)))).Float64() newNum = -newNum if newNum < num { newNumInt -= 1 newNum, _ = decimal.NewFromInt(int64(newNumInt)).Div(decimal.NewFromFloat(math.Pow(10, float64(baseLen)))).Float64() newNum = -newNum } } else { newNum = num } if newNum == -0 { newNum = 0 } } else { // 小于等于-1 tmpNumFloat := math.Abs(num) tmpNum := int(math.Floor(tmpNumFloat)) // 向上取整 str := strconv.Itoa(tmpNum) lenStr := len(str) if lenStr > baseLen { newNumStr := str[0:baseLen] //fmt.Println("newNumStr:", newNumStr) newNumInt, _ := strconv.Atoi(newNumStr) newNum = float64(newNumInt) * math.Pow(10, float64(lenStr-baseLen)) newNum = -newNum if newNum < num { newNumInt -= 1 newNum = float64(newNumInt) * math.Pow(10, float64(lenStr-baseLen)) newNum = -newNum } } else { newNum = float64(-tmpNum) } } return } // GetFloorNewNum 保留n位有效数字的向下取整 // @params num 实际数据 // @params baseLen 需要保留的有效位数 func GetFloorNewNum(num float64, baseLen int) (newNum float64) { if num >= 1 { tmpNum := int(math.Floor(num)) // 向上取整 str := strconv.Itoa(tmpNum) lenStr := len(str) if lenStr > baseLen { newNumStr := str[0:baseLen] newNumInt, _ := strconv.Atoi(newNumStr) newNum = float64(newNumInt) * math.Pow(10, float64(lenStr-baseLen)) if newNum < num { newNumInt -= 1 newNum = float64(newNumInt) * math.Pow(10, float64(lenStr-baseLen)) } } else { newNum = float64(tmpNum) } return } else if num > 0 { // 这是小数 str := strconv.FormatFloat(num, 'f', -1, 64) // 去除小数点和负号 str = removeDecimalPoint(str) // 计算字符串长度 lenStr := len(str) if lenStr > baseLen { newNumStr := str[0:baseLen] newNumInt, _ := strconv.Atoi(newNumStr) newNum, _ = decimal.NewFromInt(int64(newNumInt)).Div(decimal.NewFromFloat(math.Pow(10, float64(baseLen)))).Float64() if newNum > num { newNumInt -= 1 newNum, _ = decimal.NewFromInt(int64(newNumInt)).Div(decimal.NewFromFloat(math.Pow(10, float64(baseLen)))).Float64() } } else { newNum = num } } else if num > -1 { // 这是小数 str := strconv.FormatFloat(num, 'f', -1, 64) // 去除小数点和负号 str = removeDecimalPoint(str) // 计算字符串长度 lenStr := len(str) if lenStr > baseLen { newNumStr := str[0:baseLen] newNumInt, _ := strconv.Atoi(newNumStr) newNum, _ = decimal.NewFromInt(int64(newNumInt)).Div(decimal.NewFromFloat(math.Pow(10, float64(baseLen)))).Float64() newNum = -newNum if newNum > num { newNumInt += 1 newNum, _ = decimal.NewFromInt(int64(newNumInt)).Div(decimal.NewFromFloat(math.Pow(10, float64(baseLen)))).Float64() newNum = -newNum } } else { newNum = num } if newNum == -0 { newNum = 0 } } else { // 小于等于-1 tmpNumFloat := math.Abs(num) tmpNum := int(math.Ceil(tmpNumFloat)) // 向上取整 str := strconv.Itoa(tmpNum) lenStr := len(str) if lenStr > baseLen { newNumStr := str[0:baseLen] //fmt.Println("newNumStr:", newNumStr) newNumInt, _ := strconv.Atoi(newNumStr) newNum = float64(newNumInt) * math.Pow(10, float64(lenStr-baseLen)) newNum = -newNum if newNum > num { newNumInt += 1 newNum = float64(newNumInt) * math.Pow(10, float64(lenStr-baseLen)) newNum = -newNum } } else { newNum = float64(-tmpNum) } } return } // 去除小数点和负号 func removeDecimalPoint(str string) string { // 去除小数点 str = str[strings.Index(str, ".")+1:] return str } // GetPredictEdbDayListByEndDate 根据截止日期获取预测指标日期列表 func GetPredictEdbDayListByEndDate(startDate, endDate time.Time, frequency string) (dayList []time.Time) { //if !utils.InArrayByStr([]string{"日度", "周度", "月度"}, frequency) switch frequency { case "日度": for currDate := startDate.AddDate(0, 0, 1); currDate.Before(endDate) || currDate.Equal(endDate); currDate = currDate.AddDate(0, 0, 1) { //周六、日排除 if currDate.Weekday() == time.Sunday || currDate.Weekday() == time.Saturday { continue } dayList = append(dayList, currDate) } case "周度": //nextDate := startDate.AddDate(0, 0, 7) for currDate := startDate.AddDate(0, 0, 7); currDate.Before(endDate) || currDate.Equal(endDate); currDate = currDate.AddDate(0, 0, 7) { dayList = append(dayList, currDate) } case "旬度": for currDate := startDate.AddDate(0, 0, 1); currDate.Before(endDate) || currDate.Equal(endDate); { nextDate := currDate.AddDate(0, 0, 1) //每个月的10号、20号、最后一天,那么就写入 if nextDate.Day() == 11 || nextDate.Day() == 21 || nextDate.Day() == 1 { dayList = append(dayList, currDate) } currDate = nextDate } case "月度": for currDate := startDate; currDate.Before(endDate) || currDate.Equal(endDate); { currDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, time.Now().Location()).AddDate(0, 1, -1) if !currDate.After(endDate) && !currDate.Equal(startDate) { dayList = append(dayList, currDate) } currDate = currDate.AddDate(0, 0, 1) } case "季度": for currDate := startDate; currDate.Before(endDate) || currDate.Equal(endDate); { // 每月的最后一天 currDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, time.Now().Location()).AddDate(0, 1, -1) if !currDate.After(endDate) && !currDate.Equal(startDate) { // 季度日期就写入,否则不写入 if currDate.Month() == 3 || currDate.Month() == 6 || currDate.Month() == 9 || currDate.Month() == 12 { dayList = append(dayList, currDate) } } currDate = currDate.AddDate(0, 0, 1) } case "半年度": for currDate := startDate; currDate.Before(endDate) || currDate.Equal(endDate); { // 每月的最后一天 currDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, time.Now().Location()).AddDate(0, 1, -1) if !currDate.After(endDate) && !currDate.Equal(startDate) { // 半年度日期就写入,否则不写入 if currDate.Month() == 6 || currDate.Month() == 12 { dayList = append(dayList, currDate) } } currDate = currDate.AddDate(0, 0, 1) } case "年度": for currDate := startDate; currDate.Before(endDate) || currDate.Equal(endDate); { currDate = time.Date(currDate.Year()+1, 12, 31, 0, 0, 0, 0, time.Now().Location()) if !currDate.After(endDate) && !currDate.Equal(startDate) { dayList = append(dayList, currDate) } } } return } // GetPredictEdbDayListByNum 根据期数获取预测指标日期列表 func GetPredictEdbDayListByNum(startDate time.Time, num int, frequency string) (dayList []time.Time) { switch frequency { case "日度": for i := 1; i <= num; { currDate := startDate.AddDate(0, 0, i) //周六、日排除 if currDate.Weekday() == time.Sunday || currDate.Weekday() == time.Saturday { continue } dayList = append(dayList, currDate) i++ } case "周度": for i := 1; i <= num; { dayList = append(dayList, startDate.AddDate(0, 0, i*7)) i++ } case "旬度": currDate := startDate for i := 1; i <= num; { nextDate := currDate.AddDate(0, 0, 1) //每个月的10号、20号、最后一天,那么就写入 if nextDate.Day() == 11 || nextDate.Day() == 21 || nextDate.Day() == 1 { dayList = append(dayList, currDate) i++ } currDate = nextDate } case "月度": currDate := startDate for i := 1; i <= num; { currDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, time.Now().Location()).AddDate(0, 1, -1) if !currDate.Equal(startDate) { dayList = append(dayList, currDate) i++ } currDate = currDate.AddDate(0, 0, 1) } case "季度": currDate := startDate for i := 1; i <= num; { // 每月的最后一天 currDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, time.Now().Location()).AddDate(0, 1, -1) if !currDate.Equal(startDate) { // 季度日期就写入,否则不写入 if currDate.Month() == 3 || currDate.Month() == 6 || currDate.Month() == 9 || currDate.Month() == 12 { dayList = append(dayList, currDate) i++ } } currDate = currDate.AddDate(0, 0, 1) } case "半年度": currDate := startDate for i := 1; i <= num; { // 每月的最后一天 currDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, time.Now().Location()).AddDate(0, 1, -1) if !currDate.Equal(startDate) { // 半年度日期就写入,否则不写入 if currDate.Month() == 6 || currDate.Month() == 12 { dayList = append(dayList, currDate) i++ } } currDate = currDate.AddDate(0, 0, 1) } case "年度": currDate := startDate for i := 1; i <= num; { currDate = time.Date(currDate.Year()+1, 12, 31, 0, 0, 0, 0, time.Now().Location()) if !currDate.Equal(startDate) { dayList = append(dayList, currDate) i++ } } } return } // FormatMixTableDataShowValue 格式化自定表格显示数据 func FormatMixTableDataShowValue(x float64) (res string) { res = strconv.FormatFloat(x, 'f', -1, 64) return } // FormatTableDataShowValue 格式化自定表格显示数据 func FormatTableDataShowValue(x float64) (res string) { if x > 1 || x < -1 { res = decimal.NewFromFloat(x).Round(2).String() return } // 介于-1到1之间 xStr := strconv.FormatFloat(x, 'f', -10, 64) // 使用 strings.Split 函数将小数拆分为整数部分和小数部分 xParts := strings.Split(xStr, ".") if len(xParts) < 2 { res = fmt.Sprint(x) return } // 计算小数部分的长度,即小数点后面的位数 xDecimals := len(xParts[1]) if xDecimals > 2 { parts := xParts[1] // 小数点后小于等于两位, 直接拼接返回 partLen := len(xParts[1]) if partLen <= 2 { res = xParts[0] + "." + parts return } // 找出第一个有效数字, 算出n one := 0 for k, p := range parts { // 48->0 if p != 48 { if one == 0 { one = k + 1 } } } n := partLen - one if n >= 1 { n -= 1 } else { one -= 1 } var partFloat float64 partInt, _ := strconv.Atoi(parts) partFloat, _ = decimal.NewFromInt(int64(partInt)).Div(decimal.NewFromFloat(math.Pow(10, float64(n)))).Float64() partFloat = math.Round(partFloat) partFloat, _ = decimal.NewFromFloat(partFloat).Div(decimal.NewFromFloat(math.Pow(10, float64(one+1)))).Float64() resParts := strings.Split(fmt.Sprint(partFloat), ".") resPart := "" if len(resParts) > 1 { resPart = resParts[1] } else { resPart = resParts[0] } res = xParts[0] + "." + resPart } if xDecimals <= 2 { xDecimalsStr := xParts[1] x, _ = strconv.ParseFloat(xParts[0]+"."+xDecimalsStr, 64) res = xParts[0] + "." + xDecimalsStr } return } func DealDateTimeZero(t time.Time, format string) (timeStr string) { if !t.IsZero() { timeStr = t.Format(format) } return } // IsPercentage // @Description: 判断一个字符串是否是百分比的字符串,并返回百分比的值(比如:50%,返回true 50) // @author: Roc // @datetime 2023-11-29 14:00:31 // @param input string // @return bool // @return string func IsPercentage(input string) (bool, string) { percentagePattern := `^-?(\d+(\.\d+)?)%$` match, _ := regexp.MatchString(percentagePattern, input) if match { re := regexp.MustCompile(percentagePattern) match := re.FindStringSubmatch(input) // 区分负数和正数,确保返回结果包含负号(如有) sign := "-" if input[0] != '-' { sign = "" } return true, sign + match[1] } return false, "" } // GetLikeKeyword // // @Description: 获取sql查询中的like查询字段 // @author: Roc // @datetime2023-10-23 14:46:32 // @param keyword string // @return string func GetLikeKeyword(keyword string) string { return `%` + keyword + `%` } // GetLikeKeywordPars // // @Description: 获取sql查询中的参数切片 // @author: Roc // @datetime2023-10-23 14:50:18 // @param pars []interface{} // @param keyword string // @param num int // @return newPars []interface{} func GetLikeKeywordPars(pars []interface{}, keyword string, num int) (newPars []interface{}) { newPars = pars if newPars == nil { newPars = make([]interface{}, 0) } for i := 1; i <= num; i++ { newPars = append(newPars, `%`+keyword+`%`) } return } func GetSign(nonce, timestamp, appId, secret string) (sign string) { signStrMap := map[string]string{ "nonce": nonce, "timestamp": timestamp, "appid": appId, } keys := make([]string, 0, len(signStrMap)) for k := range signStrMap { keys = append(keys, k) } sort.Strings(keys) var signStr string for _, k := range keys { signStr += k + "=" + signStrMap[k] + "&" } signStr = strings.Trim(signStr, "&") fmt.Println("signStr:" + signStr) sign = HmacSha256ToBase64(secret, signStr) return } // HmacSha256ToBase64 将加密后的二进制转Base64字符串 func HmacSha256ToBase64(key string, data string) string { return base64.URLEncoding.EncodeToString(HmacSha256(key, data)) } // HmacSha256 计算HmacSha256 // key 是加密所使用的key // data 是加密的内容 func HmacSha256(key string, data string) []byte { mac := hmac.New(sha256.New, []byte(key)) _, _ = mac.Write([]byte(data)) return mac.Sum(nil) } func PascalToSnake(s string) string { var result []rune for i, char := range s { // 在大写字母前插入下划线,除非是第一个字母 if i > 0 && unicode.IsUpper(char) { result = append(result, '_') } // 将字母转为小写 result = append(result, unicode.ToLower(char)) } return string(result) } // ArrContainsStr函数检查一个字符串是否在字符串数组中 func ArrContainsStr(arr []string, str string) bool { for _, v := range arr { if v == str { return true } } return false } func GetColorMap() map[int]string { colorMap := make(map[int]string) colors := []string{"#0000FF", "#FF0000", "#999999", "#000000", "#7CB5EC", "#90ED7D", "#F7A35C", "#8085E9", "#F15C80", "#E4D354", "#2B908F", "#F45B5B", "#91E8E1", "#FDA8C7", "#8A4294", "#578B5A", "#0033FF", "#849EC1", "#FFDF0C", "#005496", "#00F0FF", "#4D535B", "#4F4C34", "#804141", "#86BABD", "#8AA3FF", "#960000", "#A173DB", "#A39340", "#CE814A", "#D1D2E6", "#EAB7B7", "#FF2E7A", "#FF4AF8", "#FF785B", "#FF9696", "#FFA800", "#FFBC97", "#FFDFDF"} for k, v := range colors { colorMap[k] = v } return colorMap } // 检查src属性是否以http或data:image开头 func isValidSrc(src string) bool { // 使用Parse函数解析URL parsedURL, err := url.Parse(src) if err != nil { validSchemes := regexp.MustCompile(`^data:image\/.*;base64,.*$`) return validSchemes.MatchString(src) } if parsedURL.Host == "" || (parsedURL.Scheme != "http" && parsedURL.Scheme != "https") { validSchemes := regexp.MustCompile(`^data:image\/.*;base64,.*$`) return validSchemes.MatchString(src) } return true } // ContentXssCheck 校验文本中的JS代码 func ContentXssCheck(content string) (err error) { // 解析HTML内容 node, err := xhtml.Parse(strings.NewReader(content)) if err != nil { err = fmt.Errorf(" html.Parse Err: %v", err) return } // 遍历解析后的节点树,查找特定标签 var visit func(n *xhtml.Node) error visit = func(n *xhtml.Node) error { if n.Type == xhtml.ElementNode { lowerData := strings.ToLower(n.Data) switch lowerData { case "script", "javascript": err = fmt.Errorf(" script is forbidden") return err default: for _, attr := range n.Attr { //判断事件 lowerKey := strings.ToLower(attr.Key) lowerVal := strings.ToLower(attr.Val) if lowerKey == "src" || lowerKey == "dynsrc" || lowerKey == "background" || lowerKey == "lowsrc" { if lowerVal != `` && !isValidSrc(lowerVal) { err = fmt.Errorf("invalid src attribute value: %s", attr.Val) return err } } if strings.HasPrefix(lowerKey, "on") { err = fmt.Errorf("the event is forbidden: %s:%s", attr.Key, attr.Val) return err } if lowerKey == "style" { if strings.Contains(lowerVal, "javascript:") || strings.Contains(lowerVal, "script:") { err = fmt.Errorf("invalid style attribute value: %s", attr.Val) return err } } } /* case "src": // 如果是某个标签的属性,你可能需要递归检查其父节点 // 这里简单起见,我们假设不是有效的HTML标签,并忽略它 // 在实际中,你可能需要更复杂的逻辑来处理这种情况 fmt.Println("Warning: Unexpected 'src' tag found.")*/ } } for c := n.FirstChild; c != nil; c = c.NextSibling { if err = visit(c); err != nil { return err } } return nil } // 检查HTML文档中的事件 if err = visit(node); err != nil { return } return } func ContentXssFilter(content string) (cleanContent string) { p := customXssPolicy() // The policy can then be used to sanitize lots of input and it is safe to use the policy in multiple goroutines cleanContent = p.Sanitize( content, ) return } func customXssPolicy() (p *bluemonday.Policy) { p = bluemonday.UGCPolicy() // iframe p.AllowElements("iframe") p.AllowAttrs("width").OnElements("iframe") p.AllowAttrs("height").OnElements("iframe") p.AllowAttrs("src").OnElements("iframe") p.AllowAttrs("frameborder").Matching(bluemonday.Number).OnElements("iframe") p.AllowAttrs("allow").Matching(regexp.MustCompile(`[a-z; -]*`)).OnElements("iframe") p.AllowAttrs("allowfullscreen").OnElements("iframe") return } // SecondsToHHMMSS 秒转HH:MM:SS func SecondsToHHMMSS(seconds int) string { duration := time.Duration(seconds) * time.Second hours := int(duration.Hours()) minutes := int(duration.Minutes()) % 60 seconds = int(duration.Seconds()) % 60 if hours > 0 { return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds) } else { return fmt.Sprintf("%02d:%02d", minutes, seconds) } } // MillisecondsToHHMMSS 毫秒转HH:MM:SS func MillisecondsToHHMMSS(ms int) string { duration := time.Duration(ms) * time.Millisecond hours := int(duration / (time.Hour)) minutes := int((duration % (time.Hour)) / time.Minute) seconds := int((duration % time.Hour % time.Minute) / time.Second) // 将整数小时、分钟和秒数转换为字符串,并添加冒号分隔符 hourStr := strconv.Itoa(hours) minuteStr := strconv.Itoa(minutes) secondStr := strconv.Itoa(seconds) // 根据不足两位数的情况补零 if len(hourStr) == 1 { hourStr = "0" + hourStr } if len(minuteStr) == 1 { minuteStr = "0" + minuteStr } if len(secondStr) == 1 { secondStr = "0" + secondStr } return hourStr + ":" + minuteStr + ":" + secondStr } func ByteToMB(byteCount int) float64 { return float64(byteCount) / (1024 * 1024) } // DateConvMysqlConvMongo // @Description: 将mysql中的日期比较符转换成mongo中的日期比较符 // @author: Roc // @datetime 2024-05-08 11:03:26 // @param dateCon string func DateConvMysqlConvMongo(dateCon string) string { cond := "" switch dateCon { case "=": cond = "$eq" case "<": cond = "$lt" case "<=": cond = "$lte" case ">": cond = "$gt" case ">=": cond = "$gte" } return cond } // handleSystemAppointDateT // @Description: 处理系统日期相关的指定频率(所在周/旬/月/季/半年/年的最后/最早一天) // @author: Roc // @datetime2023-10-27 09:31:35 // @param Frequency string // @param Day string // @return date string // @return err error // @return errMsg string func HandleSystemAppointDateT(currDate time.Time, appointDay, frequency string) (date string, err error, errMsg string) { //currDate := time.Now() switch frequency { case "本周": day := int(currDate.Weekday()) if day == 0 { // 周日 day = 7 } num := 0 switch appointDay { case "周一": num = 1 case "周二": num = 2 case "周三": num = 3 case "周四": num = 4 case "周五": num = 5 case "周六": num = 6 case "周日": num = 7 } day = num - day date = currDate.AddDate(0, 0, day).Format(FormatDate) case "本旬": day := currDate.Day() var tmpDate time.Time switch appointDay { case "第一天": if day <= 10 { tmpDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, currDate.Location()) } else if day <= 20 { tmpDate = time.Date(currDate.Year(), currDate.Month(), 11, 0, 0, 0, 0, currDate.Location()) } else { tmpDate = time.Date(currDate.Year(), currDate.Month(), 21, 0, 0, 0, 0, currDate.Location()) } case "最后一天": if day <= 10 { tmpDate = time.Date(currDate.Year(), currDate.Month(), 10, 0, 0, 0, 0, currDate.Location()) } else if day <= 20 { tmpDate = time.Date(currDate.Year(), currDate.Month(), 20, 0, 0, 0, 0, currDate.Location()) } else { tmpDate = time.Date(currDate.Year(), currDate.Month()+1, 1, 0, 0, 0, 0, currDate.Location()).AddDate(0, 0, -1) } } date = tmpDate.Format(FormatDate) case "本月": var tmpDate time.Time switch appointDay { case "第一天": tmpDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, currDate.Location()) case "最后一天": tmpDate = time.Date(currDate.Year(), currDate.Month()+1, 1, 0, 0, 0, 0, currDate.Location()).AddDate(0, 0, -1) } date = tmpDate.Format(FormatDate) case "本季": month := currDate.Month() var tmpDate time.Time switch appointDay { case "第一天": if month <= 3 { tmpDate = time.Date(currDate.Year(), 1, 1, 0, 0, 0, 0, currDate.Location()) } else if month <= 6 { tmpDate = time.Date(currDate.Year(), 4, 1, 0, 0, 0, 0, currDate.Location()) } else if month <= 9 { tmpDate = time.Date(currDate.Year(), 7, 1, 0, 0, 0, 0, currDate.Location()) } else { tmpDate = time.Date(currDate.Year(), 10, 1, 0, 0, 0, 0, currDate.Location()) } case "最后一天": if month <= 3 { tmpDate = time.Date(currDate.Year(), 3, 31, 0, 0, 0, 0, currDate.Location()) } else if month <= 6 { tmpDate = time.Date(currDate.Year(), 6, 30, 0, 0, 0, 0, currDate.Location()) } else if month <= 9 { tmpDate = time.Date(currDate.Year(), 9, 30, 0, 0, 0, 0, currDate.Location()) } else { tmpDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, currDate.Location()) } } date = tmpDate.Format(FormatDate) case "本半年": month := currDate.Month() var tmpDate time.Time switch appointDay { case "第一天": if month <= 6 { tmpDate = time.Date(currDate.Year(), 1, 1, 0, 0, 0, 0, currDate.Location()) } else { tmpDate = time.Date(currDate.Year(), 7, 1, 0, 0, 0, 0, currDate.Location()) } case "最后一天": if month <= 6 { tmpDate = time.Date(currDate.Year(), 6, 30, 0, 0, 0, 0, currDate.Location()) } else { tmpDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, currDate.Location()) } } date = tmpDate.Format(FormatDate) case "本年": var tmpDate time.Time switch appointDay { case "第一天": tmpDate = time.Date(currDate.Year(), 1, 1, 0, 0, 0, 0, currDate.Location()) case "最后一天": tmpDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, currDate.Location()) } date = tmpDate.Format(FormatDate) default: errMsg = "错误的日期频度:" + frequency err = errors.New(errMsg) return } return } func CompareFloatByOpStrings(op string, a, b float64) bool { switch op { case "=": return a == b case ">": return a > b case ">=": return a >= b case "<=": return a <= b case "<": return a < b } return false } func GetDuration(filePath string) (duration string, err error) { // 构建 FFmpeg 命令,使用 ffprobe 来获取媒体文件信息 cmd := exec.Command("ffprobe", "-i", filePath, "-show_entries", "format=duration", "-v", "quiet", "-of", "csv=p=0") var out bytes.Buffer cmd.Stdout = &out // 执行命令并捕获输出 err = cmd.Run() if err != nil { return "", err } // 使用正则表达式匹配输出中的时长信息 re := regexp.MustCompile(`\d+\.\d+`) duration = re.FindString(out.String()) return duration, nil } // ForwardPars // @Description: 向前插入参数 // @param pars // @param values // @return []interface{} func ForwardPars(pars []interface{}, values ...interface{}) []interface{} { if len(values) <= 0 { return pars } return append(values, pars...) } // AppendPars // @Description: 向后插入参数 // @param pars // @param values // @return []interface{} func AppendPars(pars []interface{}, values ...interface{}) []interface{} { if len(values) <= 0 { return pars } return append(pars, values...) } func ExcelDateToDate(excelDate string) time.Time { excelTime := time.Date(1899, time.December, 30, 0, 0, 0, 0, time.UTC) var days, _ = strconv.Atoi(excelDate) return excelTime.Add(time.Second * time.Duration(days*86400)) } // ExcelTimeToTime 将 Excel 中的时间浮点数转换为 Go 的 time.Time(只包含时间部分) func ExcelTimeToTime(excelTime float64) time.Time { // Excel 中的时间是从 0(1900-01-00 00:00:00,注意 Excel 的日期基准问题)开始的浮点数天数 // 这里我们假设日期部分为 0(即只处理时间),并创建一个基准时间(可以是任意日期,因为我们只关心时间) baseTime := time.Date(1899, time.December, 30, 0, 0, 0, 0, time.UTC) // 注意:这里使用 1899-12-30 是因为 Excel 的日期系统从这一天开始(考虑到 1900 年错误) // 计算小时、分钟和秒 hours := int(excelTime * 24) minutes := int(math.Mod(excelTime*24*60, 60)) seconds := int(math.Mod(excelTime*24*60*60, 60)) // 创建一个只包含时间部分的 time.Time 对象 return time.Date(baseTime.Year(), baseTime.Month(), baseTime.Day(), hours, minutes, seconds, 0, time.UTC) } // TimeToFormatDate // @Description: 时间格式转日期字符串 // @param t // @return string func TimeToFormatDate(t time.Time) string { if t.IsZero() { return "0000-00-00" } return t.Format(FormatDate) } // TimeToFormatDateTime // @Description: 时间格式转日期+时间字符串 // @param t // @return string func TimeToFormatDateTime(t time.Time) string { if t.IsZero() { return "0000-00-00 00:00:00" } return t.Format(FormatDateTime) } // FormatDateStrToTime // @Description: 日期字符串转日期格式 // @param timeStr // @return currTime // @return err func FormatDateStrToTime(timeStr string) (currTime time.Time, err error) { if timeStr != `` { return } if strings.Contains(timeStr, "T") { return time.ParseInLocation(FormatDateWallWithLoc, timeStr, time.Local) } if strings.Contains(timeStr, ":") { return time.ParseInLocation(FormatDateTime, timeStr, time.Local) } return time.ParseInLocation(FormatDate, timeStr, time.Local) } // GormDateStrToDateTimeStr // @Description: gorm日期字符串格式转正常显示的日期时间字符串 // @param originalString // @return formatStr func GormDateStrToDateTimeStr(originalString string) (formatStr string) { formatStr = originalString if !strings.Contains(originalString, "T") { return } // 解析原始字符串 t, err := time.Parse(FormatDateWallWithLoc, originalString) if err != nil { fmt.Println("Error parsing time:", err) return } // 重新格式化时间 formatStr = t.Format(FormatDateTime) return } // GormDateStrToDateStr // @Description: gorm日期字符串格式转正常显示的日期字符串 // @param originalString // @return formatStr func GormDateStrToDateStr(originalString string) (formatStr string) { formatStr = originalString if !strings.Contains(originalString, "T") { return } // 解析原始字符串 t, err := time.Parse(FormatDateWallWithLoc, originalString) if err != nil { fmt.Println("Error parsing time:", err) return } // 重新格式化时间 formatStr = t.Format(FormatDate) return } // ReflectSetField // @Description: 通过反射处理时间字段 // @param original // @param result // @param fieldsToProcess // @param formatDate // @return interface{} // @return error func ReflectSetField(original, result interface{}, fieldsToProcess []string, formatDate string) error { // 通过反射处理时间字段 fieldsToProcess = []string{"CreateTime", "ModifyTime", "BaseModifyTime", "StartDate", "EndDate"} for _, fieldName := range fieldsToProcess { value := reflect.ValueOf(original).FieldByName(fieldName) if !value.IsValid() { continue } //fmt.Println("fieldName:", fieldName) //fmt.Println(value.Kind()) //fmt.Println(value.Type()) //fmt.Println(reflect.TypeOf(time.Time{}) == value.Type()) // 如果是时间类型,那么就写入结果中 if reflect.TypeOf(time.Time{}) == value.Type() { t := value.Interface().(time.Time) tmpVal := `` if t.IsZero() { tmpVal = `` } else { tmpVal = t.Format(formatDate) } v := reflect.ValueOf(result).Elem() f := v.FieldByName(fieldName) if !f.IsValid() { fmt.Printf("Field '%s' not found in the struct.\n", fieldName) continue } f.Set(reflect.ValueOf(tmpVal)) } } return nil } // RoundNumber 保留小数位数 func RoundNumber(num string, decimalPlaces int, hasPercent bool) string { numDecimal, _ := decimal.NewFromString(num) if hasPercent { numDecimal = numDecimal.Mul(decimal.NewFromInt(100)) } numFloat, _ := numDecimal.Round(int32(decimalPlaces)).Float64() numStr := strconv.FormatFloat(numFloat, 'f', decimalPlaces, 64) if hasPercent { numStr += "%" } return numStr }