diff --git a/CHANGELOG.md b/CHANGELOG.md index 3728c9d3..cd9af8f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,12 @@ ## v7 WIP - WrapProcess is replaced with more convenient AddHook that has access to context.Context. -- WithContext no longer creates shallow copy. +- WithContext now can not be used to create a shallow copy of the client. - New methods ProcessContext, DoContext, and ExecContext. - Client respects Context.Deadline when setting net.Conn deadline. -- Client listens on Context.Done while waiting for a connection from the pool. +- Client listens on Context.Done while waiting for a connection from the pool and returns an error when context context is cancelled. - Add PubSub.ChannelWithSubscriptions that sends `*Subscription` in addition to `*Message` to allow detecting reconnections. +- `time.Time` is now marshalled in RFC3339 format. `rdb.Get("foo").Time()` helper is added to parse time. ## v6.15 diff --git a/command.go b/command.go index c3025979..7b7c353e 100644 --- a/command.go +++ b/command.go @@ -659,6 +659,13 @@ func (cmd *StringCmd) Float64() (float64, error) { return strconv.ParseFloat(cmd.Val(), 64) } +func (cmd *StringCmd) Time() (time.Time, error) { + if cmd.err != nil { + return time.Time{}, cmd.err + } + return time.Parse(time.RFC3339, cmd.Val()) +} + func (cmd *StringCmd) Scan(val interface{}) error { if cmd.err != nil { return cmd.err diff --git a/command_test.go b/command_test.go index 020f8aac..54e99451 100644 --- a/command_test.go +++ b/command_test.go @@ -1,6 +1,8 @@ package redis_test import ( + "time" + "github.com/go-redis/redis" . "github.com/onsi/ginkgo" @@ -67,4 +69,19 @@ var _ = Describe("Cmd", func() { Expect(err).NotTo(HaveOccurred()) Expect(val).To(Equal(f)) }) + + It("supports time.Time", func() { + tm := time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC) + + err := client.Set("time_key", tm, 0).Err() + Expect(err).NotTo(HaveOccurred()) + + s, err := client.Get("time_key").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(s).To(Equal("2019-01-01T00:00:00Z")) + + tm2, err := client.Get("time_key").Time() + Expect(err).NotTo(HaveOccurred()) + Expect(tm2).To(BeTemporally("==", tm)) + }) }) diff --git a/internal/proto/write_buffer_test.go b/internal/proto/write_buffer_test.go index 29aa4692..2de532ee 100644 --- a/internal/proto/write_buffer_test.go +++ b/internal/proto/write_buffer_test.go @@ -2,6 +2,7 @@ package proto_test import ( "bytes" + "encoding" "io/ioutil" "testing" "time" @@ -12,6 +13,14 @@ import ( . "github.com/onsi/gomega" ) +type MyType struct{} + +var _ encoding.BinaryMarshaler = (*MyType)(nil) + +func (t *MyType) MarshalBinary() ([]byte, error) { + return []byte("hello"), nil +} + var _ = Describe("WriteBuffer", func() { var buf *bytes.Buffer var wr *proto.Writer @@ -45,16 +54,25 @@ var _ = Describe("WriteBuffer", func() { "\r\n"))) }) - It("should append marshalable args", func() { - err := wr.WriteArgs([]interface{}{time.Unix(1414141414, 0)}) + It("should append time", func() { + err := wr.WriteArgs([]interface{}{time.Unix(1414141414, 0).UTC()}) Expect(err).NotTo(HaveOccurred()) err = wr.Flush() Expect(err).NotTo(HaveOccurred()) - Expect(buf.Len()).To(Equal(26)) + Expect(buf.Len()).To(Equal(31)) }) + It("should append marshalable args", func() { + err := wr.WriteArgs([]interface{}{&MyType{}}) + Expect(err).NotTo(HaveOccurred()) + + err = wr.Flush() + Expect(err).NotTo(HaveOccurred()) + + Expect(buf.Len()).To(Equal(15)) + }) }) func BenchmarkWriteBuffer_Append(b *testing.B) { diff --git a/internal/proto/writer.go b/internal/proto/writer.go index d106ce0e..cded3470 100644 --- a/internal/proto/writer.go +++ b/internal/proto/writer.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "strconv" + "time" "github.com/go-redis/redis/internal/util" ) @@ -92,6 +93,8 @@ func (w *Writer) writeArg(v interface{}) error { } else { return w.int(0) } + case time.Time: + return w.string(v.Format(time.RFC3339)) case encoding.BinaryMarshaler: b, err := v.MarshalBinary() if err != nil {