github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/util/datetime/date_time.go (about)

     1  // Copyright 2019 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // This file incorporates work covered by the following copyright and
    16  // permission notice:
    17  //
    18  // Copyright 2017 Attic Labs, Inc. All rights reserved.
    19  // Licensed under the Apache License, version 2.0:
    20  // http://www.apache.org/licenses/LICENSE-2.0
    21  
    22  // Package datetime implements marshalling of Go DateTime values into Noms structs
    23  // with type DateTimeType.
    24  package datetime
    25  
    26  import (
    27  	"context"
    28  	"math"
    29  	"time"
    30  
    31  	"github.com/dolthub/dolt/go/store/marshal"
    32  	"github.com/dolthub/dolt/go/store/types"
    33  )
    34  
    35  const (
    36  	datetypename    = "DateTime"
    37  	hrsEncodingName = "noms-datetime"
    38  )
    39  
    40  // DateTime implements marshaling of time.Time to and from Noms.
    41  type DateTime struct {
    42  	time.Time
    43  }
    44  
    45  // DateTimeType is the Noms type used to represent date time objects in Noms.
    46  // The field secSinceEpoch may contain fractions in cases where seconds are
    47  // not sufficient.
    48  var DateTimeType, _ = types.MakeStructTypeFromFields(datetypename, types.FieldMap{
    49  	"secSinceEpoch": types.PrimitiveTypeMap[types.FloatKind],
    50  })
    51  
    52  var dateTimeTemplate = types.MakeStructTemplate(datetypename, []string{"secSinceEpoch"})
    53  
    54  // Epoch is the unix Epoch. This time is very consistent,
    55  // which makes it useful for testing or checking for uninitialized values
    56  var Epoch = DateTime{time.Unix(0, 0)}
    57  
    58  func init() {
    59  	RegisterHRSCommenter(time.Local)
    60  }
    61  
    62  // Now is an alias for a DateTime initialized with time.Now()
    63  func Now() DateTime {
    64  	return DateTime{time.Now()}
    65  }
    66  
    67  // MarshalNoms makes DateTime implement marshal.Marshaler and it makes
    68  // DateTime marshal into a Noms struct with type DateTimeType.
    69  func (dt DateTime) MarshalNoms(vrw types.ValueReadWriter) (types.Value, error) {
    70  	return dateTimeTemplate.NewStruct(vrw.Format(), []types.Value{types.Float(float64(dt.Unix()) + float64(dt.Nanosecond())*1e-9)})
    71  }
    72  
    73  // MarshalNomsType makes DateTime implement marshal.TypeMarshaler and it
    74  // allows marshal.MarshalType to work with DateTime.
    75  func (dt DateTime) MarshalNomsType() (*types.Type, error) {
    76  	return DateTimeType, nil
    77  }
    78  
    79  // UnmarshalNoms makes DateTime implement marshal.Unmarshaler and it allows
    80  // Noms struct with type DateTimeType able to be unmarshaled onto a DateTime
    81  // Go struct
    82  func (dt *DateTime) UnmarshalNoms(ctx context.Context, nbf *types.NomsBinFormat, v types.Value) error {
    83  	strct := struct {
    84  		SecSinceEpoch float64
    85  	}{}
    86  	err := marshal.Unmarshal(ctx, nbf, v, &strct)
    87  	if err != nil {
    88  		return err
    89  	}
    90  
    91  	s, frac := math.Modf(strct.SecSinceEpoch)
    92  	*dt = DateTime{time.Unix(int64(s), int64(frac*1e9))}
    93  	return nil
    94  }
    95  
    96  type DateTimeCommenter struct {
    97  	tz *time.Location
    98  }
    99  
   100  func (c DateTimeCommenter) Comment(ctx context.Context, v types.Value) string {
   101  	if s, ok := v.(types.Struct); ok {
   102  		if secsV, ok, err := s.MaybeGet("secSinceEpoch"); err != nil {
   103  			panic(err)
   104  		} else if ok {
   105  			if secsF, ok := secsV.(types.Float); ok {
   106  				s, frac := math.Modf(float64(secsF))
   107  				dt := time.Unix(int64(s), int64(frac*1e9))
   108  				return dt.In(c.tz).Format(time.RFC3339)
   109  			}
   110  		}
   111  	}
   112  	return ""
   113  }
   114  
   115  func RegisterHRSCommenter(tz *time.Location) {
   116  	hrsCommenter := DateTimeCommenter{tz: tz}
   117  	types.RegisterHRSCommenter(datetypename, hrsEncodingName, hrsCommenter)
   118  }