github.com/easysoft/zendata@v0.0.0-20240513203326-705bd5a7fd67/internal/pkg/helper/timestamp.go (about) 1 package helper 2 3 import ( 4 "fmt" 5 "math/rand" 6 "strconv" 7 "strings" 8 "time" 9 10 consts "github.com/easysoft/zendata/internal/pkg/const" 11 "github.com/easysoft/zendata/internal/pkg/domain" 12 stringUtils "github.com/easysoft/zendata/pkg/utils/string" 13 "github.com/easysoft/zendata/pkg/utils/vari" 14 "github.com/oklog/ulid/v2" 15 ) 16 17 func CreateTimestampField(field *domain.DefField, fieldWithValue *domain.FieldWithValues) { 18 ConvertTmFormat(field) 19 20 fieldWithValue.Field = field.Field 21 22 rang := strings.Trim(strings.TrimSpace(field.Range), ",") 23 rangeSections := strings.Split(rang, ",") 24 25 values := make([]interface{}, 0) 26 for _, section := range rangeSections { 27 CreateTimestampSectionValue(section, &values) 28 } 29 30 if len(values) == 0 { 31 values = append(values, "N/A") 32 } 33 34 fieldWithValue.Values = values 35 } 36 37 func CreateUlidField(field *domain.DefField, fieldWithValue *domain.FieldWithValues) { 38 count := 0 39 40 t := time.Unix(1000000, 0) 41 entropy := ulid.Monotonic(rand.New(rand.NewSource(t.UnixNano())), 0) 42 43 for true { 44 val := ulid.MustNew(ulid.Timestamp(t), entropy).String() 45 fieldWithValue.Values = append(fieldWithValue.Values, val) 46 47 count++ 48 if count >= consts.MaxNumb || count > vari.GlobalVars.Total { 49 break 50 } 51 } 52 } 53 54 func ConvertTmFormat(field *domain.DefField) { // to 2006-01-02 15:04:05 55 format := field.Format 56 57 if strings.Index(format, "YYYY") > -1 { 58 format = strings.Replace(format, "YYYY", "2006", 1) 59 } else { 60 format = strings.Replace(format, "YY", "06", 1) 61 } 62 63 format = strings.Replace(format, "MM", "01", 1) 64 format = strings.Replace(format, "DD", "02", 1) 65 format = strings.Replace(format, "hh", "15", 1) 66 format = strings.Replace(format, "mm", "04", 1) 67 format = strings.Replace(format, "ss", "05", 1) 68 69 field.Format = format 70 } 71 72 func CreateTimestampSectionValue(section string, values *[]interface{}) { 73 desc, step, unit := parseTsSection(section) 74 start, end := parseTsDesc(desc) 75 76 if (step > 0 && start > end) || (step < 0 && start < end) { 77 step *= -1 78 } 79 80 // get index numbers for data retrieve 81 numbs := GenerateTimeItems(start, end, step, unit, 1, "") 82 83 // generate data by index 84 index := 0 85 for _, numb := range numbs { 86 if index >= consts.MaxNumb { 87 break 88 } 89 90 *values = append(*values, numb) 91 index = index + 1 92 } 93 } 94 95 func parseTsSection(section string) (desc string, step int, unit string) { 96 section = strings.Trim(strings.TrimSpace(section), ":") 97 98 sectionArr := strings.Split(section, ":") 99 desc = sectionArr[0] 100 if len(sectionArr) > 1 { 101 stepStr := sectionArr[1] 102 step, unit = parseTsExpr(stepStr) 103 if step == 0 { 104 step = 1 105 } 106 } 107 108 return 109 } 110 111 func parseTsDesc(desc string) (start, end int64) { 112 desc = strings.TrimSpace(desc) 113 114 if strings.Contains(desc, "today") { 115 start, end = getTodayTs() 116 return 117 } 118 119 startStr, endStr := splitTmDesc(desc) 120 121 start = parseTsValue(startStr, true) 122 end = parseTsValue(endStr, false) 123 124 //logUtils.PrintTo( 125 // fmt.Sprintf("From %s to %s", 126 // time.Unix(start, 0).Format("2006-01-02 15:04:05"), 127 // time.Unix(end, 0).Format("2006-01-02 15:04:05"))) 128 129 return 130 } 131 132 func splitTmDesc(desc string) (start, end string) { 133 runeArr := []rune(desc) 134 135 index := -1 136 bracketsOpen := false 137 for i := 0; i < len(runeArr); i++ { 138 c := runeArr[i] 139 140 if c == consts.RightBrackets { 141 bracketsOpen = false 142 } else if c == consts.LeftBrackets { 143 bracketsOpen = true 144 } 145 146 str := fmt.Sprintf("%c", c) 147 if !bracketsOpen && str == "-" { 148 index = i 149 break 150 } 151 } 152 153 if index == -1 { 154 start = desc 155 } else if index == 0 { 156 end = desc[1:] 157 } else if index == len(desc)-1 { 158 start = desc[:index] 159 } else { 160 start = desc[:index] 161 end = desc[index+1:] 162 } 163 164 if len(start) > 0 { 165 start = strings.TrimPrefix(start, string(consts.LeftBrackets)) 166 start = strings.TrimSuffix(start, string(consts.RightBrackets)) 167 } 168 if len(end) > 0 { 169 end = strings.TrimPrefix(end, string(consts.LeftBrackets)) 170 end = strings.TrimSuffix(end, string(consts.RightBrackets)) 171 } 172 173 return 174 } 175 176 func parseTsValue(str string, isStart bool) (value int64) { 177 str = strings.TrimSpace(str) 178 179 if strings.HasPrefix(str, "+") || strings.HasPrefix(str, "-") { 180 value = time.Now().Unix() 181 182 value = increment(value, str) 183 184 return 185 } 186 187 loc, _ := time.LoadLocation("Local") 188 tm, err := time.ParseInLocation("20060102 150405", str, loc) 189 if err != nil { 190 todayStart, todayEnd := getTodayTs() 191 if isStart { 192 value = todayStart 193 } else { 194 value = todayEnd 195 } 196 } else { 197 value = tm.Unix() 198 } 199 200 return 201 } 202 203 func getTodayTs() (start, end int64) { 204 now := time.Now() 205 206 start = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Unix() 207 end = time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location()).Unix() 208 209 return 210 } 211 212 // parse time expression to number and unit 213 // example: parseTsExpr("+3w") -> int(3) and "w" 214 func parseTsExpr(incrementStr string) (num int, unit string) { 215 num = 0 216 unit = "s" 217 incrementStr = strings.TrimSpace(incrementStr) 218 if len(incrementStr) <= 0 { 219 return 220 } 221 222 units := []string{"Y", "M", "D", "w", "h", "m", "s"} 223 224 unit = string(incrementStr[len(incrementStr)-1]) 225 found, _ := stringUtils.FindInArr(unit, units) 226 end := len(incrementStr) - 1 227 if !found { 228 unit = "s" 229 end = len(incrementStr) 230 } 231 232 numStr := incrementStr[:end] 233 num, _ = strconv.Atoi(numStr) 234 return 235 } 236 237 func incrementUnit(originalVal int64, incNum int, unit string) (ret int64) { 238 ret = originalVal 239 240 start := time.Unix(ret, 0) 241 if incNum == 0 { 242 return 243 } 244 switch unit { 245 case "Y": 246 start = start.AddDate(incNum, 0, 0) 247 case "M": 248 start = start.AddDate(0, incNum, 0) 249 case "D": 250 start = start.AddDate(0, 0, incNum) 251 case "w": 252 start = start.AddDate(0, 0, incNum*7) 253 case "h": 254 start = start.Add(time.Hour * time.Duration(incNum)) 255 case "m": 256 start = start.Add(time.Minute * time.Duration(incNum)) 257 case "s": 258 start = start.Add(time.Second * time.Duration(incNum)) 259 default: 260 } 261 ret = start.Unix() 262 return 263 } 264 265 func increment(originalVal int64, incrementStr string) (ret int64) { 266 ret = originalVal 267 268 num, unit := parseTsExpr(incrementStr) 269 if num == 0 { 270 return 271 } 272 273 ret = incrementUnit(originalVal, num, unit) 274 275 return 276 } 277 278 func GenerateTimeItems(start int64, end int64, step int, unit string, repeat int, repeatTag string) []interface{} { 279 arr := make([]interface{}, 0) 280 281 total := 0 282 if repeatTag == "" { 283 for i := 0; true; { 284 val := incrementUnit(start, i*step, unit) 285 //val := start + int64(i*step) 286 if (val >= end && step > 0) || (val <= end && step < 0) { 287 break 288 } 289 290 for round := 0; round < repeat; round++ { 291 arr = append(arr, val) 292 293 total++ 294 if total > consts.MaxNumb { 295 break 296 } 297 } 298 299 if total >= consts.MaxNumb { 300 break 301 } 302 i++ 303 } 304 } else if repeatTag == "!" { 305 for round := 0; round < repeat; round++ { 306 for i := 0; true; { 307 val := start + incrementUnit(start, i*step, unit) 308 //val := start + int64(i*step) 309 if (val >= end && step > 0) || (val <= end && step < 0) { 310 break 311 } 312 313 arr = append(arr, val) 314 315 if total >= consts.MaxNumb { 316 break 317 } 318 i++ 319 } 320 321 if total >= consts.MaxNumb { 322 break 323 } 324 } 325 } 326 return arr 327 }