Scott Baker | eee8dd8 | 2019-09-24 12:52:34 -0700 | [diff] [blame] | 1 | // Copyright 2016 Google Inc. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | package uuid |
| 6 | |
| 7 | import ( |
| 8 | "encoding/binary" |
| 9 | "sync" |
| 10 | "time" |
| 11 | ) |
| 12 | |
| 13 | // A Time represents a time as the number of 100's of nanoseconds since 15 Oct |
| 14 | // 1582. |
| 15 | type Time int64 |
| 16 | |
| 17 | const ( |
| 18 | lillian = 2299160 // Julian day of 15 Oct 1582 |
| 19 | unix = 2440587 // Julian day of 1 Jan 1970 |
| 20 | epoch = unix - lillian // Days between epochs |
| 21 | g1582 = epoch * 86400 // seconds between epochs |
| 22 | g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs |
| 23 | ) |
| 24 | |
| 25 | var ( |
| 26 | timeMu sync.Mutex |
| 27 | lasttime uint64 // last time we returned |
| 28 | clockSeq uint16 // clock sequence for this run |
| 29 | |
| 30 | timeNow = time.Now // for testing |
| 31 | ) |
| 32 | |
| 33 | // UnixTime converts t the number of seconds and nanoseconds using the Unix |
| 34 | // epoch of 1 Jan 1970. |
| 35 | func (t Time) UnixTime() (sec, nsec int64) { |
| 36 | sec = int64(t - g1582ns100) |
| 37 | nsec = (sec % 10000000) * 100 |
| 38 | sec /= 10000000 |
| 39 | return sec, nsec |
| 40 | } |
| 41 | |
| 42 | // GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and |
| 43 | // clock sequence as well as adjusting the clock sequence as needed. An error |
| 44 | // is returned if the current time cannot be determined. |
| 45 | func GetTime() (Time, uint16, error) { |
| 46 | defer timeMu.Unlock() |
| 47 | timeMu.Lock() |
| 48 | return getTime() |
| 49 | } |
| 50 | |
| 51 | func getTime() (Time, uint16, error) { |
| 52 | t := timeNow() |
| 53 | |
| 54 | // If we don't have a clock sequence already, set one. |
| 55 | if clockSeq == 0 { |
| 56 | setClockSequence(-1) |
| 57 | } |
| 58 | now := uint64(t.UnixNano()/100) + g1582ns100 |
| 59 | |
| 60 | // If time has gone backwards with this clock sequence then we |
| 61 | // increment the clock sequence |
| 62 | if now <= lasttime { |
| 63 | clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000 |
| 64 | } |
| 65 | lasttime = now |
| 66 | return Time(now), clockSeq, nil |
| 67 | } |
| 68 | |
| 69 | // ClockSequence returns the current clock sequence, generating one if not |
| 70 | // already set. The clock sequence is only used for Version 1 UUIDs. |
| 71 | // |
| 72 | // The uuid package does not use global static storage for the clock sequence or |
| 73 | // the last time a UUID was generated. Unless SetClockSequence is used, a new |
| 74 | // random clock sequence is generated the first time a clock sequence is |
| 75 | // requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) |
| 76 | func ClockSequence() int { |
| 77 | defer timeMu.Unlock() |
| 78 | timeMu.Lock() |
| 79 | return clockSequence() |
| 80 | } |
| 81 | |
| 82 | func clockSequence() int { |
| 83 | if clockSeq == 0 { |
| 84 | setClockSequence(-1) |
| 85 | } |
| 86 | return int(clockSeq & 0x3fff) |
| 87 | } |
| 88 | |
| 89 | // SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to |
| 90 | // -1 causes a new sequence to be generated. |
| 91 | func SetClockSequence(seq int) { |
| 92 | defer timeMu.Unlock() |
| 93 | timeMu.Lock() |
| 94 | setClockSequence(seq) |
| 95 | } |
| 96 | |
| 97 | func setClockSequence(seq int) { |
| 98 | if seq == -1 { |
| 99 | var b [2]byte |
| 100 | randomBits(b[:]) // clock sequence |
| 101 | seq = int(b[0])<<8 | int(b[1]) |
| 102 | } |
| 103 | oldSeq := clockSeq |
| 104 | clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant |
| 105 | if oldSeq != clockSeq { |
| 106 | lasttime = 0 |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | // Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in |
| 111 | // uuid. The time is only defined for version 1 and 2 UUIDs. |
| 112 | func (uuid UUID) Time() Time { |
| 113 | time := int64(binary.BigEndian.Uint32(uuid[0:4])) |
| 114 | time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 |
| 115 | time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 |
| 116 | return Time(time) |
| 117 | } |
| 118 | |
| 119 | // ClockSequence returns the clock sequence encoded in uuid. |
| 120 | // The clock sequence is only well defined for version 1 and 2 UUIDs. |
| 121 | func (uuid UUID) ClockSequence() int { |
| 122 | return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff |
| 123 | } |