diff --git a/date_utils/date_utils.go b/date_utils/date_utils.go index d60b7c8255b1bc500c9585f41a32a93e0259839e..b0314232c3667a9d29e3f055dfc16f1ca95a4f89 100644 --- a/date_utils/date_utils.go +++ b/date_utils/date_utils.go @@ -2,6 +2,7 @@ package date_utils import ( "github.com/araddon/dateparse" + "reflect" "strconv" "time" ) @@ -165,3 +166,108 @@ func ParseTimeString(timeString string) (time.Time, error) { return parsedTime, err } + +func FormatTimestampsWithTimeZoneOnStructRecursively(object any, location *time.Location) error { + var objectValue reflect.Value + objectValue = reflect.ValueOf(object) + for objectValue.Kind() == reflect.Pointer || + objectValue.Kind() == reflect.Interface { + objectValue = objectValue.Elem() + } + + err := formatTimestampsWithTimeZoneOnStruct(objectValue, location) + return err +} + +func formatTimestampsWithTimeZoneOnStruct(structValue reflect.Value, location *time.Location) error { + numF := structValue.NumField() + for i := 0; i < numF; i++ { + fieldValue := structValue.Field(i) + fieldType := fieldValue.Type() + fieldKind := fieldValue.Type().Kind() + + timeType := reflect.TypeOf(time.Time{}) + if fieldType == timeType && !fieldValue.IsZero() { + fieldValue.Set(reflect.ValueOf(fieldValue.Interface().(time.Time).In(location))) + continue + } + + timePointerType := reflect.TypeOf(&time.Time{}) + if fieldType == timePointerType && !fieldValue.IsNil() { + timeInLocation := fieldValue.Interface().(*time.Time).In(location) + timeInLocationPointer := reflect.ValueOf(timeInLocation) + + fieldPointer := fieldValue.Elem() + fieldPointer.Set(timeInLocationPointer) + continue + } + + if fieldKind == reflect.Slice { + // Loop over the slice items + err := formatTimestampsWithTimeZoneInSlice(fieldValue, location) + if err != nil { + return err + } + continue + } else if fieldKind == reflect.Struct { + err := formatTimestampsWithTimeZoneOnStruct(fieldValue, location) + if err != nil { + return err + } + continue + } else if fieldKind == reflect.Interface || fieldKind == reflect.Pointer { + var objectValue reflect.Value + objectValue = fieldValue.Elem() + if objectValue.Kind() == reflect.Slice { + err := formatTimestampsWithTimeZoneInSlice(objectValue, location) + if err != nil { + return err + } + } else if objectValue.Kind() == reflect.Struct { + err := formatTimestampsWithTimeZoneOnStruct(objectValue, location) + if err != nil { + return err + } + } + continue + } + + } + + return nil +} + +func formatTimestampsWithTimeZoneInSlice(fieldValue reflect.Value, location *time.Location) error { + for j := 0; j < fieldValue.Len(); j++ { + sliceItem := fieldValue.Index(j) + + if sliceItem.IsValid() { + var sliceItemValue reflect.Value + if sliceItem.Kind() == reflect.Ptr && sliceItem.IsValid() { + // Dereference the pointer + sliceItemValue = sliceItem.Elem() + } else { + sliceItemValue = sliceItem + } + + if sliceItemValue.IsValid() { + sliceItemKind := sliceItemValue.Kind() + sliceItemType := sliceItemValue.Type() + + // Check whether we have a slice of time.Time, and set the location if we do. + if sliceItemType == reflect.TypeOf(time.Time{}) { + sliceItemValue.Set(reflect.ValueOf(sliceItemValue.Interface().(time.Time).In(location))) + continue + } + + if sliceItemKind == reflect.Struct { + err := formatTimestampsWithTimeZoneOnStruct(sliceItemValue, location) + if err != nil { + return err + } + } + } + } + } + return nil +}