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 }