Skip to content

Commit

Permalink
Add Time() and Nanos() methods
Browse files Browse the repository at this point in the history
These methods can be used to extract time values
from V1 UUIDs
  • Loading branch information
rkuris committed May 21, 2017
1 parent 5bf94b6 commit a129dcc
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 0 deletions.
22 changes: 22 additions & 0 deletions uuid.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,28 @@ func (u *NullUUID) Scan(src interface{}) error {
return u.UUID.Scan(src)
}

// Nanos returns the number of nanoseconds in a V1 UUID
func (u *UUID) Nanos() (int64, error) {
if u.Version() != 1 {
err := fmt.Errorf("uuid: %s is version %d, not version 1", u, u.Version())
return 0, err
}
low := binary.BigEndian.Uint32(u[0:4])
mid := binary.BigEndian.Uint16(u[4:6])
hi := binary.BigEndian.Uint16(u[6:8]) & 0xfff
return 100 * (int64(low) + (int64(mid) << 32) + (int64(hi) << 48) - int64(epochStart)), nil
}

// Time returns the time embedded in a V1 UUID
// An error is returned if this is not a V1 UUID
func (u *UUID) Time() (time.Time, error) {
nanos, err := u.Nanos()
if err != nil {
return time.Time{}, err
}
return time.Unix(0, nanos), nil
}

// FromBytes returns UUID converted from raw byte slice input.
// It will return error if the slice isn't 16 bytes long.
func FromBytes(input []byte) (u UUID, err error) {
Expand Down
52 changes: 52 additions & 0 deletions uuid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,20 @@ func TestNullUUIDScanNil(t *testing.T) {
}
}

func TestTimeErrors(t *testing.T) {
u := NewV2(DomainPerson)

_, err := u.Time()
if err == nil {
t.Errorf("Expected error from V2 UUID: %s", u)
}

_, err = u.Nanos()
if err == nil {
t.Errorf("Expected error from V2 UUID: %s", u)
}
}

func TestNewV1(t *testing.T) {
u := NewV1()

Expand All @@ -513,6 +527,31 @@ func TestNewV1(t *testing.T) {
t.Errorf("UUIDv1 generated two equal UUIDs: %s and %s", u1, u2)
}

n1, err := u1.Nanos()
if err != nil {
t.Errorf("UUIDv1 Nanos error: %s %v", u1, err)
}
n2, err := u2.Nanos()
if err != nil {
t.Errorf("UUIDv1 Nanos error: %s %v", u2, err)
}

if n1 > n2 {
t.Errorf("UUIDv1 generated older UUID: %s > %s", u1, u2)
}

t1, err := u1.Time()
if err != nil {
t.Errorf("UUIDv1 Time error: %s %v", u1, err)
}
t2, err := u2.Time()
if err != nil {
t.Errorf("UUIDv1 Time error: %s %v", u2, err)
}
if t1.After(t2) {
t.Errorf("UUIDv1 time comparison failed: %s (%s) > %s (%s)", u1, t1, u2, t2)
}

oldFunc := epochFunc
epochFunc = func() uint64 { return 0 }

Expand All @@ -523,6 +562,19 @@ func TestNewV1(t *testing.T) {
t.Errorf("UUIDv1 generated two equal UUIDs: %s and %s", u3, u4)
}

n3, err := u3.Nanos()
if err != nil {
t.Errorf("UUIDv1 Nanos error: %s %v", u3, err)
}
n4, err := u4.Nanos()
if err != nil {
t.Errorf("UUIDv1 Nanos error: %s %v", u4, err)
}

if n3 != n4 {
t.Errorf("UUIDv1 nanos expected equal: %s (%d) and %s (%d)", u3, n3, u4, n4)
}

epochFunc = oldFunc
}

Expand Down

0 comments on commit a129dcc

Please sign in to comment.