Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions sdk/azcore/datetime/RFC1123.go
Original file line number Diff line number Diff line change
@@ -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
}
181 changes: 181 additions & 0 deletions sdk/azcore/datetime/RFC3339.go
Original file line number Diff line number Diff line change
@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove DateTime prefix.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also will need docs.


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
}
54 changes: 54 additions & 0 deletions sdk/azcore/datetime/date_type.go
Original file line number Diff line number Diff line change
@@ -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
Copy link
Member

@jhendrixMSFT jhendrixMSFT Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type PlainDate 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
}
56 changes: 56 additions & 0 deletions sdk/azcore/datetime/unix.go
Original file line number Diff line number Diff line change
@@ -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
}
Loading