package data import ( "encoding/json" "errors" "eta_gn/eta_api/models/data_manage" "eta_gn/eta_api/utils" "fmt" "github.com/nosixtools/solarlunar" "github.com/shopspring/decimal" "math" "strings" "time" ) type RuleParams struct { EdbInfoId int DayList []time.Time PredictEdbInfoData []*data_manage.EdbDataList RealPredictEdbInfoData []*data_manage.EdbDataList ExistMap map[string]float64 Value string } type RuleCalculate interface { Calculate(params RuleParams) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64, err error) } func GetChartPredictEdbInfoDataListByRule1(edbInfoId int, dataValue float64, dayList []time.Time, predictEdbInfoData []*data_manage.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList) { newPredictEdbInfoData = predictEdbInfoData predictEdbInfoData = make([]*data_manage.EdbDataList, 0) for k, v := range dayList { newPredictEdbInfoData = append(newPredictEdbInfoData, &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + k, EdbInfoId: edbInfoId, DataTime: v.Format(utils.FormatDate), Value: dataValue, DataTimestamp: v.UnixNano() / 1e6, }) existMap[v.Format(utils.FormatDate)] = dataValue } return } func GetChartPredictEdbInfoDataListByRuleTb(edbInfoId int, tbValue float64, dayList []time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64) { allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData index := len(allDataList) predictEdbInfoData = make([]*data_manage.EdbDataList, 0) for k, currentDate := range dayList { tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + index + k, EdbInfoId: edbInfoId, DataTime: currentDate.Format(utils.FormatDate), DataTimestamp: currentDate.UnixNano() / 1e6, } var val float64 var calculateStatus bool //计算结果 preDate := currentDate.AddDate(-1, 0, 0) preDateStr := preDate.Format(utils.FormatDate) if preValue, ok := existMap[preDateStr]; ok { //上一年同期找到 val = TbzDivMul(preValue, tbValue) calculateStatus = true } else { switch frequency { case "月度": nextDateDay := preDate preDateDay := preDate for i := 0; i <= 35; i++ { nextDateDayStr := nextDateDay.Format(utils.FormatDate) if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到 val = TbzDivMul(preValue, tbValue) calculateStatus = true break } else { preDateDayStr := preDateDay.Format(utils.FormatDate) if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到 val = TbzDivMul(preValue, tbValue) calculateStatus = true break } } nextDateDay = nextDateDay.AddDate(0, 0, 1) preDateDay = preDateDay.AddDate(0, 0, -1) } case "季度", "年度": if preValue, ok := existMap[preDateStr]; ok { //上一年同期->下一个月找到 val = TbzDivMul(preValue, tbValue) calculateStatus = true break } default: nextDateDay := preDate preDateDay := preDate for i := 0; i < 35; i++ { nextDateDayStr := nextDateDay.Format(utils.FormatDate) if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到 val = TbzDivMul(preValue, tbValue) calculateStatus = true break } else { preDateDayStr := preDateDay.Format(utils.FormatDate) if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到 val = TbzDivMul(preValue, tbValue) calculateStatus = true break } else { } } nextDateDay = nextDateDay.AddDate(0, 0, 1) preDateDay = preDateDay.AddDate(0, 0, -1) } } } if calculateStatus { tmpData.Value = val newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[tmpData.DataTime] = val if val < minValue { minValue = val } if val > maxValue { maxValue = val } } } return } func TbzDivMul(a, b float64) (result float64) { af := decimal.NewFromFloat(a) bf := decimal.NewFromFloat(b) cf := decimal.NewFromFloat(1) val := bf.Add(cf) result, _ = val.Mul(af).Round(4).Float64() return } func GetChartPredictEdbInfoDataListByRuleTc(edbInfoId int, tcValue float64, dayList []time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64) { allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData index := len(allDataList) predictEdbInfoData = make([]*data_manage.EdbDataList, 0) for k, currentDate := range dayList { tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + index + k, EdbInfoId: edbInfoId, DataTime: currentDate.Format(utils.FormatDate), DataTimestamp: currentDate.UnixNano() / 1e6, } var val float64 var calculateStatus bool //计算结果 preDate := currentDate.AddDate(-1, 0, 0) preDateStr := preDate.Format(utils.FormatDate) if preValue, ok := existMap[preDateStr]; ok { //上一年同期找到 val = TczDiv(preValue, tcValue) calculateStatus = true } else { switch frequency { case "月度": nextDateDay := preDate preDateDay := preDate for i := 0; i <= 35; i++ { nextDateDayStr := nextDateDay.Format(utils.FormatDate) if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到 val = TczDiv(preValue, tcValue) calculateStatus = true break } else { preDateDayStr := preDateDay.Format(utils.FormatDate) if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到 val = TczDiv(preValue, tcValue) calculateStatus = true break } } nextDateDay = nextDateDay.AddDate(0, 0, 1) preDateDay = preDateDay.AddDate(0, 0, -1) } case "季度", "年度": if preValue, ok := existMap[preDateStr]; ok { //上一年同期->下一个月找到 val = TczDiv(preValue, tcValue) calculateStatus = true break } default: nextDateDay := preDate preDateDay := preDate for i := 0; i < 35; i++ { nextDateDayStr := nextDateDay.Format(utils.FormatDate) if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到 val = TczDiv(preValue, tcValue) calculateStatus = true break } else { preDateDayStr := preDateDay.Format(utils.FormatDate) if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到 val = TczDiv(preValue, tcValue) calculateStatus = true break } else { } } nextDateDay = nextDateDay.AddDate(0, 0, 1) preDateDay = preDateDay.AddDate(0, 0, -1) } } } if calculateStatus { tmpData.Value = val newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[tmpData.DataTime] = val if val < minValue { minValue = val } if val > maxValue { maxValue = val } } } return } func TczDiv(a, b float64) (result float64) { if b != 0 { af := decimal.NewFromFloat(a) bf := decimal.NewFromFloat(b) result, _ = af.Add(bf).Round(4).Float64() } else { result = 0 } return } func GetChartPredictEdbInfoDataListByRuleHb(edbInfoId int, hbValue float64, dayList []time.Time, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64) { allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData index := len(allDataList) for k, currentDate := range dayList { tmpK := index + k - 1 //上1期的值 val := HbzDiv(allDataList[tmpK].Value, hbValue) currentDateStr := currentDate.Format(utils.FormatDate) tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + index + k, EdbInfoId: edbInfoId, DataTime: currentDateStr, Value: val, DataTimestamp: currentDate.UnixNano() / 1e6, } newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[currentDateStr] = val if val < minValue { minValue = val } if val > maxValue { maxValue = val } } return } func HbzDiv(a, b float64) (result float64) { if b != 0 { af := decimal.NewFromFloat(a) bf := decimal.NewFromFloat(b) cf := decimal.NewFromFloat(1) val := bf.Add(cf) result, _ = val.Mul(af).Round(4).Float64() } else { result = 0 } return } func GetChartPredictEdbInfoDataListByRuleHc(edbInfoId int, hcValue float64, dayList []time.Time, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64) { allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData index := len(allDataList) for k, currentDate := range dayList { tmpK := index + k - 1 //上1期的值 val := HczDiv(allDataList[tmpK].Value, hcValue) currentDateStr := currentDate.Format(utils.FormatDate) tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + index + k, EdbInfoId: edbInfoId, DataTime: currentDateStr, Value: val, DataTimestamp: currentDate.UnixNano() / 1e6, } newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[currentDateStr] = val if val < minValue { minValue = val } if val > maxValue { maxValue = val } } return } func HczDiv(a, b float64) (result float64) { if b != 0 { af := decimal.NewFromFloat(a) bf := decimal.NewFromFloat(b) result, _ = af.Add(bf).Round(4).Float64() } else { result = 0 } return } func GetChartPredictEdbInfoDataListByRuleNMoveMeanValue(edbInfoId int, nValue int, dayList []time.Time, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64) { allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData lenAllData := len(allDataList) if lenAllData < nValue || lenAllData <= 0 { return } if nValue <= 0 { return } decimalN := decimal.NewFromInt(int64(nValue)) for k, currentDate := range dayList { tmpIndex := lenAllData + k - 1 //上1期的值 tmpDecimalVal := decimal.NewFromFloat(allDataList[tmpIndex].Value) for tmpK := 2; tmpK <= nValue; tmpK++ { tmpIndex2 := tmpIndex - tmpK //上N期的值 tmpDecimalVal2 := decimal.NewFromFloat(allDataList[tmpIndex2].Value) tmpDecimalVal = tmpDecimalVal.Add(tmpDecimalVal2) } val, _ := tmpDecimalVal.Div(decimalN).Round(4).Float64() currentDateStr := currentDate.Format(utils.FormatDate) tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + lenAllData + k, EdbInfoId: edbInfoId, DataTime: currentDateStr, Value: val, DataTimestamp: currentDate.UnixNano() / 1e6, } newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[currentDateStr] = val if val < minValue { minValue = val } if val > maxValue { maxValue = val } } return } func GetChartPredictEdbInfoDataListByRuleNLinearRegression(edbInfoId int, nValue int, dayList []time.Time, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64, err error) { allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData lenAllData := len(allDataList) if lenAllData < nValue || lenAllData <= 0 { return } if nValue <= 1 { return } coordinateData := make([]utils.Coordinate, 0) for tmpK := nValue; tmpK > 0; tmpK-- { tmpIndex2 := lenAllData - tmpK //上N期的值 tmpCoordinate := utils.Coordinate{ X: float64(nValue - tmpK + 1), Y: allDataList[tmpIndex2].Value, } coordinateData = append(coordinateData, tmpCoordinate) } a, b := utils.GetLinearResult(coordinateData) if math.IsNaN(a) || math.IsNaN(b) { err = errors.New("线性方程公式生成失败") return } for k, currentDate := range dayList { tmpK := nValue + k + 1 aDecimal := decimal.NewFromFloat(a) xDecimal := decimal.NewFromInt(int64(tmpK)) bDecimal := decimal.NewFromFloat(b) val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64() currentDateStr := currentDate.Format(utils.FormatDate) tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + lenAllData + k, EdbInfoId: edbInfoId, DataTime: currentDateStr, Value: val, DataTimestamp: currentDate.UnixNano() / 1e6, } newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[currentDateStr] = val if val < minValue { minValue = val } if val > maxValue { maxValue = val } } return } func GetChartPredictEdbInfoDataListByRuleTrendsHC(edbInfoId int, dayList []time.Time, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, hcDataMap, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64) { allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData lenAllData := len(allDataList) if lenAllData <= 0 { return } for k, currentDate := range dayList { tmpLenAllDataList := len(allDataList) lastValue := allDataList[tmpLenAllDataList-1].Value currentDateStr := currentDate.Format(utils.FormatDate) hcVal, ok := hcDataMap[currentDateStr] if !ok { continue } lastValueDecimal := decimal.NewFromFloat(lastValue) hcValDecimal := decimal.NewFromFloat(hcVal) val, _ := lastValueDecimal.Add(hcValDecimal).Round(4).Float64() tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + lenAllData + k, EdbInfoId: edbInfoId, DataTime: currentDateStr, Value: val, DataTimestamp: currentDate.UnixNano() / 1e6, } newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[currentDateStr] = val if val < minValue { minValue = val } if val > maxValue { maxValue = val } } return } func GetChartPredictEdbInfoDataListByRuleFinalValueHc(edbInfoId int, finalValue float64, dayList []time.Time, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64) { allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData index := len(allDataList) lenDay := len(dayList) if lenDay <= 0 { return } var hcValue float64 lastValueDeciamal := decimal.NewFromFloat(allDataList[index-1].Value) // 实际数据的最后一个值 finalValueDeciamal := decimal.NewFromFloat(finalValue) // 给定的终止数据 dayDecimal := decimal.NewFromInt(int64(lenDay)) // 需要作为分母的期数 hcValue, _ = finalValueDeciamal.Sub(lastValueDeciamal).Div(dayDecimal).Float64() // 计算出来的环差值 predictEdbInfoData = make([]*data_manage.EdbDataList, 0) lastK := lenDay - 1 // 最后的日期 for k, currentDate := range dayList { tmpK := index + k - 1 //上1期的值 var val float64 if k == lastK { //如果是最后一天,那么就用最终值,否则就计算 val = finalValue } else { val = HczDiv(allDataList[tmpK].Value, hcValue) } currentDateStr := currentDate.Format(utils.FormatDate) tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + index + k, EdbInfoId: edbInfoId, DataTime: currentDateStr, Value: val, DataTimestamp: currentDate.UnixNano() / 1e6, } newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[currentDateStr] = val if val < minValue { minValue = val } if val > maxValue { maxValue = val } } return } type SeasonConf struct { Calendar string `description:"公历、农历"` YearType int `description:"选择方式,1:连续N年;2:指定年份"` NValue int `description:"连续N年"` YearList []int `description:"指定年份列表"` } func GetChartPredictEdbInfoDataListByRuleSeason(edbInfoId int, configValue string, dayList []time.Time, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64, err error) { yearList, seasonConf, err := getYearListBySeasonConf(configValue) if err != nil { return } calendar := seasonConf.Calendar allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData handleDataMap := make(map[string]float64) err = handleDataByLinearRegression(allDataList, handleDataMap) if err != nil { return } moveDayMap := make(map[int]int, 0) // 每个年份的春节公历 { if calendar == "公历" { for _, year := range yearList { moveDayMap[year] = 0 //公历就不平移了 } } else { currentDay := time.Now() if currentDay.Month() >= 11 { //如果大于等于11月份,那么用的是下一年的春节 currentDay = currentDay.AddDate(1, 0, 0) } currentYear := currentDay.Year() currentYearCjnl := fmt.Sprintf("%d-01-01", currentYear) //当年的春节农历 currentYearCjgl := solarlunar.LunarToSolar(currentYearCjnl, false) //当年的春节公历 currentYearCjglTime, tmpErr := time.ParseInLocation(utils.FormatDate, currentYearCjgl, time.Local) if tmpErr != nil { err = errors.New("当前春节公历日期转换失败:" + tmpErr.Error()) return } for _, year := range yearList { tmpYearCjnl := fmt.Sprintf("%d-01-01", year) //指定年的春节农历 tmpYearCjgl := solarlunar.LunarToSolar(tmpYearCjnl, false) //指定年的春节公历 tmpYearCjglTime, tmpErr := time.ParseInLocation(utils.FormatDate, tmpYearCjgl, time.Local) if tmpErr != nil { err = errors.New(fmt.Sprintf("%d公历日期转换失败:%s", year, tmpErr.Error())) return } tmpCurrentYearCjglTime := currentYearCjglTime.AddDate(year-currentYear, 0, 0) moveDay := utils.GetTimeSubDay(tmpYearCjglTime, tmpCurrentYearCjglTime) moveDayMap[year] = moveDay //公历平移 } } } index := len(allDataList) predictEdbInfoData = make([]*data_manage.EdbDataList, 0) for k, currentDate := range dayList { if strings.Contains(currentDate.Format(utils.FormatDate), "02-29") { continue } tmpHistoryVal := decimal.NewFromFloat(0) //往期的差值总和 tmpHistoryValNum := 0 // 往期差值计算的数量 tmpLenAllDataList := len(allDataList) tmpK := tmpLenAllDataList - 1 //上1期数据的下标 lastDayData := allDataList[tmpK] // 上1期的数据 lastDayStr := lastDayData.DataTime lastDayVal := lastDayData.Value lastDay, tmpErr := time.ParseInLocation(utils.FormatDate, lastDayStr, time.Local) if tmpErr != nil { err = errors.New("获取上期日期转换失败:" + tmpErr.Error()) } for _, year := range yearList { moveDay := moveDayMap[year] //需要移动的天数 var tmpHistoryCurrentVal, tmpHistoryLastVal float64 var isFindHistoryCurrent, isFindHistoryLast bool //是否找到前几年的数据 tmpHistoryCurrentDate := currentDate.AddDate(year-currentDate.Year(), 0, -moveDay) for i := 0; i <= 35; i++ { // 前后35天找数据,找到最近的值,先向后面找,再往前面找 tmpDate := tmpHistoryCurrentDate.AddDate(0, 0, i) if val, ok := handleDataMap[tmpDate.Format(utils.FormatDate)]; ok { tmpHistoryCurrentVal = val isFindHistoryCurrent = true break } else { tmpDate := tmpHistoryCurrentDate.AddDate(0, 0, -i) if val, ok := handleDataMap[tmpDate.Format(utils.FormatDate)]; ok { tmpHistoryCurrentVal = val isFindHistoryCurrent = true break } } } tmpHistoryLastDate := lastDay.AddDate(year-lastDay.Year(), 0, -moveDay) for i := 0; i <= 35; i++ { // 前后35天找数据,找到最近的值,先向后面找,再往前面找 tmpDate := tmpHistoryLastDate.AddDate(0, 0, i) if val, ok := handleDataMap[tmpDate.Format(utils.FormatDate)]; ok { tmpHistoryLastVal = val isFindHistoryLast = true break } else { tmpDate := tmpHistoryLastDate.AddDate(0, 0, -i) if val, ok := handleDataMap[tmpDate.Format(utils.FormatDate)]; ok { tmpHistoryLastVal = val isFindHistoryLast = true break } } } if isFindHistoryCurrent && isFindHistoryLast { af := decimal.NewFromFloat(tmpHistoryCurrentVal) bf := decimal.NewFromFloat(tmpHistoryLastVal) tmpHistoryVal = tmpHistoryVal.Add(af.Sub(bf)) tmpHistoryValNum++ } } if tmpHistoryValNum != len(yearList) { continue } lastDayValDec := decimal.NewFromFloat(lastDayVal) val, _ := tmpHistoryVal.Div(decimal.NewFromInt(int64(tmpHistoryValNum))).Add(lastDayValDec).Round(4).Float64() currentDateStr := currentDate.Format(utils.FormatDate) tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + index + k, EdbInfoId: edbInfoId, DataTime: currentDateStr, Value: val, DataTimestamp: currentDate.UnixNano() / 1e6, } newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[currentDateStr] = val err = handleDataByLinearRegression([]*data_manage.EdbDataList{ lastDayData, tmpData, }, handleDataMap) if err != nil { return } if val < minValue { minValue = val } if val > maxValue { maxValue = val } } return } type MoveAverageConf struct { Year int `description:"指定年份"` NValue int `description:"N期的数据"` } func GetChartPredictEdbInfoDataListByRuleMoveAverageTb(edbInfoId int, nValue, year int, dayList []time.Time, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64, err error) { allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData lenAllData := len(allDataList) if lenAllData < nValue || lenAllData <= 0 { return } if nValue <= 0 { return } decimalN := decimal.NewFromInt(int64(nValue)) subYear := year - dayList[0].Year() for k, currentDate := range dayList { tmpLenAllDataList := len(allDataList) tmpIndex := tmpLenAllDataList - 1 //上1期数据的下标 averageDateList := make([]string, 0) //计算平均数的日期 tmpDecimalVal := decimal.NewFromFloat(allDataList[tmpIndex].Value) averageDateList = append(averageDateList, allDataList[tmpIndex].DataTime) for tmpK := 1; tmpK < nValue; tmpK++ { tmpIndex2 := tmpIndex - tmpK //上N期的值 tmpDecimalVal2 := decimal.NewFromFloat(allDataList[tmpIndex2].Value) tmpDecimalVal = tmpDecimalVal.Add(tmpDecimalVal2) averageDateList = append(averageDateList, allDataList[tmpIndex2].DataTime) } tmpAverageVal := tmpDecimalVal.Div(decimalN) var tmpHistoryCurrentVal float64 // 前几年当日的数据值 var isFindHistoryCurrent, isFindHistoryLast bool //是否找到前几年的数据 tmpHistoryDecimalVal := decimal.NewFromFloat(0) //前几年N期数据总值 { tmpHistoryValNum := 0 { tmpHistoryCurrentDate := currentDate.AddDate(subYear, 0, 0) for i := 0; i <= 35; i++ { // 前后35天找数据,找到最近的值,先向后面找,再往前面找 tmpDate := tmpHistoryCurrentDate.AddDate(0, 0, i) if val, ok := existMap[tmpDate.Format(utils.FormatDate)]; ok { tmpHistoryCurrentVal = val isFindHistoryCurrent = true break } else { tmpDate := tmpHistoryCurrentDate.AddDate(0, 0, -i) if val, ok := existMap[tmpDate.Format(utils.FormatDate)]; ok { tmpHistoryCurrentVal = val isFindHistoryCurrent = true break } } } } for _, averageDate := range averageDateList { lastDay, tmpErr := time.ParseInLocation(utils.FormatDate, averageDate, time.Local) if tmpErr != nil { err = tmpErr return } tmpHistoryLastDate := lastDay.AddDate(subYear, 0, 0) for i := 0; i <= 35; i++ { // 前后35天找数据,找到最近的值,先向后面找,再往前面找 tmpDate := tmpHistoryLastDate.AddDate(0, 0, i) if val, ok := existMap[tmpDate.Format(utils.FormatDate)]; ok { tmpDecimalVal2 := decimal.NewFromFloat(val) tmpHistoryDecimalVal = tmpHistoryDecimalVal.Add(tmpDecimalVal2) tmpHistoryValNum++ break } else { tmpDate := tmpHistoryLastDate.AddDate(0, 0, -i) if val, ok := existMap[tmpDate.Format(utils.FormatDate)]; ok { tmpDecimalVal2 := decimal.NewFromFloat(val) tmpHistoryDecimalVal = tmpHistoryDecimalVal.Add(tmpDecimalVal2) tmpHistoryValNum++ break } } } } if tmpHistoryValNum == nValue { isFindHistoryLast = true } } if !isFindHistoryLast || !isFindHistoryCurrent { continue } tmpHistoryAverageVal := tmpHistoryDecimalVal.Div(decimalN) tbVal := tmpAverageVal.Div(tmpHistoryAverageVal) val, _ := decimal.NewFromFloat(tmpHistoryCurrentVal).Mul(tbVal).Round(4).Float64() currentDateStr := currentDate.Format(utils.FormatDate) tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + lenAllData + k, EdbInfoId: edbInfoId, DataTime: currentDateStr, Value: val, DataTimestamp: currentDate.UnixNano() / 1e6, } newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[currentDateStr] = val if val < minValue { minValue = val } if val > maxValue { maxValue = val } } return } func GetChartPredictEdbInfoDataListByRuleTbzscz(edbInfoId int, tbEndValue float64, dayList []time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64) { allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData index := len(allDataList) if index <= 0 { return } lastData := allDataList[index-1] lastDayTime, _ := time.ParseInLocation(utils.FormatDate, lastData.DataTime, time.Local) var lastTb decimal.Decimal // 计算最新数据与上一期的数据同比值 { preDate := lastDayTime.AddDate(-1, 0, 0) preDateStr := preDate.Format(utils.FormatDate) if preValue, ok := existMap[preDateStr]; ok { //上一年同期找到 lastTb = (decimal.NewFromFloat(lastData.Value)).Sub(decimal.NewFromFloat(preValue)).Div(decimal.NewFromFloat(preValue)) } else { switch frequency { case "月度": nextDateDay := preDate preDateDay := preDate for i := 0; i <= 35; i++ { nextDateDayStr := nextDateDay.Format(utils.FormatDate) if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到 lastTb = (decimal.NewFromFloat(lastData.Value)).Sub(decimal.NewFromFloat(preValue)).Div(decimal.NewFromFloat(preValue)) break } else { preDateDayStr := preDateDay.Format(utils.FormatDate) if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到 lastTb = (decimal.NewFromFloat(lastData.Value)).Sub(decimal.NewFromFloat(preValue)).Div(decimal.NewFromFloat(preValue)) break } } nextDateDay = nextDateDay.AddDate(0, 0, 1) preDateDay = preDateDay.AddDate(0, 0, -1) } case "季度", "年度": if preValue, ok := existMap[preDateStr]; ok { //上一年同期->下一个月找到 lastTb = (decimal.NewFromFloat(lastData.Value)).Sub(decimal.NewFromFloat(preValue)).Div(decimal.NewFromFloat(preValue)) break } default: nextDateDay := preDate preDateDay := preDate for i := 0; i < 35; i++ { nextDateDayStr := nextDateDay.Format(utils.FormatDate) if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到 lastTb = (decimal.NewFromFloat(lastData.Value)).Sub(decimal.NewFromFloat(preValue)).Div(decimal.NewFromFloat(preValue)) break } else { preDateDayStr := preDateDay.Format(utils.FormatDate) if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到 lastTb = (decimal.NewFromFloat(lastData.Value)).Sub(decimal.NewFromFloat(preValue)).Div(decimal.NewFromFloat(preValue)) break } else { } } nextDateDay = nextDateDay.AddDate(0, 0, 1) preDateDay = preDateDay.AddDate(0, 0, -1) } } } } lenDay := len(dayList) tbEndValueDecimal := decimal.NewFromFloat(tbEndValue) avgTbVal := tbEndValueDecimal.Sub(lastTb).Div(decimal.NewFromInt(int64(lenDay))) predictEdbInfoData = make([]*data_manage.EdbDataList, 0) for k, currentDate := range dayList { var tbValue decimal.Decimal if k == lenDay-1 { // 如果是最后的日期了,那么就用终值去计算 tbValue = tbEndValueDecimal.Add(decimal.NewFromInt(1)) } else { // 最近数据的同比值 + (平均增值乘以当前期数) tbValue = lastTb.Add(avgTbVal.Mul(decimal.NewFromInt(int64(k + 1)))).Add(decimal.NewFromInt(1)) } tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + index + k, EdbInfoId: edbInfoId, DataTime: currentDate.Format(utils.FormatDate), DataTimestamp: currentDate.UnixNano() / 1e6, } var val float64 var calculateStatus bool //计算结果 preDate := currentDate.AddDate(-1, 0, 0) preDateStr := preDate.Format(utils.FormatDate) if preValue, ok := existMap[preDateStr]; ok { //上一年同期找到 val, _ = decimal.NewFromFloat(preValue).Mul(tbValue).Round(4).Float64() calculateStatus = true } else { switch frequency { case "月度": nextDateDay := preDate preDateDay := preDate for i := 0; i <= 35; i++ { nextDateDayStr := nextDateDay.Format(utils.FormatDate) if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到 val, _ = decimal.NewFromFloat(preValue).Mul(tbValue).Round(4).Float64() calculateStatus = true break } else { preDateDayStr := preDateDay.Format(utils.FormatDate) if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到 val, _ = decimal.NewFromFloat(preValue).Mul(tbValue).Round(4).Float64() calculateStatus = true break } } nextDateDay = nextDateDay.AddDate(0, 0, 1) preDateDay = preDateDay.AddDate(0, 0, -1) } case "季度", "年度": if preValue, ok := existMap[preDateStr]; ok { //上一年同期->下一个月找到 val, _ = decimal.NewFromFloat(preValue).Mul(tbValue).Round(4).Float64() calculateStatus = true break } default: nextDateDay := preDate preDateDay := preDate for i := 0; i < 35; i++ { nextDateDayStr := nextDateDay.Format(utils.FormatDate) if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到 val, _ = decimal.NewFromFloat(preValue).Mul(tbValue).Round(4).Float64() calculateStatus = true break } else { preDateDayStr := preDateDay.Format(utils.FormatDate) if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到 val, _ = decimal.NewFromFloat(preValue).Mul(tbValue).Round(4).Float64() calculateStatus = true break } else { } } nextDateDay = nextDateDay.AddDate(0, 0, 1) preDateDay = preDateDay.AddDate(0, 0, -1) } } } if calculateStatus { tmpData.Value = val newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[tmpData.DataTime] = val if val < minValue { minValue = val } if val > maxValue { maxValue = val } } } return } type RuleLineNhConf struct { StartDate string `description:"开始日期"` EndDate string `description:"结束日期"` MoveDay int `description:"移动天数"` EdbInfoId int `description:"指标id"` } func GetChartPredictEdbInfoDataListByRuleLineNh(edbInfoId int, dayList []time.Time, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, newNhccDataMap, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64, err error) { allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData lenAllData := len(allDataList) if lenAllData <= 0 { return } for k, currentDate := range dayList { currentDateStr := currentDate.Format(utils.FormatDate) val, ok := newNhccDataMap[currentDateStr] if !ok { continue } tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + lenAllData + k, EdbInfoId: edbInfoId, DataTime: currentDateStr, Value: val, DataTimestamp: currentDate.UnixNano() / 1e6, } newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[currentDateStr] = val if val < minValue { minValue = val } if val > maxValue { maxValue = val } } return } func getCalculateNhccData(secondDataList []*data_manage.EdbDataList, ruleConf RuleLineNhConf) (newBDataMap map[string]float64, err error) { firstEdbInfoId := ruleConf.EdbInfoId moveDay := ruleConf.MoveDay startDate, _ := time.ParseInLocation(utils.FormatDate, ruleConf.StartDate, time.Local) endDate, _ := time.ParseInLocation(utils.FormatDate, ruleConf.EndDate, time.Local) edbInfo, err := data_manage.GetEdbInfoById(firstEdbInfoId) if err != nil { return } aDataList := make([]data_manage.EdbDataList, 0) aDataMap := make(map[string]float64) { var firstDataList []*data_manage.EdbDataList switch edbInfo.EdbInfoType { case 0: firstDataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, ``, ``) case 1: _, firstDataList, _, _, err, _ = GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false) default: err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType)) } if err != nil { return } aDataList, aDataMap = handleNhccData(firstDataList, moveDay) } bDataList := make([]data_manage.EdbDataList, 0) bDataMap := make(map[string]float64) { bDataList, bDataMap = handleNhccData(secondDataList, 0) } if len(aDataList) <= 0 { err = errors.New("指标A没有数据") return } if len(bDataList) <= 0 { err = errors.New("指标B没有数据") return } { endAData := aDataList[len(aDataList)-1] tmpEndDate, tmpErr := time.ParseInLocation(utils.FormatDate, endAData.DataTime, time.Local) if tmpErr != nil { err = tmpErr return } if tmpEndDate.Before(endDate) { endDate = tmpEndDate } endBData := bDataList[len(bDataList)-1] tmpEndDate, tmpErr = time.ParseInLocation(utils.FormatDate, endBData.DataTime, time.Local) if tmpErr != nil { err = tmpErr return } if tmpEndDate.Before(endDate) { endDate = tmpEndDate } } var a, b float64 { coordinateData := make([]utils.Coordinate, 0) for i := startDate; i.Before(endDate) || i.Equal(endDate); i = i.AddDate(0, 0, 1) { dateStr := i.Format(utils.FormatDate) xValue, ok := aDataMap[dateStr] if !ok { err = errors.New("指标A日期:" + dateStr + "数据异常,导致计算线性方程公式失败") return } yValue, ok := bDataMap[dateStr] if !ok { err = errors.New("指标B日期:" + dateStr + "数据异常,导致计算线性方程公式失败") return } tmpCoordinate := utils.Coordinate{ X: xValue, Y: yValue, } coordinateData = append(coordinateData, tmpCoordinate) } a, b = utils.GetLinearResult(coordinateData) } if math.IsNaN(a) || math.IsNaN(b) { err = errors.New("线性方程公式生成失败") return } newBDataMap = make(map[string]float64) { aDecimal := decimal.NewFromFloat(a) bDecimal := decimal.NewFromFloat(b) for _, aData := range aDataList { xDecimal := decimal.NewFromFloat(aData.Value) val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64() newBDataMap[aData.DataTime] = val } } return } func handleNhccData(dataList []*data_manage.EdbDataList, moveDay int) (newDataList []data_manage.EdbDataList, dateDataMap map[string]float64) { dateMap := make(map[time.Time]float64) var minDate, maxDate time.Time dateDataMap = make(map[string]float64) for _, v := range dataList { currDate, _ := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local) if minDate.IsZero() || currDate.Before(minDate) { minDate = currDate } if maxDate.IsZero() || currDate.After(maxDate) { maxDate = currDate } dateMap[currDate] = v.Value } newDateMap := make(map[time.Time]float64) for currDate, value := range dateMap { newDate := currDate.AddDate(0, 0, moveDay) newDateMap[newDate] = value } minDate = minDate.AddDate(0, 0, moveDay) maxDate = maxDate.AddDate(0, 0, moveDay) dayNum := utils.GetTimeSubDay(minDate, maxDate) for i := 0; i <= dayNum; i++ { currDate := minDate.AddDate(0, 0, i) tmpValue, ok := newDateMap[currDate] if !ok { if len(newDataList) <= 0 { continue } tmpValue = newDataList[len(newDataList)-1].Value } tmpData := data_manage.EdbDataList{ DataTime: currDate.Format(utils.FormatDate), Value: tmpValue, } dateDataMap[tmpData.DataTime] = tmpData.Value newDataList = append(newDataList, tmpData) } return } func GetChartPredictEdbInfoDataListByRuleNAnnualAverage(edbInfoId int, configValue string, dayList []time.Time, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64, err error) { yearList, _, err := getYearListBySeasonConf(configValue) if err != nil { return } allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData handleDataMap := make(map[string]float64) err = handleDataByLinearRegression(allDataList, handleDataMap) if err != nil { return } index := len(allDataList) predictEdbInfoData = make([]*data_manage.EdbDataList, 0) for k, currentDate := range dayList { if strings.Contains(currentDate.Format(utils.FormatDate), "02-29") { continue } tmpK := len(allDataList) - 1 //上1期数据的下标 lastDayData := allDataList[tmpK] // 上1期的数据 tmpHistoryVal := decimal.NewFromFloat(0) //往期的差值总和 tmpHistoryValNum := 0 // 往期差值计算的数量 for _, year := range yearList { tmpHistoryCurrentDate := currentDate.AddDate(year-currentDate.Year(), 0, 0) if val, ok := handleDataMap[tmpHistoryCurrentDate.Format(utils.FormatDate)]; ok { tmpHistoryVal = tmpHistoryVal.Add(decimal.NewFromFloat(val)) tmpHistoryValNum++ } } if tmpHistoryValNum != len(yearList) { continue } val, _ := tmpHistoryVal.Div(decimal.NewFromInt(int64(tmpHistoryValNum))).Round(4).Float64() currentDateStr := currentDate.Format(utils.FormatDate) tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + index + k, EdbInfoId: edbInfoId, DataTime: currentDateStr, Value: val, DataTimestamp: currentDate.UnixNano() / 1e6, } newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[currentDateStr] = val err = handleDataByLinearRegression([]*data_manage.EdbDataList{ lastDayData, tmpData, }, handleDataMap) if err != nil { return } if val < minValue { minValue = val } if val > maxValue { maxValue = val } } return } type AnnualValueInversionConf struct { Value float64 `description:"年度值"` Type int `description:"分配方式,1:均值法;2:同比法"` Year int `description:"同比年份"` } func GetChartPredictEdbInfoDataListByRuleAnnualValueInversion(edbInfoId int, configValue string, dayList []time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*data_manage.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*data_manage.EdbDataList, minValue, maxValue float64, err error) { if frequency == "年度" { err = errors.New("当前指标频度是年度,不允许配置年度值倒推") return } var annualValueInversionConf AnnualValueInversionConf err = json.Unmarshal([]byte(configValue), &annualValueInversionConf) if err != nil { err = errors.New("年度值倒推配置信息异常:" + err.Error()) return } allDataList := make([]*data_manage.EdbDataList, 0) allDataList = append(allDataList, realPredictEdbInfoData...) allDataList = append(allDataList, predictEdbInfoData...) newPredictEdbInfoData = predictEdbInfoData index := len(allDataList) yearValueConfig := annualValueInversionConf.Value currDayTime, err := time.ParseInLocation(utils.FormatDate, allDataList[index-1].DataTime, time.Local) if err != nil { return } lastDayTime := dayList[len(dayList)-1] if currDayTime.Year() != lastDayTime.Year() { err = errors.New("年度值倒推不支持跨年预测") return } if annualValueInversionConf.Type == 1 { currYearN := 0 var currYearVal float64 { if frequency != "周度" { for _, v := range allDataList { currTime, tmpErr := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local) if tmpErr != nil { err = tmpErr return } if currTime.Year() != currDayTime.Year() { continue } currYearN++ currYearVal = currYearVal + v.Value } } else { tmpDataList := make([]*data_manage.EdbDataList, 0) var lastData *data_manage.EdbDataList isFirst := true for _, v := range allDataList { currTime, tmpErr := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local) if tmpErr != nil { err = tmpErr return } if currTime.Year() != currDayTime.Year() { lastData = v continue } if isFirst { tmpDataList = append(tmpDataList, lastData) } isFirst = false tmpDataList = append(tmpDataList, v) currYearN++ } tmpHandleDataMap := make(map[string]float64) err = handleDataByLinearRegression(tmpDataList, tmpHandleDataMap) if err != nil { return } for tmpDate, val := range tmpHandleDataMap { tmpDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDate, time.Local) if tmpErr != nil { err = tmpErr return } if tmpDateTime.Year() != currDayTime.Year() { continue } currYearVal = currYearVal + val } currYearVal = currYearVal / 7 } } var averageVal float64 switch frequency { case "半年度": averageVal, _ = (decimal.NewFromFloat(yearValueConfig).Sub(decimal.NewFromFloat(currYearVal))).Div(decimal.NewFromInt(int64(2 - currYearN))).Float64() case "季度": averageVal, _ = (decimal.NewFromFloat(yearValueConfig).Sub(decimal.NewFromFloat(currYearVal))).Div(decimal.NewFromInt(int64(4 - currYearN))).Float64() case "月度": averageVal, _ = (decimal.NewFromFloat(yearValueConfig).Sub(decimal.NewFromFloat(currYearVal))).Div(decimal.NewFromInt(int64(12 - currYearN))).Float64() case "旬度": averageVal, _ = (decimal.NewFromFloat(yearValueConfig).Sub(decimal.NewFromFloat(currYearVal))).Div(decimal.NewFromInt(int64(36 - currYearN))).Float64() case "周度", "日度": yearFirstDay := time.Date(currDayTime.Year(), 1, 1, 0, 0, 0, 0, time.Local) subDay := utils.GetTimeSubDay(yearFirstDay, currDayTime) + 1 yearLastDay := time.Date(currDayTime.Year(), 12, 31, 0, 0, 0, 0, time.Local) subDay2 := utils.GetTimeSubDay(yearFirstDay, yearLastDay) + 1 surplusN := decimal.NewFromInt(int64(subDay2 - subDay)).Div(decimal.NewFromInt(int64(subDay))).Mul(decimal.NewFromInt(int64(currYearN))) balance := decimal.NewFromFloat(annualValueInversionConf.Value).Sub(decimal.NewFromFloat(currYearVal)) averageVal, _ = balance.Div(surplusN).Round(4).Float64() } averageVal, _ = decimal.NewFromFloat(averageVal).Round(4).Float64() for k, currentDate := range dayList { currentDateStr := currentDate.Format(utils.FormatDate) tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + index + k, EdbInfoId: edbInfoId, DataTime: currentDateStr, Value: averageVal, DataTimestamp: currentDate.UnixNano() / 1e6, } newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[currentDateStr] = averageVal } if averageVal < minValue { minValue = averageVal } if averageVal > maxValue { maxValue = averageVal } return } dateTotalMap := make(map[time.Time]float64) yearTotalMap := make(map[int]float64) for _, v := range allDataList { currTime, tmpErr := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local) if tmpErr != nil { err = tmpErr return } yearVal := yearTotalMap[currTime.Year()] yearVal = yearVal + v.Value yearTotalMap[currTime.Year()] = yearVal dateTotalMap[currTime] = yearVal } for k, currentDate := range dayList { currYearBalance := yearValueConfig - yearTotalMap[currentDate.Year()] // 当年的余额 prevDateStr := allDataList[len(allDataList)-1].DataTime prevDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, prevDateStr, time.Local) if tmpErr != nil { err = tmpErr return } lastYear := annualValueInversionConf.Year + (currentDate.Year() - currDayTime.Year()) var lastPrevDateTime, lastDateTime time.Time switch frequency { case "半年度", "季度": lastDateTime = time.Date(lastYear, currentDate.Month(), currentDate.Day(), 0, 0, 0, 0, currentDate.Location()) lastPrevDateTime = time.Date(lastYear, prevDateTime.Month(), prevDateTime.Day(), 0, 0, 0, 0, prevDateTime.Location()) case "月度": lastDateTime = time.Date(lastYear, currentDate.Month()+1, 1, 0, 0, 0, 0, currentDate.Location()).AddDate(0, 0, -1) lastPrevDateTime = time.Date(lastYear, prevDateTime.Month()+1, 1, 0, 0, 0, 0, prevDateTime.Location()).AddDate(0, 0, -1) case "旬度": if prevDateTime.Day() == 10 || prevDateTime.Day() == 20 { lastDateTime = time.Date(lastYear, currentDate.Month(), currentDate.Day(), 0, 0, 0, 0, currentDate.Location()) lastPrevDateTime = time.Date(lastYear, prevDateTime.Month(), prevDateTime.Day(), 0, 0, 0, 0, prevDateTime.Location()) } else { lastDateTime = time.Date(lastYear, currentDate.Month()+1, 1, 0, 0, 0, 0, currentDate.Location()).AddDate(0, 0, -1) lastPrevDateTime = time.Date(lastYear, prevDateTime.Month()+1, 1, 0, 0, 0, 0, prevDateTime.Location()).AddDate(0, 0, -1) } case "周度", "日度": lastDateTime = time.Date(lastYear, currentDate.Month(), currentDate.Day(), 0, 0, 0, 0, currentDate.Location()) lastPrevDateTime = time.Date(lastYear, prevDateTime.Month(), prevDateTime.Day(), 0, 0, 0, 0, prevDateTime.Location()) } var dateTotal float64 dateTotal, ok := dateTotalMap[lastPrevDateTime] if !ok { //如果没有找到这个日期,那么就往前面找,一直到找到这个累计值,或者找完这一年 yearFirstDayTime := time.Date(lastPrevDateTime.Year(), 1, 1, 0, 0, 0, 0, lastDateTime.Location()) for tmpDateTime := lastPrevDateTime.AddDate(0, 0, -1); tmpDateTime.After(yearFirstDayTime) || tmpDateTime.Equal(yearFirstDayTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) { dateTotal, ok = dateTotalMap[tmpDateTime] if ok { break } } } lastYearDateBalance := yearTotalMap[lastPrevDateTime.Year()] - dateTotal if lastYearDateBalance == 0 { continue } tbVal := decimal.NewFromFloat(currYearBalance).Div(decimal.NewFromFloat(lastYearDateBalance)) if lastDateVal, ok := existMap[lastDateTime.Format(utils.FormatDate)]; ok { tmpVal, _ := decimal.NewFromFloat(lastDateVal).Mul(tbVal).Round(4).Float64() currentDateStr := currentDate.Format(utils.FormatDate) tmpData := &data_manage.EdbDataList{ EdbDataId: edbInfoId + 100000 + index + k, EdbInfoId: edbInfoId, DataTime: currentDateStr, Value: tmpVal, DataTimestamp: currentDate.UnixNano() / 1e6, } newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData) allDataList = append(allDataList, tmpData) existMap[currentDateStr] = tmpVal yearVal := yearTotalMap[currentDate.Year()] yearVal = yearVal + tmpVal yearTotalMap[currentDate.Year()] = yearVal dateTotalMap[currentDate] = yearVal if tmpVal < minValue { minValue = tmpVal } if tmpVal > maxValue { maxValue = tmpVal } } } return } func getYearListBySeasonConf(configValue string) (yearList []int, seasonConf SeasonConf, err error) { tmpErr := json.Unmarshal([]byte(configValue), &seasonConf) if tmpErr != nil { err = errors.New("年份配置信息异常:" + tmpErr.Error()) return } if seasonConf.YearType == 1 { if seasonConf.NValue < 1 { err = errors.New("连续N年不允许小于1") return } currYear := time.Now().Year() for i := 0; i < seasonConf.NValue; i++ { yearList = append(yearList, currYear-i-1) } } else { yearList = seasonConf.YearList } return }