Home | History | Annotate | Download | only in ptypes
      1 // Go support for Protocol Buffers - Google's data interchange format
      2 //
      3 // Copyright 2016 The Go Authors.  All rights reserved.
      4 // https://github.com/golang/protobuf
      5 //
      6 // Redistribution and use in source and binary forms, with or without
      7 // modification, are permitted provided that the following conditions are
      8 // met:
      9 //
     10 //     * Redistributions of source code must retain the above copyright
     11 // notice, this list of conditions and the following disclaimer.
     12 //     * Redistributions in binary form must reproduce the above
     13 // copyright notice, this list of conditions and the following disclaimer
     14 // in the documentation and/or other materials provided with the
     15 // distribution.
     16 //     * Neither the name of Google Inc. nor the names of its
     17 // contributors may be used to endorse or promote products derived from
     18 // this software without specific prior written permission.
     19 //
     20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31 
     32 package ptypes
     33 
     34 // This file implements operations on google.protobuf.Timestamp.
     35 
     36 import (
     37 	"errors"
     38 	"fmt"
     39 	"time"
     40 
     41 	tspb "github.com/golang/protobuf/ptypes/timestamp"
     42 )
     43 
     44 const (
     45 	// Seconds field of the earliest valid Timestamp.
     46 	// This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
     47 	minValidSeconds = -62135596800
     48 	// Seconds field just after the latest valid Timestamp.
     49 	// This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
     50 	maxValidSeconds = 253402300800
     51 )
     52 
     53 // validateTimestamp determines whether a Timestamp is valid.
     54 // A valid timestamp represents a time in the range
     55 // [0001-01-01, 10000-01-01) and has a Nanos field
     56 // in the range [0, 1e9).
     57 //
     58 // If the Timestamp is valid, validateTimestamp returns nil.
     59 // Otherwise, it returns an error that describes
     60 // the problem.
     61 //
     62 // Every valid Timestamp can be represented by a time.Time, but the converse is not true.
     63 func validateTimestamp(ts *tspb.Timestamp) error {
     64 	if ts == nil {
     65 		return errors.New("timestamp: nil Timestamp")
     66 	}
     67 	if ts.Seconds < minValidSeconds {
     68 		return fmt.Errorf("timestamp: %v before 0001-01-01", ts)
     69 	}
     70 	if ts.Seconds >= maxValidSeconds {
     71 		return fmt.Errorf("timestamp: %v after 10000-01-01", ts)
     72 	}
     73 	if ts.Nanos < 0 || ts.Nanos >= 1e9 {
     74 		return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts)
     75 	}
     76 	return nil
     77 }
     78 
     79 // Timestamp converts a google.protobuf.Timestamp proto to a time.Time.
     80 // It returns an error if the argument is invalid.
     81 //
     82 // Unlike most Go functions, if Timestamp returns an error, the first return value
     83 // is not the zero time.Time. Instead, it is the value obtained from the
     84 // time.Unix function when passed the contents of the Timestamp, in the UTC
     85 // locale. This may or may not be a meaningful time; many invalid Timestamps
     86 // do map to valid time.Times.
     87 //
     88 // A nil Timestamp returns an error. The first return value in that case is
     89 // undefined.
     90 func Timestamp(ts *tspb.Timestamp) (time.Time, error) {
     91 	// Don't return the zero value on error, because corresponds to a valid
     92 	// timestamp. Instead return whatever time.Unix gives us.
     93 	var t time.Time
     94 	if ts == nil {
     95 		t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp
     96 	} else {
     97 		t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC()
     98 	}
     99 	return t, validateTimestamp(ts)
    100 }
    101 
    102 // TimestampNow returns a google.protobuf.Timestamp for the current time.
    103 func TimestampNow() *tspb.Timestamp {
    104 	ts, err := TimestampProto(time.Now())
    105 	if err != nil {
    106 		panic("ptypes: time.Now() out of Timestamp range")
    107 	}
    108 	return ts
    109 }
    110 
    111 // TimestampProto converts the time.Time to a google.protobuf.Timestamp proto.
    112 // It returns an error if the resulting Timestamp is invalid.
    113 func TimestampProto(t time.Time) (*tspb.Timestamp, error) {
    114 	seconds := t.Unix()
    115 	nanos := int32(t.Sub(time.Unix(seconds, 0)))
    116 	ts := &tspb.Timestamp{
    117 		Seconds: seconds,
    118 		Nanos:   nanos,
    119 	}
    120 	if err := validateTimestamp(ts); err != nil {
    121 		return nil, err
    122 	}
    123 	return ts, nil
    124 }
    125 
    126 // TimestampString returns the RFC 3339 string for valid Timestamps. For invalid
    127 // Timestamps, it returns an error message in parentheses.
    128 func TimestampString(ts *tspb.Timestamp) string {
    129 	t, err := Timestamp(ts)
    130 	if err != nil {
    131 		return fmt.Sprintf("(%v)", err)
    132 	}
    133 	return t.Format(time.RFC3339Nano)
    134 }
    135