diff --git a/README.md b/README.md index 38b701b..e6a35b1 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,7 @@ Usage: ulid [-hlqz] [-f ] [parameters ...] -h, --help print this help text -l, --local when parsing, show local time instead of UTC -q, --quick when generating, use non-crypto-grade entropy + -u, --uuid when parsing or generating, print as UUID string -z, --zero when generating, fix entropy to all-zeroes ``` @@ -134,6 +135,10 @@ $ ulid 01D78XZ44G0000000000000000 Sun Mar 31 03:51:23.536 UTC 2019 $ ulid --format=rfc3339 --local 01D78XZ44G0000000000000000 2019-03-31T05:51:23.536+02:00 +$ ulid -u 01D78XZ44G0000000000000000 +0169d1df-9090-0000-0000-000000000000 +$ ulid --uuid +0184ceda-2982-6f83-9645-7fc810743a30 ``` ## Specification diff --git a/cmd/ulid/main.go b/cmd/ulid/main.go index 50e62cc..730787b 100644 --- a/cmd/ulid/main.go +++ b/cmd/ulid/main.go @@ -28,6 +28,7 @@ func main() { local = fs.BoolLong("local", 'l', "when parsing, show local time instead of UTC") quick = fs.BoolLong("quick", 'q', "when generating, use non-crypto-grade entropy") zero = fs.BoolLong("zero", 'z', "when generating, fix entropy to all-zeroes") + asUUID = fs.BoolLong("uuid", 'u', "when parsing or generating, print as UUID string") help = fs.BoolLong("help", 'h', "print this help text") ) if err := fs.Getopt(os.Args, nil); err != nil { @@ -56,13 +57,13 @@ func main() { switch args := fs.Args(); len(args) { case 0: - generate(*quick, *zero) + generate(*quick, *zero, *asUUID) default: - parse(args[0], *local, formatFunc) + parse(args[0], *local, *asUUID, formatFunc) } } -func generate(quick, zero bool) { +func generate(quick, zero, asUUID bool) { entropy := cryptorand.Reader if quick { seed := time.Now().UnixNano() @@ -79,16 +80,21 @@ func generate(quick, zero bool) { os.Exit(1) } - fmt.Fprintf(os.Stdout, "%s\n", id) + printID(id, asUUID) } -func parse(s string, local bool, f func(time.Time) string) { +func parse(s string, local, asUUID bool, f func(time.Time) string) { id, err := ulid.Parse(s) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } + if asUUID { + printID(id, true) + return + } + t := ulid.Time(id.Time()) if !local { t = t.UTC() @@ -104,3 +110,11 @@ func (zeroReader) Read(p []byte) (int, error) { } return len(p), nil } + +func printID(id ulid.ULID, asUUID bool) { + if !asUUID { + fmt.Fprintf(os.Stdout, "%s\n", id) + return + } + fmt.Fprintf(os.Stdout, "%s\n", id.UUIDString()) +} diff --git a/ulid.go b/ulid.go index 81f9c8d..c020ea8 100644 --- a/ulid.go +++ b/ulid.go @@ -18,6 +18,7 @@ import ( "bytes" "database/sql/driver" "encoding/binary" + "encoding/hex" "errors" "io" "math" @@ -282,6 +283,25 @@ func (id ULID) String() string { return string(ulid) } +// UUIDString returns an UUID representation of the ULID +// (36 characters, 32 hex encoded repr plus 4 dashes) +// e.g. 01AN4Z07BY79KA1307SR9X4MV3 will be 015549f0-1d7e-3a66-a08c-07ce13d25363 +func (id ULID) UUIDString() string { + var buf [36]byte + + hex.Encode(buf[:], id[:4]) + buf[8] = '-' + hex.Encode(buf[9:13], id[4:6]) + buf[13] = '-' + hex.Encode(buf[14:18], id[6:8]) + buf[18] = '-' + hex.Encode(buf[19:23], id[8:10]) + buf[23] = '-' + hex.Encode(buf[24:], id[10:]) + + return string(buf[:]) +} + // MarshalBinary implements the encoding.BinaryMarshaler interface by // returning the ULID as a byte slice. func (id ULID) MarshalBinary() ([]byte, error) {