Skip to content

Commit

Permalink
Merge pull request #9 from MWM-io/rba/reimplement_time
Browse files Browse the repository at this point in the history
feat: Reimplement time.Time to display a timestamp in JSON response a…
  • Loading branch information
rach-ba committed Dec 12, 2023
2 parents bb781b6 + 6c0b5f1 commit 8f76085
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 2 deletions.
3 changes: 1 addition & 2 deletions gcloud/helpers/spanner/iter.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ func IterToStructs[T any](iter *spanner.RowIterator) ([]T, error) {
// You can use it to simplify your code when you know there is only one row in the iterator.
func IterToStruct[T any](iter *spanner.RowIterator) (result T, exist bool, err error) {
results, errIter := IterToStructs[T](iter)

if err != nil {
if errIter != nil {
return result, false, errIter
}

Expand Down
94 changes: 94 additions & 0 deletions gcloud/helpers/spanner/time.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package spanner

import (
"strconv"
"time"

"cloud.google.com/go/spanner"
)

// Time overrides the spanner.Time to produce a unix milli timestamp when marshalled to json
type Time time.Time

// MarshalJSON implements the json.Marshaler interface to produce a unix milli timestamp
func (nt Time) MarshalJSON() ([]byte, error) {
casted := time.Time(nt)

return []byte(strconv.FormatInt(casted.UnixMilli(), 10)), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface to handle a unix milli timestamp and convert it to a Time
func (nt *Time) UnmarshalJSON(b []byte) error {
i, err := strconv.ParseInt(string(b), 10, 64)
if err == nil {
*nt = Time(time.UnixMilli(i))
return nil
}

// if it's not a unix timestamp try decoding as time this is useful for json object created by spanner TO_JSON()
if b[0] == '"' {
b = b[1 : len(b)-1]
}

date, errT := time.Parse(time.RFC3339Nano, string(b))
if errT != nil {
return errT
}

*nt = Time(date)
return nil
}

// CommitTimestamp returns a spanner.CommitTimestamp cast to a models.Time
func CommitTimestamp() Time {
return Time(spanner.CommitTimestamp)
}

// NullTime overrides the spanner.NullTime to produce a unix milli timestamp when marshalled to json
type NullTime spanner.NullTime

// MarshalJSON implements the json.Marshaler interface to produce a unix milli timestamp
func (nt NullTime) MarshalJSON() ([]byte, error) {
if nt.Valid {
return []byte(strconv.FormatInt(nt.Time.UnixMilli(), 10)), nil
}

return []byte("0"), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface to handle a unix milli timestamp and convert it to a NullTime
func (nt *NullTime) UnmarshalJSON(b []byte) error {
if string(b) == "0" {
nt.Valid = false
return nil
}

i, err := strconv.ParseInt(string(b), 10, 64)
if err == nil {
*nt = NullTime(spanner.NullTime{Valid: true, Time: time.UnixMilli(i)})
return nil
}

// if it's not a unix timestamp try decoding as time this is useful for json object created by spanner TO_JSON()
if b[0] == '"' {
b = b[1 : len(b)-1]
}
date, errT := time.Parse(time.RFC3339Nano, string(b))
if errT != nil {
return errT
}

*nt = NullTime{
Time: date,
Valid: true,
}
return nil
}

// NullCommitTimestamp returns a spanner.CommitTimestamp casted to a models.NullTime
func NullCommitTimestamp() NullTime {
return NullTime{
Time: spanner.CommitTimestamp,
Valid: true,
}
}

0 comments on commit 8f76085

Please sign in to comment.