瀏覽代碼

Merge pull request #86 from phopkins/custom-time-uuid

Fixes UUID Timestamp and add FromTime function
Christoph Hack 12 年之前
父節點
當前提交
2ae8898256
共有 4 個文件被更改,包括 35 次插入24 次删除
  1. 1 0
      AUTHORS
  2. 3 14
      marshal.go
  3. 14 10
      uuid/uuid.go
  4. 17 0
      uuid/uuid_test.go

+ 1 - 0
AUTHORS

@@ -11,3 +11,4 @@ Ghais Issa <ghais.issa@gmail.com>
 Sasha Klizhentas <klizhentas@gmail.com>
 Sasha Klizhentas <klizhentas@gmail.com>
 Konstantin Cherkasov <k.cherkasoff@gmail.com>
 Konstantin Cherkasov <k.cherkasoff@gmail.com>
 Ben Hood <0x6e6562@gmail.com>
 Ben Hood <0x6e6562@gmail.com>
+Pete Hopkins <phopkins@gmail.com>

+ 3 - 14
marshal.go

@@ -920,20 +920,11 @@ func unmarshalTimeUUID(info *TypeInfo, data []byte, value interface{}) error {
 		*v = uuid.FromBytes(data)
 		*v = uuid.FromBytes(data)
 		return nil
 		return nil
 	case *time.Time:
 	case *time.Time:
-		if len(data) != 16 {
+		id := uuid.FromBytes(data)
+		if id.Version() != 1 {
 			return unmarshalErrorf("invalid timeuuid")
 			return unmarshalErrorf("invalid timeuuid")
 		}
 		}
-		if version := int(data[6] & 0xF0 >> 4); version != 1 {
-			return unmarshalErrorf("invalid timeuuid")
-		}
-		timestamp := int64(uint64(data[0])<<24|uint64(data[1])<<16|
-			uint64(data[2])<<8|uint64(data[3])) +
-			int64(uint64(data[4])<<40|uint64(data[5])<<32) +
-			int64(uint64(data[6]&0x0F)<<56|uint64(data[7])<<48)
-		timestamp = timestamp - timeEpoch
-		sec := timestamp / 1e7
-		nsec := timestamp - sec
-		*v = time.Unix(int64(sec), int64(nsec)).UTC()
+		*v = id.Time()
 		return nil
 		return nil
 	}
 	}
 	return unmarshalErrorf("can not unmarshal %s into %T", info, value)
 	return unmarshalErrorf("can not unmarshal %s into %T", info, value)
@@ -1067,5 +1058,3 @@ func (m UnmarshalError) Error() string {
 func unmarshalErrorf(format string, args ...interface{}) UnmarshalError {
 func unmarshalErrorf(format string, args ...interface{}) UnmarshalError {
 	return UnmarshalError(fmt.Sprintf(format, args...))
 	return UnmarshalError(fmt.Sprintf(format, args...))
 }
 }
-
-var timeEpoch int64 = 0x01B21DD213814000

+ 14 - 10
uuid/uuid.go

@@ -100,14 +100,20 @@ func RandomUUID() UUID {
 
 
 var timeBase = time.Date(1582, time.October, 15, 0, 0, 0, 0, time.UTC).Unix()
 var timeBase = time.Date(1582, time.October, 15, 0, 0, 0, 0, time.UTC).Unix()
 
 
-// TimeUUID generates a new time based UUID (version 1) as described in RFC
-// 4122. This UUID contains the MAC address of the node that generated the
-// UUID, a timestamp and a sequence number.
+// TimeUUID generates a new time based UUID (version 1) using the current
+// time as the timestamp.
 func TimeUUID() UUID {
 func TimeUUID() UUID {
+	return FromTime(time.Now())
+}
+
+// FromTime generates a new time based UUID (version 1) as described in RFC
+// 4122. This UUID contains the MAC address of the node that generated the
+// UUID, the given timestamp and a sequence number.
+func FromTime(aTime time.Time) UUID {
 	var u UUID
 	var u UUID
 
 
-	now := time.Now().In(time.UTC)
-	t := uint64(now.Unix()-timeBase)*10000000 + uint64(now.Nanosecond()/100)
+	utcTime := aTime.In(time.UTC)
+	t := uint64(utcTime.Unix()-timeBase)*10000000 + uint64(utcTime.Nanosecond()/100)
 	u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t)
 	u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t)
 	u[4], u[5] = byte(t>>40), byte(t>>32)
 	u[4], u[5] = byte(t>>40), byte(t>>32)
 	u[6], u[7] = byte(t>>56)&0x0F, byte(t>>48)
 	u[6], u[7] = byte(t>>56)&0x0F, byte(t>>48)
@@ -187,10 +193,8 @@ func (u UUID) Time() time.Time {
 	if u.Version() != 1 {
 	if u.Version() != 1 {
 		return time.Time{}
 		return time.Time{}
 	}
 	}
-	t := u.Timestamp() - timeEpoch
+	t := u.Timestamp()
 	sec := t / 1e7
 	sec := t / 1e7
-	nsec := t - sec
-	return time.Unix(int64(sec), int64(nsec)).UTC()
+	nsec := t % 1e7
+	return time.Unix(sec+timeBase, nsec).UTC()
 }
 }
-
-var timeEpoch int64 = 0x01B21DD213814000

+ 17 - 0
uuid/uuid_test.go

@@ -7,6 +7,7 @@ package uuid
 import (
 import (
 	"bytes"
 	"bytes"
 	"testing"
 	"testing"
+	"time"
 )
 )
 
 
 func TestNil(t *testing.T) {
 func TestNil(t *testing.T) {
@@ -74,6 +75,22 @@ func TestRandomUUID(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func TestFromTime(t *testing.T) {
+	date := time.Date(1982, 5, 5, 12, 34, 56, 0, time.UTC)
+	uuid := FromTime(date)
+
+	if uuid.Time() != date {
+		t.Errorf("embedded time incorrect. Expected %v got %v", date, uuid.Time())
+	}
+}
+
+func TestParse(t *testing.T) {
+	uuid, _ := ParseUUID("486f3a88-775b-11e3-ae07-d231feb1dc81")
+	if uuid.Time().Truncate(time.Second) != time.Date(2014, 1, 7, 5, 19, 29, 0, time.UTC) {
+		t.Errorf("Expected date of 1/7/2014 at 5:19:29, got %v", uuid.Time())
+	}
+}
+
 func TestTimeUUID(t *testing.T) {
 func TestTimeUUID(t *testing.T) {
 	var node []byte
 	var node []byte
 	timestamp := int64(0)
 	timestamp := int64(0)