Browse Source

feat:超季节性

Roc 2 years ago
parent
commit
3688b7de25
3 changed files with 100 additions and 11 deletions
  1. 1 0
      go.mod
  2. 2 0
      go.sum
  3. 97 11
      models/edb_data_calculate_cjjx.go

+ 1 - 0
go.mod

@@ -8,6 +8,7 @@ require (
 	github.com/beego/beego/v2 v2.0.2
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/go-sql-driver/mysql v1.6.0
+	github.com/nosixtools/solarlunar v0.0.0-20211112060703-1b6dea7b4a19
 	github.com/olivere/elastic/v7 v7.0.32
 	github.com/rdlucklib/rdluck_tools v1.0.3
 	github.com/shopspring/decimal v1.3.1

+ 2 - 0
go.sum

@@ -330,6 +330,8 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi
 github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/nosixtools/solarlunar v0.0.0-20211112060703-1b6dea7b4a19 h1:LhWT2dBuNkYexwRSsPpYh67e0ikmH1ebBDaVkGHoMts=
+github.com/nosixtools/solarlunar v0.0.0-20211112060703-1b6dea7b4a19/go.mod h1:LjhyrWzOLJ9l1azMoNr9iCvfNrHEREqvJHzSLQcD0/o=
 github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
 github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=

+ 97 - 11
models/edb_data_calculate_cjjx.go

@@ -4,6 +4,7 @@ import (
 	"errors"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
+	"github.com/nosixtools/solarlunar"
 	"github.com/shopspring/decimal"
 	"hongze/hongze_edb_lib/utils"
 	"strconv"
@@ -88,7 +89,7 @@ func AddCalculateCjjx(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbInfo, e
 	}
 
 	//计算数据
-	err = refreshAllCalculateCjjx(to, edbInfo.EdbInfoId, edbInfo.Source, fromEdbInfo, edbInfo.EdbCode, "", "", formulaInt)
+	err = refreshAllCalculateCjjx(to, edbInfo.EdbInfoId, edbInfo.Source, fromEdbInfo, edbInfo.EdbCode, "", "", "公历", formulaInt)
 
 	return
 }
@@ -187,7 +188,7 @@ func EditCalculateCjjx(req *EdbInfoCalculateBatchEditReq, edbInfo, fromEdbInfo *
 	}
 
 	//计算数据
-	err = refreshAllCalculateCjjx(to, edbInfo.EdbInfoId, edbInfo.Source, fromEdbInfo, edbInfo.EdbCode, "", "", formulaInt)
+	err = refreshAllCalculateCjjx(to, edbInfo.EdbInfoId, edbInfo.Source, fromEdbInfo, edbInfo.EdbCode, "", "", "公历", formulaInt)
 
 	return
 }
@@ -209,13 +210,13 @@ func RefreshAllCalculateCjjx(edbInfoId, source int, fromEdbInfo *EdbInfo, edbCod
 	}()
 
 	// 重新计算
-	err = refreshAllCalculateCjjx(to, edbInfoId, source, fromEdbInfo, edbCode, startDate, endDate, formulaInt)
+	err = refreshAllCalculateCjjx(to, edbInfoId, source, fromEdbInfo, edbCode, startDate, endDate, "农历", formulaInt)
 
 	return
 }
 
 // refreshAllCalculateCjjx 刷新全部超季节性数据
-func refreshAllCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate string, formulaInt int) (err error) {
+func refreshAllCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate, calendar string, formulaInt int) (err error) {
 	if err != nil {
 		return
 	}
@@ -257,8 +258,10 @@ func refreshAllCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo
 		return err
 	}
 	existDataMap := make(map[string]string)
+	removeDataTimeMap := make(map[string]int) //需要移除的日期数据
 	for _, v := range existDataList {
 		existDataMap[edbCode+v.DataTime] = v.Value
+		removeDataTimeMap[v.DataTime] = 1
 	}
 
 	addSql := ` INSERT INTO edb_data_calculate_cjjx(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
@@ -269,6 +272,12 @@ func refreshAllCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo
 		isCompatibility = true
 	}
 
+	// 每个年份的日期数据需要平移的天数
+	moveDayMap := make(map[int]int, 0) // 每个年份的春节公历
+	var lastDataDay time.Time
+	if len(dataList) > 0 {
+		lastDataDay, _ = time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
+	}
 	for _, av := range dateArr {
 		currentItem := dataMap[av]
 		if currentItem != nil {
@@ -280,15 +289,31 @@ func refreshAllCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo
 				return
 			}
 			pastValueList = append(pastValueList, currentItem.Value)
+
 			for i := 1; i < formulaInt; i++ {
-				//前几年的日期
-				preDate := currentDate.AddDate(-i, 0, 0)
-				preDateStr := preDate.Format(utils.FormatDate)
-				if findItem, ok := dataMap[preDateStr]; ok { //上一年同期找到
+				//前几年当天公历的日期
+				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
+					}
+
+					// 移动天数到对应农历 的 公历 日期
+					hisoryPreDate = hisoryPreDate.AddDate(0, 0, moveDay)
+				}
+
+				hisoryPreDateStr := hisoryPreDate.Format(utils.FormatDate)
+				if findItem, ok := dataMap[hisoryPreDateStr]; ok { //上一年同期找到
 					pastValueList = append(pastValueList, findItem.Value)
 				} else if isCompatibility { // 如果需要兼容上下35天
-					nextDateDay := preDate
-					preDateDay := preDate
+					nextDateDay := hisoryPreDate
+					preDateDay := hisoryPreDate
 					for i := 0; i < 35; i++ {
 						nextDateDayStr := nextDateDay.Format(utils.FormatDate)
 						if findItem, ok := dataMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
@@ -305,9 +330,17 @@ func refreshAllCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo
 						preDateDay = preDateDay.AddDate(0, 0, -1)
 					}
 				}
+				if av == "2022-11-28" {
+					fmt.Println(moveDay)
+				}
+			}
+			if av == "2022-11-28" {
+				fmt.Println(pastValueList)
 			}
 
 			if len(pastValueList) == formulaInt {
+				delete(removeDataTimeMap, av) //将待删除的日期给移除
+
 				val := CjjxSub(currentItem.Value, pastValueList)
 
 				if existVal, ok := existDataMap[edbCode+av]; !ok {
@@ -331,6 +364,26 @@ func refreshAllCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo
 			existDataMap[edbCode+av] = av
 		}
 	}
+
+	//删除已经不存在的超季节性指标数据(由于该指标当日的数据删除了)
+	{
+		removeDateList := make([]string, 0)
+		for dateTime := range removeDataTimeMap {
+			removeDateList = append(removeDateList, dateTime)
+		}
+		removeNum := len(removeDateList)
+		if removeNum > 0 {
+			//如果拼接指标变更了,那么需要删除所有的指标数据
+			tableName := GetEdbDataTableName(source)
+			sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? and data_time in (`+utils.GetOrmInReplace(removeNum)+`) `, tableName)
+			_, err = to.Raw(sql, edbInfoId, removeDateList).Exec()
+			if err != nil {
+				err = fmt.Errorf("删除不存在的超季节性指标数据失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
+
 	if isAdd {
 		addSql = strings.TrimRight(addSql, ",")
 		_, err = to.Raw(addSql).Exec()
@@ -341,6 +394,39 @@ func refreshAllCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo
 	return
 }
 
+// getMoveDay 获取两个日期的平移天数
+func getMoveDay(lastDataDay, currentDataDay time.Time) (moveDay int, err error) {
+	if lastDataDay.Month() >= 11 { //最新数据的日期如果大于等于11月份,那么用的是下一年的春节
+		lastDataDay = lastDataDay.AddDate(1, 0, 0)
+	}
+
+	currentYear := lastDataDay.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
+	}
+
+	//指定年的春节农历
+	tmpYearCjnl := fmt.Sprintf("%d-01-01", currentDataDay.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", currentDataDay.Year(), tmpErr.Error()))
+		return
+	}
+
+	// 将两个日期同步到同一年,然后计算两个日期相差的天数
+	tmpCurrentYearCjglTime := currentYearCjglTime.AddDate(currentDataDay.Year()-currentYear, 0, 0)
+	moveDay = utils.GetTimeSubDay(tmpYearCjglTime, tmpCurrentYearCjglTime)
+
+	return
+}
+
 // 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。
@@ -352,7 +438,7 @@ func CjjxSub(currValue float64, pastValue []float64) (value string) {
 	numDecimal := decimal.NewFromInt(int64(num))
 
 	af := decimal.NewFromFloat(currValue)
-	fmt.Println(af)
+	//fmt.Println(af)
 
 	bf := decimal.NewFromFloat(pastValue[0])