time_codec.go raw

   1  // Copyright (C) MongoDB, Inc. 2017-present.
   2  //
   3  // Licensed under the Apache License, Version 2.0 (the "License"); you may
   4  // not use this file except in compliance with the License. You may obtain
   5  // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
   6  
   7  package bsoncodec
   8  
   9  import (
  10  	"fmt"
  11  	"reflect"
  12  	"time"
  13  
  14  	"go.mongodb.org/mongo-driver/bson/bsonoptions"
  15  	"go.mongodb.org/mongo-driver/bson/bsonrw"
  16  	"go.mongodb.org/mongo-driver/bson/bsontype"
  17  	"go.mongodb.org/mongo-driver/bson/primitive"
  18  )
  19  
  20  const (
  21  	timeFormatString = "2006-01-02T15:04:05.999Z07:00"
  22  )
  23  
  24  // TimeCodec is the Codec used for time.Time values.
  25  //
  26  // Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the
  27  // TimeCodec registered.
  28  type TimeCodec struct {
  29  	// UseLocalTimeZone specifies if we should decode into the local time zone. Defaults to false.
  30  	//
  31  	// Deprecated: Use bson.Decoder.UseLocalTimeZone instead.
  32  	UseLocalTimeZone bool
  33  }
  34  
  35  var (
  36  	defaultTimeCodec = NewTimeCodec()
  37  
  38  	// Assert that defaultTimeCodec satisfies the typeDecoder interface, which allows it to be used
  39  	// by collection type decoders (e.g. map, slice, etc) to set individual values in a collection.
  40  	_ typeDecoder = defaultTimeCodec
  41  )
  42  
  43  // NewTimeCodec returns a TimeCodec with options opts.
  44  //
  45  // Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the
  46  // TimeCodec registered.
  47  func NewTimeCodec(opts ...*bsonoptions.TimeCodecOptions) *TimeCodec {
  48  	timeOpt := bsonoptions.MergeTimeCodecOptions(opts...)
  49  
  50  	codec := TimeCodec{}
  51  	if timeOpt.UseLocalTimeZone != nil {
  52  		codec.UseLocalTimeZone = *timeOpt.UseLocalTimeZone
  53  	}
  54  	return &codec
  55  }
  56  
  57  func (tc *TimeCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
  58  	if t != tTime {
  59  		return emptyValue, ValueDecoderError{
  60  			Name:     "TimeDecodeValue",
  61  			Types:    []reflect.Type{tTime},
  62  			Received: reflect.Zero(t),
  63  		}
  64  	}
  65  
  66  	var timeVal time.Time
  67  	switch vrType := vr.Type(); vrType {
  68  	case bsontype.DateTime:
  69  		dt, err := vr.ReadDateTime()
  70  		if err != nil {
  71  			return emptyValue, err
  72  		}
  73  		timeVal = time.Unix(dt/1000, dt%1000*1000000)
  74  	case bsontype.String:
  75  		// assume strings are in the isoTimeFormat
  76  		timeStr, err := vr.ReadString()
  77  		if err != nil {
  78  			return emptyValue, err
  79  		}
  80  		timeVal, err = time.Parse(timeFormatString, timeStr)
  81  		if err != nil {
  82  			return emptyValue, err
  83  		}
  84  	case bsontype.Int64:
  85  		i64, err := vr.ReadInt64()
  86  		if err != nil {
  87  			return emptyValue, err
  88  		}
  89  		timeVal = time.Unix(i64/1000, i64%1000*1000000)
  90  	case bsontype.Timestamp:
  91  		t, _, err := vr.ReadTimestamp()
  92  		if err != nil {
  93  			return emptyValue, err
  94  		}
  95  		timeVal = time.Unix(int64(t), 0)
  96  	case bsontype.Null:
  97  		if err := vr.ReadNull(); err != nil {
  98  			return emptyValue, err
  99  		}
 100  	case bsontype.Undefined:
 101  		if err := vr.ReadUndefined(); err != nil {
 102  			return emptyValue, err
 103  		}
 104  	default:
 105  		return emptyValue, fmt.Errorf("cannot decode %v into a time.Time", vrType)
 106  	}
 107  
 108  	if !tc.UseLocalTimeZone && !dc.useLocalTimeZone {
 109  		timeVal = timeVal.UTC()
 110  	}
 111  	return reflect.ValueOf(timeVal), nil
 112  }
 113  
 114  // DecodeValue is the ValueDecoderFunc for time.Time.
 115  func (tc *TimeCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
 116  	if !val.CanSet() || val.Type() != tTime {
 117  		return ValueDecoderError{Name: "TimeDecodeValue", Types: []reflect.Type{tTime}, Received: val}
 118  	}
 119  
 120  	elem, err := tc.decodeType(dc, vr, tTime)
 121  	if err != nil {
 122  		return err
 123  	}
 124  
 125  	val.Set(elem)
 126  	return nil
 127  }
 128  
 129  // EncodeValue is the ValueEncoderFunc for time.TIme.
 130  func (tc *TimeCodec) EncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
 131  	if !val.IsValid() || val.Type() != tTime {
 132  		return ValueEncoderError{Name: "TimeEncodeValue", Types: []reflect.Type{tTime}, Received: val}
 133  	}
 134  	tt := val.Interface().(time.Time)
 135  	dt := primitive.NewDateTimeFromTime(tt)
 136  	return vw.WriteDateTime(int64(dt))
 137  }
 138