github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/timeutil/time.go (about)

     1  // Copyright 2016 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package timeutil
    12  
    13  import (
    14  	"strings"
    15  	"time"
    16  	"unsafe"
    17  )
    18  
    19  // LibPQTimePrefix is the prefix lib/pq prints time-type datatypes with.
    20  const LibPQTimePrefix = "0000-01-01"
    21  
    22  // Now returns the current UTC time.
    23  //
    24  // We've decided in times immemorial that always returning UTC is a good policy
    25  // across the cluster so that all the timestamps print uniformly across
    26  // different nodes, and also because we were afraid that timestamps leak into
    27  // SQL Datums, and there the timestamp matters. Years later, it's not clear
    28  // whether this was a good decision since it's forcing the nasty implementation
    29  // below.
    30  func Now() time.Time {
    31  	t := time.Now()
    32  	// HACK: instead of doing t = t.UTC(), we reach inside the
    33  	// struct and set the location manually. UTC() strips the monotonic clock reading
    34  	// from t, for no good reason: https://groups.google.com/g/golang-nuts/c/dyPTdi6oem8
    35  	// Stripping the monotonic part has bad consequences:
    36  	// 1. We lose the benefits of the monotonic clock reading.
    37  	// 2. On OSX, only the monotonic clock seems to have nanosecond resolution. If
    38  	// we strip it, we only get microsecond resolution. Besides generally sucking,
    39  	// microsecond resolution is not enough to guarantee that consecutive
    40  	// timeutil.Now() calls don't return the same instant. This trips up some of
    41  	// our tests, which assume that they can measure any duration of time.
    42  	// 3. time.Since(t) does one less system calls when t has a monotonic reading,
    43  	// making it twice as fast as otherwise:
    44  	// https://cs.opensource.google/go/go/+/refs/tags/go1.17.2:src/time/time.go;l=878;drc=refs%2Ftags%2Fgo1.17.2
    45  	x := (*timeLayout)(unsafe.Pointer(&t))
    46  	x.loc = nil // nil means UTC
    47  	return t
    48  }
    49  
    50  // NowNoMono is like Now(), but it strips down the monotonic part of the
    51  // timestamp. This is useful for getting timestamps that rounds-trip through
    52  // various channels that strip out the monotonic part - for example yaml
    53  // marshaling.
    54  func NowNoMono() time.Time {
    55  	// UTC has the side-effect of stripping the nanos.
    56  	return time.Now().UTC()
    57  }
    58  
    59  // StripMono returns a copy of t with its monotonic clock reading stripped. This
    60  // is useful for getting a time.Time that compares == with another one that
    61  // might not have the mono part. time.Time is meant to be compared with
    62  // Time.Equal() (which ignores the mono), not with ==, but sometimes we have a
    63  // time.Time in a bigger struct and we want to use require.Equal() or such.
    64  func StripMono(t time.Time) time.Time {
    65  	// UTC() has the side-effect of stripping the mono part.
    66  	return t.UTC()
    67  }
    68  
    69  // timeLayout mimics time.Time, exposing all the fields. We do an unsafe cast of
    70  // a time.Time to this in order to set the location.
    71  type timeLayout struct {
    72  	wall uint64
    73  	ext  int64
    74  	loc  *time.Location
    75  }
    76  
    77  // Since returns the time elapsed since t.
    78  // It is shorthand for Now().Sub(t), but more efficient.
    79  func Since(t time.Time) time.Duration {
    80  	return time.Since(t)
    81  }
    82  
    83  // Until returns the duration until t.
    84  // It is shorthand for t.Sub(Now()), but more efficient.
    85  func Until(t time.Time) time.Duration {
    86  	return time.Until(t)
    87  }
    88  
    89  // UnixEpoch represents the Unix epoch, January 1, 1970 UTC.
    90  var UnixEpoch = time.Unix(0, 0).UTC()
    91  
    92  // FromUnixMicros returns the UTC time.Time corresponding to the given Unix
    93  // time, usec microseconds since UnixEpoch. In Go's current time.Time
    94  // implementation, all possible values for us can be represented as a time.Time.
    95  func FromUnixMicros(us int64) time.Time {
    96  	return time.Unix(us/1e6, (us%1e6)*1e3).UTC()
    97  }
    98  
    99  // FromUnixNanos returns the UTC time.Time corresponding to the given Unix
   100  // time, ns nanoseconds since UnixEpoch. In Go's current time.Time
   101  // implementation, all possible values for ns can be represented as a time.Time.
   102  func FromUnixNanos(ns int64) time.Time {
   103  	return time.Unix(ns/1e9, ns%1e9).UTC()
   104  }
   105  
   106  // ToUnixMicros returns t as the number of microseconds elapsed since UnixEpoch.
   107  // Fractional microseconds are rounded, half up, using time.Round. Similar to
   108  // time.Time.UnixNano, the result is undefined if the Unix time in microseconds
   109  // cannot be represented by an int64.
   110  func ToUnixMicros(t time.Time) int64 {
   111  	return t.Unix()*1e6 + int64(t.Round(time.Microsecond).Nanosecond())/1e3
   112  }
   113  
   114  // Unix wraps time.Unix ensuring that the result is in UTC instead of Local.
   115  func Unix(sec, nsec int64) time.Time {
   116  	return time.Unix(sec, nsec).UTC()
   117  }
   118  
   119  // ReplaceLibPQTimePrefix replaces unparsable lib/pq dates used for timestamps
   120  // (0000-01-01) with timestamps that can be parsed by date libraries.
   121  func ReplaceLibPQTimePrefix(s string) string {
   122  	if strings.HasPrefix(s, LibPQTimePrefix) {
   123  		return "1970-01-01" + s[len(LibPQTimePrefix):]
   124  	}
   125  	return s
   126  }