From a1fdc969dd20a97087e986c69fdfd25ffe115368 Mon Sep 17 00:00:00 2001
From: sunty <1172534965@qq.com>
Date: 星期二, 30 四月 2024 18:10:41 +0800
Subject: [PATCH] 新增迁入迁出,属性分析,身份分析等

---
 db/repository.go |  290 ++++++++++++
 config/config.go |   73 +++
 data/prepare.go  |  122 +++++
 go.mod           |   46 ++
 rule/service.go  |  147 ++++++
 main.go          |   46 ++
 rule/engine.go   |  304 +++++++++++++
 util/util.go     |  285 ++++++++++++
 config/app.yaml  |   26 +
 9 files changed, 1,339 insertions(+), 0 deletions(-)

diff --git a/config/app.yaml b/config/app.yaml
new file mode 100644
index 0000000..f740e99
--- /dev/null
+++ b/config/app.yaml
@@ -0,0 +1,26 @@
+app:
+  name: Capture Analysis Rule Model Engine
+  port: 7024
+  logLevel: debug
+database:
+  driver: mysql
+  host: 192.168.20.115
+  port: 3306
+  #  username: root
+  #  password: c++java123
+  name: faceanalysis
+elastic:
+  host: 192.168.20.115
+  port: 9200
+  index: ai_face_ocean
+  type: analysisModel
+  documentSize: 100000
+  topHitsSize: 100000
+  cameraSize: 100000
+  timeInterval: 30
+log:
+  path: /opt/vasystem/valog/
+  level: -1
+  maxSize: 128
+  maxBackups: 30
+  maxAge: 15
\ No newline at end of file
diff --git a/config/config.go b/config/config.go
new file mode 100644
index 0000000..ed8e823
--- /dev/null
+++ b/config/config.go
@@ -0,0 +1,73 @@
+package config
+
+import (
+	"basic.com/valib/logger.git"
+	"github.com/spf13/viper"
+	"log"
+)
+
+type LogConfig struct {
+	Path       string `mapstructure:"path"`       //鏃ュ織瀛樺偍璺緞
+	Level      int    `mapstructure:"level"`      //鏃ュ織绛夌骇
+	MaxSize    int    `mapstructure:"maxSize"`    //鏃ュ織鏂囦欢澶у皬涓婇檺
+	MaxBackups int    `mapstructure:"maxBackups"` //鏃ュ織鍘嬬缉鍖呬釜鏁�
+	MaxAge     int    `mapstructure:"maxAge"`     //淇濈暀鍘嬬缉鍖呭ぉ鏁�
+}
+
+type database struct {
+	Driver string `mapstructure: "driver"`
+	Host   string `mapstructure: "host"`
+	Port   string `mapstructure: "port"`
+	Name   string `mapstructure: "name"`
+}
+
+type elastic struct {
+	Host         string `mapstructure: "host"`
+	Port         string `mapstructure: "port"`
+	Index        string `mapstructure: "index"`
+	Type         string `mapstructure: "type"`
+	DocumentSize int    `mapstructure: "documentSize"`
+	TopHitsSize  int    `mapstructure: "topHitsSize"`
+	CameraSize   int    `mapstructure: "cameraSize"`
+	TimeInterval int    `mapstructure: "timeInterval"`
+}
+
+type app struct {
+	Name     string `mapstructure: "Annotation Service Application"`
+	Port     string `mapstructure: "port"`
+	LogLevel string `mapstructure: "logLevel"`
+}
+
+var LogConf = &LogConfig{}
+var DataBase = &database{}
+var Elastic = &elastic{}
+var App = &app{}
+var LogBasePath string
+var LogLevel int
+
+func Init(env string) {
+	var err error
+	viper.SetConfigType("yaml")
+	viper.SetConfigName(env)
+	viper.AddConfigPath("config")
+	err = viper.ReadInConfig()
+	if err != nil {
+		log.Fatal("error on parsing configuration file", err)
+	}
+	viper.UnmarshalKey("elastic", Elastic)
+	viper.UnmarshalKey("database", DataBase)
+	viper.UnmarshalKey("app", App)
+	viper.UnmarshalKey("log", LogConf)
+	logger.SetLevel(LogConf.Level)
+	if viper.GetString("LogBasePath") != "" {
+		LogBasePath = viper.GetString("LogBasePath")
+	} else {
+		LogBasePath = "./logger/"
+	}
+
+	if viper.IsSet("LogLevel") && viper.GetInt("LogLevel") >= logger.PanicLevel && viper.GetInt("LogLevel") <= logger.DebugLevel {
+		LogLevel = viper.GetInt("LogLevel")
+	} else {
+		LogLevel = logger.DebugLevel
+	}
+}
diff --git a/data/prepare.go b/data/prepare.go
new file mode 100644
index 0000000..ac6cf9a
--- /dev/null
+++ b/data/prepare.go
@@ -0,0 +1,122 @@
+package data
+
+import (
+	"fmt"
+	"ruleModelEngine/db"
+	"time"
+)
+
+// 璁$畻鎶撴媿澶╂暟
+func CalculateCaptureDays(details []db.CaptureDetail) int {
+	// 浣跨敤 map 鏉ュ瓨鍌ㄦ瘡澶╂槸鍚︽湁鎶撴媿璁板綍
+	captureMap := make(map[string]bool)
+	for _, detail := range details {
+		// 瑙f瀽鎶撴媿鏃ユ湡
+		layout := "2006-01-02 15:04:05"
+		captureTime, err := time.Parse(layout, detail.CaptureDate)
+		if err != nil {
+			fmt.Println("瑙f瀽鎶撴媿鏃ユ湡鏃跺嚭閿�:", err)
+			continue
+		}
+		// 鑾峰彇鏃ユ湡閮ㄥ垎
+		date := captureTime.Format("2006-01-02")
+		// 鍦� map 涓爣璁拌繖涓�澶╂湁鎶撴媿璁板綍
+		captureMap[date] = true
+	}
+
+	// 缁熻鏈夋姄鎷嶈褰曠殑澶╂暟
+	captureDays := 0
+	for range captureMap {
+		captureDays++
+	}
+
+	return captureDays
+}
+
+// 璁剧疆鐘舵��
+func SetStatus(captureDays int, rules []db.PersonnelStatusRule) string {
+	for _, rule := range rules {
+		if captureDays >= rule.DetectionDaysStart && captureDays <= rule.DetectionDaysEnd {
+			return rule.Name
+		}
+	}
+	return rules[1].Name
+}
+
+// SetFrequentAddress 鏂规硶璁$畻鍑虹幇鏈�棰戠箒鐨勫嚭琛屽湴鍧�骞惰缃负甯哥敤鍦板潃
+func SetFrequentAddress(c *db.CaptureInfo) {
+	outAddressCounts := make(map[string]int)
+	inAddressCounts := make(map[string]int)
+	// 缁熻姣忎釜鍑鸿鍦板潃鐨勫嚭鐜版鏁�
+	for _, detail := range c.CaptureDetail {
+		if detail.Direction == "out" {
+			outAddressCounts[detail.CaptureAddress]++
+		}
+		if detail.Direction == "in" {
+			inAddressCounts[detail.CaptureAddress]++
+		}
+	}
+
+	// 鎵惧埌鍑虹幇娆℃暟鏈�澶氱殑鍑鸿鍦板潃
+	maxOutCount := 0
+	var frequentAddress string
+	for address, count := range outAddressCounts {
+		if count > maxOutCount {
+			maxOutCount = count
+			frequentAddress = address
+		}
+	}
+	if frequentAddress == "" {
+		maxInCount := 0
+		for address, count := range inAddressCounts {
+			if count > maxInCount {
+				maxInCount = count
+				frequentAddress = address
+			}
+		}
+	}
+	// 灏嗗嚭鐜版鏁版渶澶氱殑鍑鸿鍦板潃璁剧疆涓哄父鐢ㄥ湴鍧�
+	c.FrequentAddress = frequentAddress
+}
+
+// processData 鍑芥暟澶勭悊鏁版嵁锛屾牴鎹姹傝繃婊ゆ帀鏁版嵁骞舵牴鎹鍒欐洿鏂扮姸鎬�
+func ProcessData(captureInfos []db.CaptureInfo, personStatus []db.PersonStatus, ruleInfos []db.PersonnelStatusRule, communityID string) []db.PersonStatus {
+	filteredInfos := make([]db.PersonStatus, 0)
+
+	// 鏋勫缓蹇�熸煡鎵剧储寮曪紝鏂逛究鏌ユ壘瀵瑰簲鐨勪汉鍛樼姸鎬佸拰瑙勫垯
+	statusIndex := make(map[string]db.PersonStatus)
+	ruleIndex := make(map[string]db.PersonnelStatusRule)
+
+	for _, person := range personStatus {
+		statusIndex[person.DocumentNumber] = person
+	}
+
+	for _, rule := range ruleInfos {
+		ruleIndex[rule.Name] = rule
+	}
+
+	// 澶勭悊姣忎釜鎶撴媿淇℃伅
+	for _, info := range captureInfos {
+		//fmt.Println("info", info.DocumentNumber, info.Status, info.FrequentAddress)
+		//fmt.Println("person", statusIndex[info.DocumentNumber].DocumentNumber, statusIndex[info.DocumentNumber].Status, statusIndex[info.DocumentNumber].FrequentAddress)
+		// 妫�鏌ユ槸鍚﹀瓨鍦ㄥ搴旂殑浜哄憳鐘舵��
+		person, ok := statusIndex[info.DocumentNumber]
+		if !ok {
+			// 涓嶅瓨鍦ㄥ搴旂殑浜哄憳鐘舵�佷负鏂版暟鎹�
+			filteredInfos = append(filteredInfos, db.PersonStatus{CommunityID: communityID, DocumentNumber: info.DocumentNumber, Status: info.Status, FrequentAddress: info.FrequentAddress})
+			continue
+		}
+
+		// 鍒ゆ柇鐘舵�佸拰甯哥敤鍦板潃鏄惁鐩哥瓑锛屽鏋滅浉绛夊垯蹇界暐
+		if (info.Status == person.Status || info.CaptureDays <= ruleIndex[person.DocumentNumber].DetectionDaysEnd) &&
+			info.FrequentAddress == person.FrequentAddress {
+			continue
+		}
+
+		// 鏇存柊杩囨护鍚庣殑淇℃伅鍒楄〃
+		filteredInfos = append(filteredInfos, db.PersonStatus{CommunityID: communityID, DocumentNumber: info.DocumentNumber, Status: info.Status, FrequentAddress: info.FrequentAddress})
+
+	}
+
+	return filteredInfos
+}
diff --git a/db/repository.go b/db/repository.go
new file mode 100644
index 0000000..5cdc1d8
--- /dev/null
+++ b/db/repository.go
@@ -0,0 +1,290 @@
+package db
+
+import (
+	"basic.com/valib/logger.git"
+	"errors"
+	"gorm.io/gorm"
+)
+
+// 鏌ヨ灏忓尯琛�
+func GetCommunityIDs() ([]string, error) {
+	db, err := ConnectDB()
+	if err != nil {
+		return nil, err
+	}
+
+	// 鏌ヨ鏁版嵁
+	var communityIDs []string
+	result := db.Table("domain_unit").Where("domainType = ?", 1).Pluck("id", &communityIDs)
+	if result.Error != nil {
+		return nil, result.Error
+	}
+
+	return communityIDs, nil
+}
+
+// 鏌ヨ鍏ㄩ儴鏁版嵁
+func GetAllData() ([]PersonnelStatusRule, error) {
+	db, err := ConnectDB()
+	if err != nil {
+		return nil, err
+	}
+
+	var rules []PersonnelStatusRule
+	if err := db.Find(&rules).Error; err != nil {
+		return nil, err
+	}
+
+	return rules, nil
+}
+
+// 鏌ヨ浣忔埛鏃堕棿鏁版嵁
+func GetResidentData(status, communityID string) ([]Resident, error) {
+	db, err := ConnectDB()
+	if err != nil {
+		return nil, err
+	}
+
+	var residents []Resident
+
+	// 鎵ц鏌ヨ
+	rows, err := db.Table("person_status").
+		Select("person_status.documentNumber", "person_status.communityID", "snapshot_count_summary.last_appearance_time", "snapshot_count_summary.created_at").
+		Joins("INNER JOIN snapshot_count_summary ON person_status.documentNumber = snapshot_count_summary.document_number AND person_status.communityID = snapshot_count_summary.community_id").
+		Where("person_status.status = ? AND person_status.communityID = ?", status, communityID).
+		Rows()
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	// 閬嶅巻鏌ヨ缁撴灉
+	for rows.Next() {
+		var resident Resident
+		err := rows.Scan(&resident.DocumentNumber, &resident.CommunityID, &resident.LastAppearanceTime, &resident.CreateAt)
+		if err != nil {
+			return nil, err
+		}
+		residents = append(residents, resident)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+
+	return residents, nil
+}
+
+// 鏌ヨ浜虹墿灞炴��
+func GetDBPersonStatusData(id string) ([]PersonStatus, error) {
+	db, err := ConnectDB()
+	if err != nil {
+		return nil, err
+	}
+
+	// 鏌ヨ鏁版嵁
+	var personStatusList []PersonStatus
+	if err := db.Table("person_status").
+		Select("documentNumber, status, frequentAddress").
+		Where("communityID = ?", id).
+		Find(&personStatusList).Error; err != nil {
+		return nil, err
+	}
+
+	return personStatusList, nil
+}
+
+// 鏍规嵁绀惧尯id鍜屼綇鎴峰睘鎬ф煡璇綇鎴锋。妗堢紪鍙�
+func GetDocNumberFromPersonStatus(id, status string) ([]string, error) {
+	db, err := ConnectDB()
+	if err != nil {
+		return nil, err
+	}
+
+	// 鏌ヨ鏁版嵁
+	var personStatusList []PersonStatus
+	if err := db.Table("person_status").
+		Select("documentNumber, status, frequentAddress").
+		Where("communityID = ? AND status = ?", id, status).
+		Find(&personStatusList).Error; err != nil {
+		return nil, err
+	}
+
+	docNum := make([]string, 0)
+	for _, ps := range personStatusList {
+		docNum = append(docNum, ps.DocumentNumber)
+	}
+
+	return docNum, nil
+}
+
+// 鏌ヨ浜虹墿韬唤灞炴�ц〃
+func GetLabelManageIdentity(IdentityType int) ([]LabelManage, error) {
+	db, err := ConnectDB()
+	if err != nil {
+		return nil, err
+	}
+
+	// 鏌ヨ鏁版嵁
+	var labelManageIdentity []LabelManage
+	if err := db.Table("label_manage").
+		Select("id, name, valid_days").
+		Where("type = ?", IdentityType).
+		Find(&labelManageIdentity).Error; err != nil {
+		return nil, err
+	}
+
+	return labelManageIdentity, nil
+}
+
+// UpdatePersonInfo 鏇存柊鎴栨彃鍏ュ涓汉鍛樹俊鎭�
+func UpdateMoveInout(personsMoveInout []MoveInout) error {
+	// 鏁版嵁搴撹繛鎺ヤ俊鎭�
+	db, err := ConnectDB()
+	if err != nil {
+		return err
+	}
+	// 閬嶅巻浜哄憳淇℃伅
+	for _, personMoveInout := range personsMoveInout {
+
+		// 妫�鏌ヨ褰曟槸鍚﹀瓨鍦�
+		var existingPerson MoveInout
+		err := db.Where("document_number = ? AND community_id = ?", personMoveInout.DocumentNumber, personMoveInout.CommunityID).First(&existingPerson).Error
+		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
+			logger.Error("Query person error:", err, personMoveInout.DocumentNumber, personMoveInout.CommunityID)
+			//fmt.Println("asdasfasfasf")
+			continue
+			//return err
+		}
+
+		// 濡傛灉璁板綍瀛樺湪锛屽垯鏇存柊
+		if existingPerson.DocumentNumber != "" {
+			if existingPerson.Status != "Verified" {
+				err := db.Model(&MoveInout{}).
+					Where("document_number = ? AND community_id = ?", personMoveInout.DocumentNumber, personMoveInout.CommunityID).
+					Updates(map[string]interface{}{
+						"status":        personMoveInout.Status,
+						"move_out_date": personMoveInout.MoveOutDate,
+					}).Error
+				if err != nil {
+					return err
+				}
+			} else {
+				err := db.Model(&MoveInout{}).
+					Where("document_number = ? AND community_id = ?", personMoveInout.DocumentNumber, personMoveInout.CommunityID).
+					Updates(map[string]interface{}{
+						"move_out_date": personMoveInout.MoveOutDate,
+					}).Error
+				if err != nil {
+					return err
+				}
+			}
+		} else {
+			// 濡傛灉璁板綍涓嶅瓨鍦紝鍒欐彃鍏ユ柊璁板綍
+			err := db.Create(&personsMoveInout).Error
+			if err != nil {
+				return err
+			}
+		}
+
+	}
+
+	return nil
+}
+
+// UpdatePersonInfo 鏇存柊鎴栨彃鍏ュ涓汉鍛樿韩浠戒俊鎭�
+func UpdateDBPersonLabel(personsIdentity []Identity) error {
+	// 鏁版嵁搴撹繛鎺ヤ俊鎭�
+	db, err := ConnectDB()
+	if err != nil {
+		return err
+	}
+	// 閬嶅巻浜哄憳淇℃伅
+	for _, personIdentity := range personsIdentity {
+
+		// 妫�鏌ヨ褰曟槸鍚﹀瓨鍦�
+		var existingPerson Identity
+		err := db.Where("dbtablepersons_id = ? AND community_id = ? AND label_id = ?",
+			personIdentity.DocumentNumber,
+			personIdentity.CommunityID,
+			personIdentity.LabelId,
+		).First(&existingPerson).Error
+		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
+			logger.Error("Query person error:", err,
+				personIdentity.DocumentNumber,
+				personIdentity.CommunityID,
+				personIdentity.LabelId)
+			//fmt.Println("asdasfasfasf")
+			continue
+			//return err
+		}
+
+		// 濡傛灉璁板綍瀛樺湪锛屽垯鏇存柊
+		if existingPerson.DocumentNumber != "" {
+			err := db.Model(&Identity{}).
+				Where("dbtablepersons_id = ? AND community_id = ? AND label_id = ?",
+					personIdentity.DocumentNumber,
+					personIdentity.CommunityID,
+					personIdentity.LabelId,
+				).
+				Updates(map[string]interface{}{
+					"expire_time": personIdentity.ExpireTime,
+				}).Error
+			if err != nil {
+				return err
+			}
+		} else {
+			// 濡傛灉璁板綍涓嶅瓨鍦紝鍒欐彃鍏ユ柊璁板綍
+			err := db.Create(&personIdentity).Error
+			if err != nil {
+				return err
+			}
+		}
+
+	}
+
+	return nil
+}
+
+// UpdatePersonInfo 鏇存柊鎴栨彃鍏ュ涓汉鍛樹俊鎭�
+func UpdatePersonInfo(persons []PersonStatus, communityID string) error {
+	// 鏁版嵁搴撹繛鎺ヤ俊鎭�
+	db, err := ConnectDB()
+	if err != nil {
+		return err
+	}
+	// 閬嶅巻浜哄憳淇℃伅
+	for _, person := range persons {
+
+		// 妫�鏌ヨ褰曟槸鍚﹀瓨鍦�
+		var existingPerson PersonStatus
+		err := db.Where("documentNumber = ? AND communityID = ?", person.DocumentNumber, communityID).First(&existingPerson).Error
+		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
+			logger.Error("Query person error:", err, person.DocumentNumber, communityID)
+			//fmt.Println("asdasfasfasf")
+			continue
+			//return err
+		}
+
+		// 濡傛灉璁板綍瀛樺湪锛屽垯鏇存柊
+		if existingPerson.DocumentNumber != "" {
+			err := db.Model(&PersonStatus{}).
+				Where("documentNumber = ? AND communityID = ?", person.DocumentNumber, communityID).
+				Updates(map[string]interface{}{
+					"status":          person.Status,
+					"frequentAddress": person.FrequentAddress,
+				}).Error
+			if err != nil {
+				return err
+			}
+		} else {
+			// 濡傛灉璁板綍涓嶅瓨鍦紝鍒欐彃鍏ユ柊璁板綍
+			err := db.Create(&person).Error
+			if err != nil {
+				return err
+			}
+		}
+
+	}
+
+	return nil
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..d3cde2e
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,46 @@
+module ruleModelEngine
+
+go 1.20
+
+require (
+	basic.com/pubsub/esutil.git v0.0.0-20240401091908-7a10b30099c6
+	basic.com/valib/logger.git v0.0.0-20220225105132-5cf6309c132f
+	github.com/spf13/viper v1.18.2
+	gorm.io/driver/mysql v1.5.6
+	gorm.io/gorm v1.25.9
+)
+
+require (
+	basic.com/pubsub/protomsg.git v0.0.0-20230210092337-5f1e6cdae7c3 // indirect
+	filippo.io/edwards25519 v1.1.0 // indirect
+	github.com/fsnotify/fsnotify v1.7.0 // indirect
+	github.com/go-sql-driver/mysql v1.8.1 // indirect
+	github.com/gogo/protobuf v1.3.2 // indirect
+	github.com/golang/protobuf v1.5.4 // indirect
+	github.com/hashicorp/hcl v1.0.0 // indirect
+	github.com/jinzhu/inflection v1.0.0 // indirect
+	github.com/jinzhu/now v1.1.5 // indirect
+	github.com/magiconair/properties v1.8.7 // indirect
+	github.com/mitchellh/mapstructure v1.5.0 // indirect
+	github.com/natefinch/lumberjack v2.0.0+incompatible // indirect
+	github.com/pelletier/go-toml/v2 v2.2.1 // indirect
+	github.com/sagikazarmark/locafero v0.4.0 // indirect
+	github.com/sagikazarmark/slog-shim v0.1.0 // indirect
+	github.com/sourcegraph/conc v0.3.0 // indirect
+	github.com/spf13/afero v1.11.0 // indirect
+	github.com/spf13/cast v1.6.0 // indirect
+	github.com/spf13/pflag v1.0.5 // indirect
+	github.com/subosito/gotenv v1.6.0 // indirect
+	go.uber.org/atomic v1.11.0 // indirect
+	go.uber.org/multierr v1.11.0 // indirect
+	go.uber.org/zap v1.27.0 // indirect
+	golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect
+	golang.org/x/net v0.24.0 // indirect
+	golang.org/x/sys v0.19.0 // indirect
+	golang.org/x/text v0.14.0 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect
+	google.golang.org/grpc v1.63.2 // indirect
+	google.golang.org/protobuf v1.33.0 // indirect
+	gopkg.in/ini.v1 v1.67.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..b03808f
--- /dev/null
+++ b/main.go
@@ -0,0 +1,46 @@
+package main
+
+import (
+	"ruleModelEngine/config"
+	//"annotation_service/db"
+	"basic.com/valib/logger.git"
+	"flag"
+	"ruleModelEngine/rule"
+	"time"
+)
+
+var env = flag.String("app", "app", "read database info")
+
+func init() {
+	config.Init(*env)
+	var logFile = config.LogConf.Path + "annotation_service.log"
+	logger.InitLogger(logFile, config.LogConf.Level, config.LogConf.MaxSize, config.LogConf.MaxBackups, config.LogConf.MaxAge)
+	logger.Info("loginit success !")
+
+}
+
+func main() {
+	//db.UpdatePersonStatusByIds()
+	immediate := flag.Bool("immediate", true, "whether to execute immediately")
+	flag.Parse()
+
+	if *immediate {
+		logger.Info("Executing immediately...")
+		rule.ExecuteTask()
+	}
+
+	now := time.Now()
+	next := time.Date(now.Year(), now.Month(), now.Day()+1, 1, 0, 0, 0, now.Location())
+	duration := next.Sub(now)
+
+	timer := time.NewTimer(duration)
+	logger.Info("The program has started and will execute at one o'clock in the early morning every night.")
+	for {
+		<-timer.C
+		logger.Info("Executing at 1 AM...")
+		rule.ExecuteTask()
+		next = next.Add(24 * time.Hour)
+		timer.Reset(next.Sub(time.Now()))
+	}
+
+}
diff --git a/rule/engine.go b/rule/engine.go
new file mode 100644
index 0000000..9409760
--- /dev/null
+++ b/rule/engine.go
@@ -0,0 +1,304 @@
+package rule
+
+import (
+	"basic.com/valib/logger.git"
+	"errors"
+	"fmt"
+	"math"
+	"ruleModelEngine/db"
+	"strings"
+	"time"
+)
+
+func processResidentStatus(residents []db.Resident) []db.MoveInout {
+	// 鑾峰彇褰撳墠鏃ユ湡鐨勫勾鏈堟棩
+	now := time.Now()
+	currentDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
+	moveInout := make([]db.MoveInout, 0)
+
+	// 閬嶅巻Resident缁撴瀯浣撳垏鐗�
+	for _, resident := range residents {
+		//fmt.Println("gogogogo!!!!!!!!!!!!!!!!!!!!!!!!!!!")
+		// 灏嗗瓧绗︿覆绫诲瀷鐨勬椂闂磋浆鎹负time.Time绫诲瀷锛屽苟鍙繚鐣欏勾鏈堟棩
+		lastAppearanceTime := time.Unix(resident.LastAppearanceTime, 0)
+		lastAppearanceDate := time.Date(lastAppearanceTime.Year(), lastAppearanceTime.Month(), lastAppearanceTime.Day(), 0, 0, 0, 0, lastAppearanceTime.Location())
+		//lastAppearanceTime, err := time.Parse("2006-01-02", resident.LastAppearanceTime)
+		datePart := strings.Split(resident.CreateAt, "T")[0]
+		createdAt, err := time.Parse("2006-01-02", datePart)
+		if err != nil {
+			fmt.Println(err)
+			// 澶勭悊鏃堕棿瑙f瀽閿欒
+			// 鍙互閫夋嫨璺宠繃璇ユ潯鏁版嵁鎴栬�呰褰曟棩蹇�
+			continue
+		}
+		// 璁$畻LastAppearanceTime鍜孋reateAt璺濈褰撳墠鏃ユ湡鐨勫ぉ鏁�
+		daysSinceLastAppearance := currentDate.Sub(lastAppearanceDate).Hours() / 24
+		daysSinceCreateAt := currentDate.Sub(createdAt).Hours() / 24
+
+		moveType := "MoveIn"
+		status := ""
+		//fmt.Println("daysSinceLastAppearance: ", daysSinceLastAppearance)
+		//fmt.Println("daysSinceCreateAt: ", daysSinceCreateAt)
+		// 鍒ゆ柇鏄惁涓虹枒浼兼惉绂绘垨纭鎼
+		if daysSinceLastAppearance > 15 {
+			moveType = "MoveOut"
+			status = "Pending"
+		} else if daysSinceLastAppearance > 30 {
+			moveType = "MoveOut"
+			status = "Confirmed"
+		}
+
+		// 鍒ゆ柇鏄惁涓虹枒浼煎叆浣忔垨纭鍏ヤ綇
+		if moveType == "MoveIn" {
+			if daysSinceCreateAt > 15 {
+				status = "Pending"
+			} else if daysSinceCreateAt > 30 {
+				status = "Confirmed"
+			}
+		}
+
+		//fmt.Println("status: ", status)
+		moveInout = append(moveInout, db.MoveInout{
+			DocumentNumber: resident.DocumentNumber,
+			CommunityID:    resident.CommunityID,
+			MoveInDate:     createdAt,           // 瀛樺偍骞存湀鏃�
+			MoveOutDate:    &lastAppearanceDate, // 瀛樺偍骞存湀鏃�
+			MoveType:       moveType,
+			Status:         status,
+		})
+	}
+
+	return moveInout
+}
+
+func ProcessRuleEngine(personInfos []db.CaptureInfo, ruleInfo []db.PersonnelStatusRule, cmmunityID string) (bool, error) {
+	ruleInfoCheck := checkRuleValidity(ruleInfo)
+	if ruleInfoCheck == false {
+		logger.Error("瑙勫垯搴撴暟鎹紓甯�")
+		return false, errors.New("瑙勫垯搴撴暟鎹紓甯�")
+	}
+	fmt.Println("娓呮礂鍓嶏細 ", len(personInfos))
+	logger.Info("瑙勫垯绠楁硶鎵ц瀹屾瘯锛侊紒锛�")
+	return true, nil
+}
+
+func CreateLinearModel(personInfos []db.CaptureInfo, communityID string, threshold float64, validDays int) ([]db.Identity, []db.CaptureInfo) {
+	identity := make([]db.Identity, 0)
+	captureInfo := make([]db.CaptureInfo, 0)
+	for _, info := range personInfos {
+		if info.Status == "resident" {
+			addrData := make(map[string]int)
+			//fmt.Println("DocumentNumber: ", info.DocumentNumber)
+			for _, addr := range info.CaptureDetail {
+				if !strings.Contains(addr.CaptureAddress, "F") || addr.Direction == "in" {
+					continue
+				}
+				addrData[addr.CaptureAddress]++
+			}
+			if len(addrData) < 5 {
+				captureInfo = append(captureInfo, info)
+				continue
+			}
+			addrDataArray := mapIntToFloatSlice(addrData)
+			derivative := firstDerivative(addrDataArray)
+			//fmt.Println(addrData)
+			stdDev := stdDeviation(derivative)
+			if len(addrDataArray) > 10 {
+				stdDev = stdDev / 2
+			}
+
+			if stdDev < threshold {
+				//fmt.Println(addrDataArray)
+				//fmt.Println("threshold: ", threshold)
+				//fmt.Println("stdDev: ", stdDev)
+				info.Status = "fieldworker"
+				captureInfo = append(captureInfo, info)
+				identity = append(identity, db.Identity{
+					CommunityID:    communityID,
+					DocumentNumber: info.DocumentNumber,
+					LabelId:        3,
+					ExpireTime:     GetCurrentDateAddDaysTimestamp(validDays)})
+				continue
+			}
+			captureInfo = append(captureInfo, info)
+		}
+
+	}
+	//addressLinearData := []
+	return identity, captureInfo
+}
+
+func totalDirection(personInfos []db.CaptureInfo) {
+	// 缁熻姣忎釜鍦板潃鐨勮繘鍑烘儏鍐�
+	addrData := make(map[string]map[string]int) // 浣跨敤map[string]map[string]int鏉ュ瓨鍌ㄦ瘡涓湴鍧�鐨勮繘鍑烘儏鍐�
+	for _, info := range personInfos {
+		if info.Status == "resident" {
+			for _, addr := range info.CaptureDetail {
+				if !strings.Contains(addr.CaptureAddress, "F") {
+					continue
+				}
+				// 妫�鏌ヨ鍦板潃鏄惁宸茬粡鍦╝ddrData涓�
+				if _, ok := addrData[addr.CaptureAddress]; !ok {
+					addrData[addr.CaptureAddress] = make(map[string]int)
+				}
+				// 鏇存柊璇ュ湴鍧�鐨勮繘鍑烘儏鍐�
+				addrData[addr.CaptureAddress][addr.Direction]++
+			}
+		}
+	}
+	fmt.Println(addrData)
+}
+
+func CreateProcessModel(personInfos []db.CaptureInfo, days int) {
+	timeTOIndex := getIndexForTime(24 * 60)
+	dateTOIndex := getIndexForDate(days)
+	//fmt.Println(dateTOIndex)
+	inModelMatrix := make([][]int, days)
+	for i := range inModelMatrix {
+		inModelMatrix[i] = make([]int, 24*60)
+	}
+	outModelMatrix := make([][]int, days)
+	for i := range outModelMatrix {
+		outModelMatrix[i] = make([]int, 24*60)
+	}
+	for _, info := range personInfos {
+		//fmt.Println("info: ", info)
+		for _, captureInfo := range info.CaptureDetail {
+			captrueDateTime := captureInfo.CaptureDate
+			dateTimeObj, err := time.Parse("2006-01-02 15:04:05", captrueDateTime)
+			if err != nil {
+				logger.Error("Parse time error", err)
+				return
+			}
+			if isWeekend(dateTimeObj) {
+				continue
+			}
+			datePart := dateTimeObj.Format("2006-01-02")
+			timePart := dateTimeObj.Format("15:04")
+			switch captureInfo.Direction {
+			case "out":
+				outModelMatrix[dateTOIndex[datePart]][timeTOIndex[timePart]] = 1
+			case "in":
+				inModelMatrix[dateTOIndex[datePart]][timeTOIndex[timePart]] = 1
+			default:
+				continue
+			}
+		}
+	}
+	fmt.Println(outModelMatrix)
+	fmt.Println(inModelMatrix)
+}
+
+// 璁$畻涓�闃跺鏁�
+func firstDerivative(data []float64) []float64 {
+	n := len(data)
+	derivative := make([]float64, n)
+
+	for i := 0; i < n-1; i++ {
+		derivative[i] = data[i+1] - data[i]
+	}
+
+	return derivative
+}
+
+// 璁$畻瀵兼暟鐨勬爣鍑嗗樊
+func stdDeviation(data []float64) float64 {
+	n := len(data)
+	mean := 0.0
+
+	// 璁$畻骞冲潎鍊�
+	for _, value := range data {
+		mean += value
+	}
+	mean /= float64(n)
+
+	// 璁$畻鏂瑰樊
+	sum := 0.0
+	for _, value := range data {
+		sum += math.Pow(value-mean, 2)
+	}
+	variance := sum / float64(n)
+
+	return math.Sqrt(variance)
+}
+
+// 灏� map[string]int 杞崲涓� []float64
+func mapIntToFloatSlice(addrData map[string]int) []float64 {
+	var data []float64
+
+	// 閬嶅巻 addrData锛屽皢鍏跺�艰浆鎹负 float64 绫诲瀷鍚庢坊鍔犲埌 data 涓�
+	for _, v := range addrData {
+		data = append(data, float64(v))
+	}
+
+	return data
+}
+
+// GetCurrentDateAddDaysTimestamp 杩斿洖褰撳墠鏃ユ湡鍔犱笂鎸囧畾澶╂暟鍚庣殑鏃堕棿鎴筹紙绉掞級
+func GetCurrentDateAddDaysTimestamp(days int) int64 {
+	// 鑾峰彇褰撳墠鏃堕棿
+	now := time.Now()
+
+	// 鍙繚鐣欏勾鏈堟棩閮ㄥ垎
+	currentYear, currentMonth, currentDay := now.Date()
+
+	// 鏋勫缓褰撳ぉ闆剁偣鏃堕棿
+	zeroTime := time.Date(currentYear, currentMonth, currentDay, 0, 0, 0, 0, now.Location())
+
+	// 灏嗗ぉ鏁拌浆鎹负Duration绫诲瀷
+	duration := time.Duration(days) * 24 * time.Hour
+
+	// 璁$畻鎸囧畾澶╂暟鍚庣殑鏃堕棿
+	futureTime := zeroTime.Add(duration)
+
+	// 杩斿洖鏃堕棿鎴筹紙绉掞級
+	return futureTime.Unix()
+}
+
+// 鍑忓幓鎸囧畾澶╂暟鍚庣殑鏃ユ湡
+func subtractDays(days int) time.Time {
+	// 鑾峰彇褰撳墠鏃堕棿
+	now := time.Now()
+
+	// 鍑忓幓鎸囧畾澶╂暟
+	previousDays := now.AddDate(0, 0, -days)
+
+	return previousDays
+}
+
+// 鍒ゆ柇缁欏畾鏃ユ湡鏄惁鏄懆鏈�
+func isWeekend(date time.Time) bool {
+	dayOfWeek := date.Weekday()
+	return dayOfWeek == time.Saturday || dayOfWeek == time.Sunday
+}
+
+// 鑾峰彇涓棩鏈熷唴鎬诲ぉ鏁板搴旂殑绱㈠紩
+func getIndexForDate(days int) map[string]int {
+	startDate := subtractDays(days)
+	endDate := subtractDays(1)
+	arraySize := days
+	layout := "2006-01-02"
+	dateTOIndex := make(map[string]int)
+	for i := 0; i <= int(endDate.Sub(startDate).Hours()/24); i++ {
+		date := startDate.AddDate(0, 0, i)
+		offsetDays := int(date.Sub(startDate).Hours() / 24)
+		arrayIndex := offsetDays % arraySize
+		dateTOIndex[date.Format(layout)] = arrayIndex
+	}
+
+	return dateTOIndex
+}
+
+// 鑾峰彇涓�澶╀腑姣忓垎閽熺殑绱㈠紩浣嶇疆鏄犲皠
+func getIndexForTime(arraySize int) map[string]int {
+	timeTOIndex := make(map[string]int)
+
+	for i := 0; i < arraySize; i++ {
+		hour := i / 60
+		minute := i % 60
+		timeStr := fmt.Sprintf("%02d:%02d", hour, minute)
+		timeTOIndex[timeStr] = i
+	}
+
+	return timeTOIndex
+}
diff --git a/rule/service.go b/rule/service.go
new file mode 100644
index 0000000..4de8888
--- /dev/null
+++ b/rule/service.go
@@ -0,0 +1,147 @@
+package rule
+
+import (
+	"basic.com/valib/logger.git"
+	"fmt"
+	"ruleModelEngine/data"
+	"ruleModelEngine/db"
+)
+
+//func PrintFilteredPersonnelInfo(filteredPersonnelInfo []db.PersonnelInfo) {
+//	for _, pi := range filteredPersonnelInfo {
+//		fmt.Printf("DocumentNumber: %s\n", pi.DocumentNumber)
+//		fmt.Printf("TotalCaptureCount: %d\n", pi.TotalCaptureCount)
+//		fmt.Printf("TotalCaptureDays: %d\n", pi.TotalCaptureDays)
+//		fmt.Printf("PersonnelStatus: %s\n", pi.PersonnelStatus)
+//
+//		fmt.Println("CaptureDetails:")
+//		for _, cd := range pi.CaptureDetails {
+//			fmt.Printf("  Date: %s\n", cd.Date)
+//			fmt.Printf("  TotalCaptureCount: %d\n", cd.TotalCaptureCount)
+//			fmt.Println("  Captures:")
+//			for _, c := range cd.Captures {
+//				fmt.Printf("    DataTime: %s\n", c.DataTime)
+//				fmt.Printf("    Location: %s\n", c.Location)
+//			}
+//		}
+//		fmt.Println()
+//	}
+//}
+
+// 璁$畻甯哥敤鍦板潃
+//func assignFrequentAddress(personnelInfo []db.PersonnelInfo) []db.PersonnelInfo {
+//	for i := range personnelInfo {
+//		addressCounts := make(map[string]int)
+//		var maxAddress string
+//		maxCount := 0
+//		for _, detail := range personnelInfo[i].CaptureDetails {
+//			for _, capture := range detail.Captures {
+//				addressCounts[capture.Location]++
+//				if addressCounts[capture.Location] > maxCount {
+//					maxCount = addressCounts[capture.Location]
+//					maxAddress = capture.Location
+//				}
+//			}
+//		}
+//		personnelInfo[i].FrequentAddress = maxAddress
+//	}
+//	return personnelInfo
+//}
+
+// 妫�鏌ヨ鍒欒〃涔﹀惁瀛樺湪寮傚父
+func checkRuleValidity(rules []db.PersonnelStatusRule) bool {
+	for i := 0; i < len(rules); i++ {
+		for j := i + 1; j < len(rules); j++ {
+			ruleI := rules[i]
+			ruleJ := rules[j]
+			//fmt.Println(ruleI.DetectionDaysStart,ruleI.DetectionDaysEnd)
+			//fmt.Println(ruleJ.DetectionDaysStart,ruleJ.DetectionDaysEnd)
+			if (ruleI.DetectionDaysStart <= ruleJ.DetectionDaysEnd && ruleI.DetectionDaysStart >= ruleJ.DetectionDaysStart) ||
+				(ruleI.DetectionDaysEnd <= ruleJ.DetectionDaysEnd && ruleI.DetectionDaysEnd >= ruleJ.DetectionDaysStart) ||
+				(ruleI.DetectionDaysStart <= ruleJ.DetectionDaysStart && ruleI.DetectionDaysEnd >= ruleJ.DetectionDaysEnd) {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+// 鎵ц绋嬪簭鍏ュ彛
+func ExecuteTask() {
+	ruleInfo, err := db.GetAllData()
+	if err != nil {
+		logger.Error("GetAllData Error", err)
+	}
+	fmt.Println("ruleInfo: ", ruleInfo)
+	communityIDs, err := db.GetCommunityIDs()
+	//fmt.Println("communityIDs:", communityIDs)
+	if err != nil {
+		logger.Error("GetCommunityIDs Error", err)
+	}
+	for _, communityID := range communityIDs {
+		//鏌ヨ绀惧尯鍐呬汉鍛樻。妗堬紝鏂逛究鏁版嵁鏇存柊
+		personStatus, err := db.GetDBPersonStatusData(communityID)
+		if err != nil {
+			logger.Error("GetDBPersonStatusData Error", err)
+		}
+		labeManage, err := db.GetLabelManageIdentity(2)
+		if err != nil {
+			logger.Error("GetDBPersonStatusData Error", err)
+		}
+		//fmt.Println(labeManage)
+		//fmt.Println("personStatus: ", personStatus)
+		//fmt.Println("CcmmunityIDs: ", cmmunityID)
+		//鎸夌ぞ鍖篿d鏌ヨ杩戜竴涓湀es鏁版嵁
+		captureInfos, err := db.Query1MDataByCommunityId(communityID)
+		//fmt.Println("captureInfos: ", captureInfos)
+		for i := range captureInfos {
+			captureDays := data.CalculateCaptureDays(captureInfos[i].CaptureDetail)
+			captureInfos[i].CaptureDays = captureDays
+			//fmt.Println("璇ヤ汉鍛樺嚭鐜板ぉ鏁颁负", captureInfos[i].CaptureDays)
+			captureInfos[i].Status = data.SetStatus(captureDays, ruleInfo)
+			data.SetFrequentAddress(&captureInfos[i])
+		}
+		if err != nil {
+			logger.Error("MatchAllTargets Error", err)
+		}
+		if len(captureInfos) == 0 {
+			continue
+		}
+		//fmt.Println("captureInfosQ: ", captureInfos)
+		for _, identity := range labeManage {
+			switch identity.Name {
+			case "鏈嶅姟浜哄憳":
+				identity, attribute := CreateLinearModel(captureInfos, communityID, 2.68, identity.ValidDays)
+				errIdentity := db.UpdateDBPersonLabel(identity)
+				if errIdentity != nil {
+					logger.Error("UpdateDBPersonLabel Error", errIdentity)
+				}
+				captureInfos = attribute
+
+			}
+		}
+		//CreateProcessModel(captureInfos, 30)
+		//continue
+		//fmt.Println("captureInfos: ", captureInfos)
+		postCaptureInfos := data.ProcessData(captureInfos, personStatus, ruleInfo, communityID)
+		//fmt.Println("postCaptureInfos: ", postCaptureInfos)
+		//fmt.Println("鍏辫繃婊ゆ潯鏁帮細", len(captureInfos)-len(postCaptureInfos))
+		UpdatePersonInfoErr := db.UpdatePersonInfo(postCaptureInfos, communityID)
+		if UpdatePersonInfoErr != nil {
+			logger.Error("MatchPermanentResidentTargets Error: ", UpdatePersonInfoErr)
+		}
+
+		resident, DocNumberErr := db.GetResidentData("resident", communityID)
+		if DocNumberErr != nil {
+			logger.Error("GetDocNumberFromPersonStatus Error: ", DocNumberErr)
+		}
+		//fmt.Println(resident)
+		mio := processResidentStatus(resident)
+		//fmt.Println("mip: ", mio)
+		UpdateMoveInoutErr := db.UpdateMoveInout(mio)
+		if UpdateMoveInoutErr != nil {
+			logger.Error("UpdateMoveInoutErr Error: ", UpdateMoveInoutErr)
+		}
+	}
+
+}
diff --git a/util/util.go b/util/util.go
new file mode 100644
index 0000000..de40e86
--- /dev/null
+++ b/util/util.go
@@ -0,0 +1,285 @@
+package util
+
+import (
+	"basic.com/valib/logger.git"
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"math"
+	"os/exec"
+	"strconv"
+	"time"
+)
+
+// 鑴氭湰灏佽
+func RunScript(str string) string {
+	cmd := exec.Command("sh", "-c", str)
+	var out bytes.Buffer
+	cmd.Stdout = &out
+	err := cmd.Run()
+	if err != nil {
+		return "杩愯澶辫触"
+	}
+	return out.String()
+}
+
+func Sourcelist(buf []byte) (sources []map[string]interface{}, err error) {
+	var info interface{}
+	json.Unmarshal(buf, &info)
+	out, ok := info.(map[string]interface{})
+	if !ok {
+		return nil, errors.New("http response interface can not change map[string]interface{}")
+	}
+
+	middle, ok := out["hits"].(map[string]interface{})
+	if !ok {
+		return nil, errors.New("first hits change error!")
+	}
+	for _, in := range middle["hits"].([]interface{}) {
+		tmpbuf, ok := in.(map[string]interface{})
+		if !ok {
+			fmt.Println("change to source error!")
+			continue
+		}
+		source, ok := tmpbuf["_source"].(map[string]interface{})
+		if !ok {
+			fmt.Println("change _source error!")
+			continue
+		}
+		sources = append(sources, source)
+	}
+	return sources, nil
+}
+
+func SourceTotal(buf []byte) (total int, err error) {
+	var info interface{}
+	json.Unmarshal(buf, &info)
+	out, ok := info.(map[string]interface{})
+	if !ok {
+		return -1, errors.New("http response interface can not change map[string]interface{}")
+	}
+
+	middle, ok := out["hits"].(map[string]interface{})
+	if !ok {
+		return -1, errors.New("first total change error!")
+	}
+
+	tmp, b := middle["total"].(map[string]interface{})
+	if b != true {
+		v := middle["total"].(float64)
+		t := int(v)
+		return t, nil
+	}
+	value := tmp["value"].(float64)
+	total = int(value)
+	return total, nil
+}
+
+func SourceCreated(buf []byte) (result bool, err error) {
+	var info interface{}
+	json.Unmarshal(buf, &info)
+	out, ok := info.(map[string]interface{})
+	if !ok {
+		return false, errors.New("http response interface can not change map[string]interface{}")
+	}
+
+	middle, ok := out["result"].(string)
+	if !ok {
+		return false, errors.New("first total change error!")
+	}
+	if middle == "created" || middle == "updated" {
+		result = true
+	}
+	return result, nil
+}
+
+func SourceDeleted(buf []byte) (total int, err error) {
+	var info interface{}
+	json.Unmarshal(buf, &info)
+	out, ok := info.(map[string]interface{})
+	if !ok {
+		return -1, errors.New("http response interface can not change map[string]interface{}")
+	}
+
+	middle, ok := out["deleted"].(float64)
+	if !ok {
+		return -1, errors.New("first total change error!")
+	}
+	total = int(middle)
+	return total, nil
+}
+
+func SourceUpdated(buf []byte) (total int, err error) {
+	var info interface{}
+	json.Unmarshal(buf, &info)
+	out, ok := info.(map[string]interface{})
+	if !ok {
+		return -1, errors.New("http response interface can not change map[string]interface{}")
+	}
+	//fmt.Println(out)
+	middle, ok := out["updated"].(float64)
+	if !ok {
+		return -1, errors.New("first total change error!")
+	}
+	total = int(middle)
+	return total, nil
+}
+
+func SourceAggregationList(buf []byte) (sources []map[string]interface{}, err error) {
+	var info interface{}
+	json.Unmarshal(buf, &info)
+	out, ok := info.(map[string]interface{})
+	if !ok {
+		return nil, errors.New("http response interface can not change map[string]interface{}")
+	}
+
+	middle, ok := out["aggregations"].(map[string]interface{})
+	if !ok {
+		return nil, errors.New("first hits change error!")
+	}
+
+	documentAggregations := middle["group_by_documentnumber"].(map[string]interface{})
+	buckets := documentAggregations["buckets"].([]interface{})
+	if len(buckets) == 0 {
+		return nil, nil
+	}
+	for _, in := range buckets {
+		tmpbuf, ok := in.(map[string]interface{})
+		if !ok {
+			return nil, errors.New("")
+		}
+		sources = append(sources, tmpbuf)
+	}
+	return sources, nil
+}
+
+func StartTimer(f func()) {
+	for {
+		f()
+		now := time.Now()
+		// 璁$畻涓嬩竴涓浂鐐�
+		next := now.Add(time.Hour * 24)
+		next = time.Date(next.Year(), next.Month(), next.Day(), 0, 0, 0, 0, next.Location())
+		t := time.NewTimer(next.Sub(now))
+		<-t.C
+		t.Stop()
+	}
+}
+
+// 鏃ユ湡鎹㈢畻宸ュ叿
+func GetTimeArr(earliestDate string) int {
+	now := time.Now().Format("2006-01-02")
+	fmt.Println(earliestDate, now)
+	a, _ := time.Parse("2006-01-02", earliestDate)
+	b, _ := time.Parse("2006-01-02", now)
+	d := a.Sub(b)
+	date := d.Hours() / 24
+	return int(math.Abs(date))
+}
+
+// 鏃ユ湡閬嶅巻宸ュ叿
+// GetBetweenDates 鏍规嵁寮�濮嬫棩鏈熷拰缁撴潫鏃ユ湡璁$畻鍑烘椂闂存鍐呮墍鏈夋棩鏈�
+// 鍙傛暟涓烘棩鏈熸牸寮忥紝濡傦細2020-01-01
+func GetBetweenDates(sdate, edate string) []string {
+	d := []string{}
+	timeFormatTpl := "2006-01-02"
+	if len(timeFormatTpl) != len(sdate) {
+		timeFormatTpl = timeFormatTpl[0:len(sdate)]
+	}
+	date, err := time.Parse(timeFormatTpl, sdate)
+	if err != nil {
+		// 鏃堕棿瑙f瀽锛屽紓甯�
+		return d
+	}
+	date2, err := time.Parse(timeFormatTpl, edate)
+	if err != nil {
+		// 鏃堕棿瑙f瀽锛屽紓甯�
+		return d
+	}
+	if date2.Before(date) {
+		// 濡傛灉缁撴潫鏃堕棿灏忎簬寮�濮嬫椂闂达紝寮傚父
+		return d
+	}
+	// 杈撳嚭鏃ユ湡鏍煎紡鍥哄畾
+	timeFormatTpl = "2006-01-02"
+	date2Str := date2.Format(timeFormatTpl)
+	d = append(d, date.Format(timeFormatTpl))
+	for {
+		date = date.AddDate(0, 0, 1)
+		dateStr := date.Format(timeFormatTpl)
+		d = append(d, dateStr)
+		if dateStr == date2Str {
+			break
+		}
+	}
+	return d
+}
+
+func IpIntToString(ipInt int) string {
+	ipSegs := make([]string, 4)
+	var len int = len(ipSegs)
+	buffer := bytes.NewBufferString("")
+	for i := 0; i < len; i++ {
+		tempInt := ipInt & 0xFF
+		ipSegs[len-i-1] = strconv.Itoa(tempInt)
+
+		ipInt = ipInt >> 8
+	}
+	for i := 0; i < len; i++ {
+		buffer.WriteString(ipSegs[i])
+		if i < len-1 {
+			buffer.WriteString(".")
+		}
+	}
+	return buffer.String()
+}
+
+// 璁$畻鏃堕棿闃堝��
+func CheckTimeDifference(timestampStr1 string, timestampStr2 string, intervalInMinutes int) bool {
+	layout := "2006-01-02 15:04:05"
+	timestampStr1 = timestampStr1[:19]
+	timestampStr2 = timestampStr2[:19]
+	// 灏嗗瓧绗︿覆瑙f瀽涓烘椂闂�
+	time1, err := time.Parse(layout, timestampStr1)
+	if err != nil {
+		fmt.Println("鏃堕棿瑙f瀽澶辫触:", err)
+		return false
+	}
+	time2, err := time.Parse(layout, timestampStr2)
+	if err != nil {
+		fmt.Println("鏃堕棿瑙f瀽澶辫触:", err)
+		return false
+	}
+
+	// 璁$畻鏃堕棿宸�
+	diff := time2.Sub(time1)
+
+	// 妫�鏌ユ椂闂村樊鏄惁灏忎簬绛変簬鎸囧畾鐨勯棿闅�
+	if diff.Minutes() <= float64(intervalInMinutes) {
+		return true
+	} else {
+		return false
+	}
+}
+
+func CalculateDays(startDate string, endDate string) int {
+	layout := "2006-01-02" // 鏃ユ湡鏍煎紡
+	startTime, err := time.Parse(layout, startDate)
+	if err != nil {
+		// 閿欒澶勭悊
+		logger.Error("Error parsing start date:", err)
+		return 0
+	}
+
+	endTime, err := time.Parse(layout, endDate)
+	if err != nil {
+		// 閿欒澶勭悊
+		logger.Error("Error parsing end date:", err)
+		return 0
+	}
+
+	duration := endTime.Sub(startTime)
+	days := int(duration.Hours() / 24) // 灏嗘椂闂村樊杞崲涓哄ぉ鏁�
+	return days
+}

--
Gitblit v1.8.0