diff --git a/sdk/azcore/datetime/RFC1123.go b/sdk/azcore/datetime/RFC1123.go new file mode 100644 index 000000000000..543663cc409f --- /dev/null +++ b/sdk/azcore/datetime/RFC1123.go @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package datetime + +import ( + "encoding/json" + "fmt" + "reflect" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) + +const ( + DateTimeRFC1123JSON = `"` + time.RFC1123 + `"` +) + +type DateTimeRFC1123 time.Time + +func (t DateTimeRFC1123) MarshalJSON() ([]byte, error) { + b := []byte(time.Time(t).Format(DateTimeRFC1123JSON)) + return b, nil +} + +func (t DateTimeRFC1123) MarshalText() ([]byte, error) { + b := []byte(time.Time(t).Format(time.RFC1123)) + return b, nil +} + +func (t *DateTimeRFC1123) UnmarshalJSON(data []byte) error { + p, err := time.Parse(DateTimeRFC1123JSON, strings.ToUpper(string(data))) + *t = DateTimeRFC1123(p) + return err +} + +func (t *DateTimeRFC1123) UnmarshalText(data []byte) error { + if len(data) == 0 { + return nil + } + p, err := time.Parse(time.RFC1123, string(data)) + *t = DateTimeRFC1123(p) + return err +} + +func (t DateTimeRFC1123) String() string { + return time.Time(t).Format(time.RFC1123) +} + +func PopulateDateTimeRFC1123(m map[string]any, k string, t *time.Time) { + if t == nil { + return + } else if azcore.IsNullValue(t) { + m[k] = nil + return + } else if reflect.ValueOf(t).IsNil() { + return + } + m[k] = (*DateTimeRFC1123)(t) +} + +func UnpopulateDateTimeRFC1123(data json.RawMessage, fn string, t **time.Time) error { + if data == nil || string(data) == "null" { + return nil + } + var aux DateTimeRFC1123 + if err := json.Unmarshal(data, &aux); err != nil { + return fmt.Errorf("struct field %s: %v", fn, err) + } + *t = (*time.Time)(&aux) + return nil +} diff --git a/sdk/azcore/datetime/RFC3339.go b/sdk/azcore/datetime/RFC3339.go new file mode 100644 index 000000000000..b8cf08462528 --- /dev/null +++ b/sdk/azcore/datetime/RFC3339.go @@ -0,0 +1,181 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package datetime + +import ( + "encoding/json" + "fmt" + "reflect" + "regexp" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) + +// Azure reports time in UTC but it doesn't include the 'Z' time zone suffix in some cases. +var tzOffsetRegex = regexp.MustCompile(`(?:Z|z|\\+|-)(?:\\d+:\\d+)*"*$`) + +const ( + utcDateTime = "2006-01-02T15:04:05.999999999" + utcDateTimeJSON = `"` + utcDateTime + `"` + utcDateTimeNoT = "2006-01-02 15:04:05.999999999" + utcDateTimeJSONNoT = `"` + utcDateTimeNoT + `"` + dateTimeNoT = `2006-01-02 15:04:05.999999999Z07:00` + dateTimeJSON = `"` + time.RFC3339Nano + `"` + dateTimeJSONNoT = `"` + dateTimeNoT + `"` +) + +type DateTimeRFC3339 time.Time + +func (t DateTimeRFC3339) MarshalJSON() ([]byte, error) { + tt := time.Time(t) + return tt.MarshalJSON() +} + +func (t DateTimeRFC3339) MarshalText() ([]byte, error) { + tt := time.Time(t) + return tt.MarshalText() +} + +func (t *DateTimeRFC3339) UnmarshalJSON(data []byte) error { + tzOffset := tzOffsetRegex.Match(data) + hasT := strings.Contains(string(data), "T") || strings.Contains(string(data), "t") + var layout string + if tzOffset && hasT { + layout = dateTimeJSON + } else if tzOffset { + layout = dateTimeJSONNoT + } else if hasT { + layout = utcDateTimeJSON + } else { + layout = utcDateTimeJSONNoT + } + return t.Parse(layout, string(data)) +} + +func (t *DateTimeRFC3339) UnmarshalText(data []byte) error { + if len(data) == 0 { + return nil + } + tzOffset := tzOffsetRegex.Match(data) + hasT := strings.Contains(string(data), "T") || strings.Contains(string(data), "t") + var layout string + if tzOffset && hasT { + layout = time.RFC3339Nano + } else if tzOffset { + layout = dateTimeNoT + } else if hasT { + layout = utcDateTime + } else { + layout = utcDateTimeNoT + } + return t.Parse(layout, string(data)) +} + +func (t *DateTimeRFC3339) Parse(layout, value string) error { + p, err := time.Parse(layout, strings.ToUpper(value)) + *t = DateTimeRFC3339(p) + return err +} + +func (t DateTimeRFC3339) String() string { + return time.Time(t).Format(time.RFC3339Nano) +} + +func PopulateDateTimeRFC3339(m map[string]any, k string, t *time.Time) { + if t == nil { + return + } else if azcore.IsNullValue(t) { + m[k] = nil + return + } else if reflect.ValueOf(t).IsNil() { + return + } + m[k] = (*DateTimeRFC3339)(t) +} + +func UnpopulateDateTimeRFC3339(data json.RawMessage, fn string, t **time.Time) error { + if data == nil || string(data) == "null" { + return nil + } + var aux DateTimeRFC3339 + if err := json.Unmarshal(data, &aux); err != nil { + return fmt.Errorf("struct field %s: %v", fn, err) + } + *t = (*time.Time)(&aux) + return nil +} + +const ( + utcTimeJSON = "15:04:05.999999999" + utcTime = "15:04:05.999999999" + timeFormat = "15:04:05.999999999Z07:00" +) + +type TimeRFC3339 time.Time + +func (t TimeRFC3339) MarshalJSON() ([]byte, error) { + s, _ := t.MarshalText() + return []byte(fmt.Sprintf(`"%s"`, s)), nil +} + +func (t TimeRFC3339) MarshalText() ([]byte, error) { + tt := time.Time(t) + return []byte(tt.Format(timeFormat)), nil +} + +func (t *TimeRFC3339) UnmarshalJSON(data []byte) error { + layout := utcTimeJSON + if tzOffsetRegex.Match(data) { + layout = timeFormat + } + return t.Parse(layout, string(data)) +} + +func (t *TimeRFC3339) UnmarshalText(data []byte) error { + if len(data) == 0 { + return nil + } + layout := utcTime + if tzOffsetRegex.Match(data) { + layout = timeFormat + } + return t.Parse(layout, string(data)) +} + +func (t *TimeRFC3339) Parse(layout, value string) error { + p, err := time.Parse(layout, strings.ToUpper(value)) + *t = TimeRFC3339(p) + return err +} + +func (t TimeRFC3339) String() string { + tt := time.Time(t) + return tt.Format(timeFormat) +} + +func PopulateTimeRFC3339(m map[string]any, k string, t *time.Time) { + if t == nil { + return + } else if azcore.IsNullValue(t) { + m[k] = nil + return + } else if reflect.ValueOf(t).IsNil() { + return + } + m[k] = (*TimeRFC3339)(t) +} + +func UnpopulateTimeRFC3339(data json.RawMessage, fn string, t **time.Time) error { + if data == nil || string(data) == "null" { + return nil + } + var aux TimeRFC3339 + if err := json.Unmarshal(data, &aux); err != nil { + return fmt.Errorf("struct field %s: %v", fn, err) + } + *t = (*time.Time)(&aux) + return nil +} diff --git a/sdk/azcore/datetime/date_type.go b/sdk/azcore/datetime/date_type.go new file mode 100644 index 000000000000..2e04dc1243f3 --- /dev/null +++ b/sdk/azcore/datetime/date_type.go @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package datetime + +import ( + "encoding/json" + "fmt" + "reflect" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) + +const ( + fullDateJSON = `2006-01-02` + jsonFormat = `%04d-%02d-%02d` +) + +type DateType time.Time + +func (t DateType) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(jsonFormat, time.Time(t).Year(), time.Time(t).Month(), time.Time(t).Day())), nil +} + +func (d *DateType) UnmarshalJSON(data []byte) (err error) { + t, err := time.Parse(fullDateJSON, string(data)) + *d = (DateType)(t) + return err +} + +func PopulateDateType(m map[string]any, k string, t *time.Time) { + if t == nil { + return + } else if azcore.IsNullValue(t) { + m[k] = nil + return + } else if reflect.ValueOf(t).IsNil() { + return + } + m[k] = (*DateType)(t) +} + +func UnpopulateDateType(data json.RawMessage, fn string, t **time.Time) error { + if data == nil || string(data) == "null" { + return nil + } + var aux DateType + if err := json.Unmarshal(data, &aux); err != nil { + return fmt.Errorf("struct field %s: %v", fn, err) + } + *t = (*time.Time)(&aux) + return nil +} diff --git a/sdk/azcore/datetime/unix.go b/sdk/azcore/datetime/unix.go new file mode 100644 index 000000000000..0129adcb379c --- /dev/null +++ b/sdk/azcore/datetime/unix.go @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package datetime + +import ( + "encoding/json" + "fmt" + "reflect" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) + +type TimeUnix time.Time + +func (t TimeUnix) MarshalJSON() ([]byte, error) { + return json.Marshal(time.Time(t).Unix()) +} + +func (t *TimeUnix) UnmarshalJSON(data []byte) error { + var seconds int64 + if err := json.Unmarshal(data, &seconds); err != nil { + return err + } + *t = TimeUnix(time.Unix(seconds, 0)) + return nil +} + +func (t TimeUnix) String() string { + return fmt.Sprintf("%d", time.Time(t).Unix()) +} + +func PopulateTimeUnix(m map[string]any, k string, t *time.Time) { + if t == nil { + return + } else if azcore.IsNullValue(t) { + m[k] = nil + return + } else if reflect.ValueOf(t).IsNil() { + return + } + m[k] = (*TimeUnix)(t) +} + +func UnpopulateTimeUnix(data json.RawMessage, fn string, t **time.Time) error { + if data == nil || string(data) == "null" { + return nil + } + var aux TimeUnix + if err := json.Unmarshal(data, &aux); err != nil { + return fmt.Errorf("struct field %s: %v", fn, err) + } + *t = (*time.Time)(&aux) + return nil +}