- Marked the Cache Implementation as complete in TODO.md, confirming all tasks are finished with comprehensive integration tests. - Updated cache.go to provide a thread-safe in-memory cache for Robot instances, improving performance and reliability. - Enhanced the Load method to include pagination and configurable model name, ensuring efficient data handling. - Added detailed comments and structured code for better readability and maintainability across the cache implementation. - Improved validation and error handling in various utility functions to ensure robustness in data processing.
114 lines
2.8 KiB
Go
114 lines
2.8 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// ParseTime parses a time string in HH:MM format
|
|
func ParseTime(timeStr string) (hour, minute int, err error) {
|
|
parts := strings.Split(timeStr, ":")
|
|
if len(parts) != 2 {
|
|
return 0, 0, fmt.Errorf("invalid time format: %s (expected HH:MM)", timeStr)
|
|
}
|
|
|
|
hour, err = strconv.Atoi(parts[0])
|
|
if err != nil || hour < 0 || hour > 23 {
|
|
return 0, 0, fmt.Errorf("invalid hour: %s", parts[0])
|
|
}
|
|
|
|
minute, err = strconv.Atoi(parts[1])
|
|
if err != nil || minute < 0 || minute > 59 {
|
|
return 0, 0, fmt.Errorf("invalid minute: %s", parts[1])
|
|
}
|
|
|
|
return hour, minute, nil
|
|
}
|
|
|
|
// FormatTime formats hour and minute into HH:MM format
|
|
func FormatTime(hour, minute int) string {
|
|
return fmt.Sprintf("%02d:%02d", hour, minute)
|
|
}
|
|
|
|
// LoadLocation loads a timezone location, returns Local if empty or invalid
|
|
func LoadLocation(tz string) *time.Location {
|
|
if tz == "" {
|
|
return time.Local
|
|
}
|
|
loc, err := time.LoadLocation(tz)
|
|
if err != nil {
|
|
return time.Local
|
|
}
|
|
return loc
|
|
}
|
|
|
|
// ParseDuration parses a duration string with fallback default
|
|
func ParseDuration(durStr string, defaultDur time.Duration) time.Duration {
|
|
if durStr == "" {
|
|
return defaultDur
|
|
}
|
|
d, err := time.ParseDuration(durStr)
|
|
if err != nil {
|
|
return defaultDur
|
|
}
|
|
return d
|
|
}
|
|
|
|
// IsTimeMatch checks if current time matches the specified time (HH:MM)
|
|
func IsTimeMatch(now time.Time, timeStr string, loc *time.Location) bool {
|
|
hour, minute, err := ParseTime(timeStr)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
nowInLoc := now.In(loc)
|
|
return nowInLoc.Hour() == hour && nowInLoc.Minute() == minute
|
|
}
|
|
|
|
// IsDayMatch checks if current day matches the specified day
|
|
// days can be: "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", or "*" for any day
|
|
func IsDayMatch(now time.Time, days []string) bool {
|
|
if len(days) == 0 {
|
|
return true
|
|
}
|
|
|
|
dayName := now.Weekday().String()[:3] // "Monday" -> "Mon"
|
|
|
|
for _, day := range days {
|
|
if day == "*" || day == dayName {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// NextScheduledTime calculates the next time a scheduled time will occur
|
|
func NextScheduledTime(now time.Time, timeStr string, days []string, loc *time.Location) (time.Time, error) {
|
|
hour, minute, err := ParseTime(timeStr)
|
|
if err != nil {
|
|
return time.Time{}, err
|
|
}
|
|
|
|
nowInLoc := now.In(loc)
|
|
|
|
// Start from today at the specified time
|
|
next := time.Date(nowInLoc.Year(), nowInLoc.Month(), nowInLoc.Day(), hour, minute, 0, 0, loc)
|
|
|
|
// If the time has passed today, start from tomorrow
|
|
if next.Before(nowInLoc) || next.Equal(nowInLoc) {
|
|
next = next.Add(24 * time.Hour)
|
|
}
|
|
|
|
// Find the next matching day (within 7 days)
|
|
for i := 0; i < 7; i++ {
|
|
if IsDayMatch(next, days) {
|
|
return next, nil
|
|
}
|
|
next = next.Add(24 * time.Hour)
|
|
}
|
|
|
|
// If no matching day found (should not happen with valid days), return the calculated time
|
|
return next, nil
|
|
}
|