|
@@ -7,6 +7,7 @@ import (
|
|
|
"github.com/nosixtools/solarlunar"
|
|
|
"github.com/shopspring/decimal"
|
|
|
"hongze/hongze_edb_lib/utils"
|
|
|
+ "math"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"time"
|
|
@@ -251,6 +252,13 @@ func refreshAllCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo
|
|
|
dateArr = append(dateArr, v.DataTime)
|
|
|
dataMap[v.DataTime] = v
|
|
|
}
|
|
|
+
|
|
|
+ // 通过插值法补全所有数据(包含周末)
|
|
|
+ handleDataMap := make(map[string]float64)
|
|
|
+ err = handleDataByLinearRegression(dataList, handleDataMap)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
//获取指标所有数据
|
|
|
existDataList := make([]*EdbData, 0)
|
|
|
dataTableName := GetEdbDataTableName(source)
|
|
@@ -270,10 +278,10 @@ func refreshAllCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo
|
|
|
addSql := ` INSERT INTO edb_data_calculate_cjjx(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
|
|
|
var isAdd bool
|
|
|
//日度/周度/季度/月度
|
|
|
- isCompatibility := false //是否向上下兼容35天
|
|
|
- if utils.InArrayByStr([]string{"日度", "周度", "季度", "月度"}, fromEdbInfo.Frequency) {
|
|
|
- isCompatibility = true
|
|
|
- }
|
|
|
+ //isCompatibility := false //是否向上下兼容35天
|
|
|
+ //if utils.InArrayByStr([]string{"日度", "周度", "季度", "月度"}, fromEdbInfo.Frequency) {
|
|
|
+ // isCompatibility = true
|
|
|
+ //}
|
|
|
|
|
|
// 每个年份的日期数据需要平移的天数
|
|
|
moveDayMap := make(map[int]int, 0) // 每个年份的春节公历
|
|
@@ -282,90 +290,99 @@ func refreshAllCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo
|
|
|
lastDataDay, _ = time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
|
|
|
}
|
|
|
for _, av := range dateArr {
|
|
|
- currentItem := dataMap[av]
|
|
|
- if currentItem != nil {
|
|
|
- pastValueList := make([]float64, 0) // 过去几期的数据
|
|
|
- //当前日期
|
|
|
- currentDate, tmpErr := time.Parse(utils.FormatDate, av)
|
|
|
- if tmpErr != nil {
|
|
|
- err = tmpErr
|
|
|
- return
|
|
|
- }
|
|
|
- pastValueList = append(pastValueList, currentItem.Value)
|
|
|
-
|
|
|
- for i := 1; i < formulaInt; i++ {
|
|
|
- //前几年当天公历的日期
|
|
|
- hisoryPreDate := currentDate.AddDate(-i, 0, 0)
|
|
|
- moveDay := 0
|
|
|
- if calendar == "农历" {
|
|
|
- if tmpMoveDay, ok := moveDayMap[hisoryPreDate.Year()]; !ok {
|
|
|
- moveDay, err = getMoveDay(lastDataDay, hisoryPreDate)
|
|
|
- if err != nil {
|
|
|
- return
|
|
|
- }
|
|
|
- } else {
|
|
|
- moveDay = tmpMoveDay
|
|
|
- }
|
|
|
+ // 如果遇到闰二月,如2.29,去掉该天数据
|
|
|
+ if strings.Contains(av, "02-29") {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ currentDate, tmpErr := time.Parse(utils.FormatDate, av)
|
|
|
+ if tmpErr != nil {
|
|
|
+ err = tmpErr
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //超季节性指标计算只计算11月--次年5月,分段计算,与数据区间和N数值有关
|
|
|
+ if currentDate.Month() > 5 && currentDate.Month() < 11 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
|
|
|
- // 移动天数到对应农历 的 公历 日期
|
|
|
- hisoryPreDate = hisoryPreDate.AddDate(0, 0, moveDay)
|
|
|
- }
|
|
|
+ currentItem, ok := dataMap[av]
|
|
|
+ // 找不到数据就退出当前循环,进入下一循环
|
|
|
+ if !ok {
|
|
|
+ continue
|
|
|
+ }
|
|
|
|
|
|
- hisoryPreDateStr := hisoryPreDate.Format(utils.FormatDate)
|
|
|
- if findItem, ok := dataMap[hisoryPreDateStr]; ok { //上一年同期找到
|
|
|
- pastValueList = append(pastValueList, findItem.Value)
|
|
|
- } else if isCompatibility { // 如果需要兼容上下35天
|
|
|
- nextDateDay := hisoryPreDate
|
|
|
- preDateDay := hisoryPreDate
|
|
|
- for i := 0; i < 35; i++ {
|
|
|
- nextDateDayStr := nextDateDay.Format(utils.FormatDate)
|
|
|
- if findItem, ok := dataMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
|
|
|
- pastValueList = append(pastValueList, findItem.Value)
|
|
|
- break
|
|
|
- } else {
|
|
|
- preDateDayStr := preDateDay.Format(utils.FormatDate)
|
|
|
- if findItem, ok := dataMap[preDateDayStr]; ok { //上一年同期->上一个月找到
|
|
|
- pastValueList = append(pastValueList, findItem.Value)
|
|
|
- break
|
|
|
- }
|
|
|
- }
|
|
|
- nextDateDay = nextDateDay.AddDate(0, 0, 1)
|
|
|
- preDateDay = preDateDay.AddDate(0, 0, -1)
|
|
|
+ pastValueList := make([]float64, 0) // 过去几期的数据
|
|
|
+ //当前日期
|
|
|
+ pastValueList = append(pastValueList, currentItem.Value)
|
|
|
+
|
|
|
+ for i := 1; i < formulaInt; i++ {
|
|
|
+ //前几年当天公历的日期
|
|
|
+ historyPreDate := currentDate.AddDate(-i, 0, 0)
|
|
|
+ moveDay := 0
|
|
|
+ if calendar == "农历" {
|
|
|
+ if tmpMoveDay, ok := moveDayMap[historyPreDate.Year()]; !ok {
|
|
|
+ moveDay, err = getMoveDay(lastDataDay, historyPreDate)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
}
|
|
|
+ } else {
|
|
|
+ moveDay = tmpMoveDay
|
|
|
}
|
|
|
- if av == "2022-11-28" {
|
|
|
- fmt.Println(moveDay)
|
|
|
- }
|
|
|
- }
|
|
|
- if av == "2022-11-28" {
|
|
|
- fmt.Println(pastValueList)
|
|
|
- }
|
|
|
|
|
|
- if len(pastValueList) == formulaInt {
|
|
|
- delete(removeDataTimeMap, av) //将待删除的日期给移除
|
|
|
+ // 移动天数到对应农历 的 公历 日期
|
|
|
+ historyPreDate = historyPreDate.AddDate(0, 0, moveDay)
|
|
|
+ }
|
|
|
|
|
|
- val := CjjxSub(currentItem.Value, pastValueList)
|
|
|
+ historyPreDateStr := historyPreDate.Format(utils.FormatDate)
|
|
|
+ if tmpValue, ok := handleDataMap[historyPreDateStr]; ok { //上一年同期找到
|
|
|
+ pastValueList = append(pastValueList, tmpValue)
|
|
|
+ }
|
|
|
+ //if findItem, ok := dataMap[hisoryPreDateStr]; ok { //上一年同期找到
|
|
|
+ // pastValueList = append(pastValueList, findItem.Value)
|
|
|
+ //} else if isCompatibility { // 如果需要兼容上下35天
|
|
|
+ // nextDateDay := hisoryPreDate
|
|
|
+ // preDateDay := hisoryPreDate
|
|
|
+ // for i := 0; i < 35; i++ {
|
|
|
+ // nextDateDayStr := nextDateDay.Format(utils.FormatDate)
|
|
|
+ // if findItem, ok := dataMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
|
|
|
+ // pastValueList = append(pastValueList, findItem.Value)
|
|
|
+ // break
|
|
|
+ // } else {
|
|
|
+ // preDateDayStr := preDateDay.Format(utils.FormatDate)
|
|
|
+ // if findItem, ok := dataMap[preDateDayStr]; ok { //上一年同期->上一个月找到
|
|
|
+ // pastValueList = append(pastValueList, findItem.Value)
|
|
|
+ // break
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // nextDateDay = nextDateDay.AddDate(0, 0, 1)
|
|
|
+ // preDateDay = preDateDay.AddDate(0, 0, -1)
|
|
|
+ // }
|
|
|
+ //}
|
|
|
+ }
|
|
|
|
|
|
- if existVal, ok := existDataMap[edbCode+av]; !ok {
|
|
|
- timestamp := currentDate.UnixNano() / 1e6
|
|
|
- timestampStr := fmt.Sprintf("%d", timestamp)
|
|
|
- addSql += GetAddSql(edbInfoIdStr, edbCode, av, timestampStr, val)
|
|
|
- isAdd = true
|
|
|
- } else {
|
|
|
- existValDecimal, err := decimal.NewFromString(existVal)
|
|
|
- existStr := existValDecimal.String()
|
|
|
- if existStr != val {
|
|
|
- sql := ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
|
|
|
- sql = fmt.Sprintf(sql, dataTableName)
|
|
|
- _, err = to.Raw(sql, val, edbInfoId, av).Exec()
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
+ if len(pastValueList) == formulaInt {
|
|
|
+ delete(removeDataTimeMap, av) //将待删除的日期给移除
|
|
|
+
|
|
|
+ val := CjjxSub(currentItem.Value, pastValueList)
|
|
|
+
|
|
|
+ if existVal, ok := existDataMap[edbCode+av]; !ok {
|
|
|
+ timestamp := currentDate.UnixNano() / 1e6
|
|
|
+ timestampStr := fmt.Sprintf("%d", timestamp)
|
|
|
+ addSql += GetAddSql(edbInfoIdStr, edbCode, av, timestampStr, val)
|
|
|
+ isAdd = true
|
|
|
+ } else {
|
|
|
+ existValDecimal, err := decimal.NewFromString(existVal)
|
|
|
+ existStr := existValDecimal.String()
|
|
|
+ if existStr != val {
|
|
|
+ sql := ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
|
|
|
+ sql = fmt.Sprintf(sql, dataTableName)
|
|
|
+ _, err = to.Raw(sql, val, edbInfoId, av).Exec()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- existDataMap[edbCode+av] = av
|
|
|
}
|
|
|
+ existDataMap[edbCode+av] = av
|
|
|
}
|
|
|
|
|
|
//删除已经不存在的超季节性指标数据(由于该指标当日的数据删除了)
|
|
@@ -432,7 +449,7 @@ func getMoveDay(lastDataDay, currentDataDay time.Time) (moveDay int, err error)
|
|
|
|
|
|
// CjjxSub 计算超季节性值
|
|
|
// 计算公式=现值-过去n年(包括今年)均值,n为取数个数,需大于等于1;
|
|
|
-//举例:A指标 2022-10-13值100,2021-10-13值120,2020-10-13值110,设置n=3,则“超季节性”指标计算值为100-(100+120+110)/3=-10。
|
|
|
+// 举例:A指标 2022-10-13值100,2021-10-13值120,2020-10-13值110,设置n=3,则“超季节性”指标计算值为100-(100+120+110)/3=-10。
|
|
|
func CjjxSub(currValue float64, pastValue []float64) (value string) {
|
|
|
num := len(pastValue)
|
|
|
if num == 0 {
|
|
@@ -454,3 +471,72 @@ func CjjxSub(currValue float64, pastValue []float64) (value string) {
|
|
|
valStr := decimal.NewFromFloat(val).RoundCeil(4).String()
|
|
|
return valStr
|
|
|
}
|
|
|
+
|
|
|
+// handleDataByLinearRegression 插值法补充数据(线性方程式)
|
|
|
+func handleDataByLinearRegression(edbInfoDataList []*EdbInfoSearchData, handleDataMap map[string]float64) (err error) {
|
|
|
+ if len(edbInfoDataList) < 2 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ var startEdbInfoData *EdbInfoSearchData
|
|
|
+ for _, v := range edbInfoDataList {
|
|
|
+ handleDataMap[v.DataTime] = v.Value
|
|
|
+
|
|
|
+ // 第一个数据就给过滤了,给后面的试用
|
|
|
+ if startEdbInfoData == nil {
|
|
|
+ startEdbInfoData = v
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取两条数据之间相差的天数
|
|
|
+ startDataTime, _ := time.ParseInLocation(utils.FormatDate, startEdbInfoData.DataTime, time.Local)
|
|
|
+ currDataTime, _ := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
|
|
|
+ betweenHour := int(currDataTime.Sub(startDataTime).Hours())
|
|
|
+ betweenDay := betweenHour / 24
|
|
|
+
|
|
|
+ // 如果相差一天,那么过滤
|
|
|
+ if betweenDay <= 1 {
|
|
|
+ startEdbInfoData = v
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成线性方程式
|
|
|
+ var a, b float64
|
|
|
+ {
|
|
|
+ coordinateData := make([]utils.Coordinate, 0)
|
|
|
+ tmpCoordinate1 := utils.Coordinate{
|
|
|
+ X: 1,
|
|
|
+ Y: startEdbInfoData.Value,
|
|
|
+ }
|
|
|
+ coordinateData = append(coordinateData, tmpCoordinate1)
|
|
|
+ tmpCoordinate2 := utils.Coordinate{
|
|
|
+ X: float64(betweenDay) + 1,
|
|
|
+ Y: v.Value,
|
|
|
+ }
|
|
|
+ coordinateData = append(coordinateData, tmpCoordinate2)
|
|
|
+
|
|
|
+ a, b = utils.GetLinearResult(coordinateData)
|
|
|
+ if math.IsNaN(a) || math.IsNaN(b) {
|
|
|
+ err = errors.New("线性方程公式生成失败")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成对应的值
|
|
|
+ {
|
|
|
+ for i := 1; i < betweenDay; i++ {
|
|
|
+ tmpDataTime := startDataTime.AddDate(0, 0, i)
|
|
|
+ aDecimal := decimal.NewFromFloat(a)
|
|
|
+ xDecimal := decimal.NewFromInt(int64(i) + 1)
|
|
|
+ bDecimal := decimal.NewFromFloat(b)
|
|
|
+
|
|
|
+ val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).RoundCeil(4).Float64()
|
|
|
+ handleDataMap[tmpDataTime.Format(utils.FormatDate)] = val
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ startEdbInfoData = v
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|