This repository has been archived by the owner on May 9, 2020. It is now read-only.
forked from bakanis/uuid
-
Notifications
You must be signed in to change notification settings - Fork 13
/
timestamp.go
117 lines (104 loc) · 3.73 KB
/
timestamp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package uuid
import (
"time"
)
const (
gregorianToUNIXOffset = 122192928e9
// set the following to the number of 100ns ticks of the actual
// resolution of your system's clock
defaultSpinResolution = 1024
)
// 4.1.4. Timestamp https://www.ietf.org/rfc/rfc4122.txt
//
// The timestamp is a 60-bit value. For UUID version 1, this is
//
// represented by Coordinated Universal Time (UTC) as a count of 100-
// nanosecond intervals since 00:00:00.00, 15 October 1582 (the date of
// Gregorian reform to the Christian calendar).
//
// For systems that do not have UTC available, but do have the local
// time, they may use that instead of UTC, as long as they do so
// consistently throughout the system. However, this is not recommended
// since generating the UTC from local time only needs a time zone
// offset.
//
// For UUID version 3 or 5, the timestamp is a 60-bit value constructed
// from a name as described in Section 4.3.
//
// For UUID version 4, the timestamp is a randomly or pseudo-randomly
// generated 60-bit value, as described in Section 4.4.
type Timestamp uint64
// Converts Unix formatted time to RFC4122 UUID formatted times
// UUID UTC base time is October 15, 1582.
// Unix base time is January 1, 1970.
// Converts time to 100 nanosecond ticks since epoch. Uses time.Now
func Now() Timestamp {
return Timestamp(time.Now().UnixNano()/100 + gregorianToUNIXOffset)
}
// Converts UUID Timestamp to UTC time.Time
// Note some higher clock resolutions will lose accuracy if above 100 ns ticks
func (o Timestamp) Time() time.Time {
return time.Unix(0, int64((o-gregorianToUNIXOffset)*100)).UTC()
}
// Returns the timestamp as modified by the duration
func (o Timestamp) Add(pDuration time.Duration) Timestamp {
return o + Timestamp(pDuration/100)
}
// Returns the timestamp as modified by the duration
func (o Timestamp) Sub(pDuration time.Duration) Timestamp {
return o - Timestamp(pDuration/100)
}
// Converts UUID Timestamp to time.Time and then calls the Stringer
func (o Timestamp) String() string {
return o.Time().String()
}
// 4.2.1.2. System Clock Resolution https://www.ietf.org/rfc/rfc4122.txt
//
// The timestamp is generated from the system time, whose resolution may
// be less than the resolution of the UUID timestamp.
//
// If UUIDs do not need to be frequently generated, the timestamp can
// simply be the system time multiplied by the number of 100-nanosecond
// intervals per system time interval.
//
// If a system overruns the generator by requesting too many UUIDs
// within a single system time interval, the UUID service MUST either
// return an error, or stall the UUID generator until the system clock
// catches up.
//
// A high resolution timestamp can be simulated by keeping a count of
// the number of UUIDs that have been generated with the same value of
// the system time, and using it to construct the low order bits of the
// timestamp. The count will range between zero and the number of
// 100-nanosecond intervals per system time interval.
//
// Note: If the processors overrun the UUID generation frequently,
// additional node identifiers can be allocated to the system, which
// will permit higher speed allocation by making multiple UUIDs
// potentially available for each time stamp value.
type spinner struct {
// the amount of ids based on the Timestamp
Count, Resolution uint
// the tracked spin stamp
Timestamp
}
func (o *spinner) next() Timestamp {
for {
now := Now()
// if clock reading changed since last UUID generated
if o.Timestamp == now {
o.Count++
if o.Count == o.Resolution {
for Now() < o.Timestamp+Timestamp(o.Resolution) {
}
continue
}
break
}
// reset count of UUIDs with this timestamp
o.Count = 0
o.Timestamp = now
break
}
return o.Timestamp + Timestamp(o.Count)
}