diff --git a/README.md b/README.md
index 438e163..df560f6 100644
--- a/README.md
+++ b/README.md
@@ -35,14 +35,11 @@ Add these lines to your `pom.xml`.
com.github.f4b6a3
ulid-creator
- 3.0.1
+ 3.1.0
```
See more options in [maven.org](https://search.maven.org/artifact/com.github.f4b6a3/ulid-creator).
-Implementation
-------------------------------------------------------
-
### ULID
The ULID is a 128 bit long identifier. The first 48 bits represent the count of milliseconds since Unix Epoch, 1970-01-01. The remaining 80 bits are generated by a secure random number generator.
@@ -168,25 +165,40 @@ Get the creation instant of a ULID:
Instant instant = ulid.getInstant(); // 2007-02-16T02:13:14.633Z
```
+```java
+// static method
+Instant instant = Ulid.getInstant("0123456789ABCDEFGHJKMNPQRS"); // 2007-02-16T02:13:14.633Z
+```
+
Get the time component of a ULID:
```java
long time = ulid.getTime(); // 1171591994633
```
+```java
+// static method
+long time = Ulid.getTime("0123456789ABCDEFGHJKMNPQRS"); // 1171591994633
+```
+
Get the random component of a ULID:
```java
byte[] random = ulid.getRandom(); // 10 bytes (80 bits)
```
+```java
+// static method
+byte[] random = Ulid.getRandom("0123456789ABCDEFGHJKMNPQRS"); // 10 bytes (80 bits)
+```
+
Use a `UlidFactory` instance with `java.util.Random` to generate ULIDs:
```java
Random random = new Random();
UlidFactory factory = UlidCreator.getDefaultFactory().withRandomGenerator(random::nextBytes);
-Ulid ulid = facory.create();
+Ulid ulid = factory.create();
```
Use a `UlidFactory` instance with any random generator you like(*) to generate ULIDs:
@@ -196,7 +208,7 @@ import com.github.niceguy.random.AwesomeRandom; // a hypothetical RNG
AwesomeRandom awesomeRandom = new AwesomeRandom();
UlidFactory factory = UlidCreator.getDefaultFactory().withRandomGenerator(awesomeRandom::nextBytes);
-Ulid ulid = facory.create();
+Ulid ulid = factory.create();
```
(*) since it provides a void method like `nextBytes(byte[])`.
diff --git a/src/main/java/com/github/f4b6a3/ulid/Ulid.java b/src/main/java/com/github/f4b6a3/ulid/Ulid.java
index 8c0563a..d2285e1 100644
--- a/src/main/java/com/github/f4b6a3/ulid/Ulid.java
+++ b/src/main/java/com/github/f4b6a3/ulid/Ulid.java
@@ -423,6 +423,18 @@ public final class Ulid implements Serializable, Comparable {
return Instant.ofEpochMilli(this.getTime());
}
+ /**
+ * Returns the instant of creation.
+ *
+ * The instant of creation is extracted from the time component.
+ *
+ * @param string a canonical string
+ * @return {@link Instant}
+ */
+ public static Instant getInstant(String string) {
+ return Instant.ofEpochMilli(getTime(string));
+ }
+
/**
* Returns the time component as a number.
*
@@ -435,6 +447,35 @@ public final class Ulid implements Serializable, Comparable {
return this.msb >>> 16;
}
+ /**
+ * Returns the time component as a number.
+ *
+ * The time component is a number between 0 and 2^48-1. It is equivalent to the
+ * count of milliseconds since 1970-01-01 (Unix epoch).
+ *
+ * @param string a canonical string
+ * @return a number of milliseconds.
+ */
+ public static long getTime(String string) {
+
+ final char[] chars = toCharArray(string);
+
+ long time = 0;
+
+ time |= ALPHABET_VALUES[chars[0x00]] << 45;
+ time |= ALPHABET_VALUES[chars[0x01]] << 40;
+ time |= ALPHABET_VALUES[chars[0x02]] << 35;
+ time |= ALPHABET_VALUES[chars[0x03]] << 30;
+ time |= ALPHABET_VALUES[chars[0x04]] << 25;
+ time |= ALPHABET_VALUES[chars[0x05]] << 20;
+ time |= ALPHABET_VALUES[chars[0x06]] << 15;
+ time |= ALPHABET_VALUES[chars[0x07]] << 10;
+ time |= ALPHABET_VALUES[chars[0x08]] << 5;
+ time |= ALPHABET_VALUES[chars[0x09]];
+
+ return time;
+ }
+
/**
* Returns the random component as a byte array.
*
@@ -443,8 +484,71 @@ public final class Ulid implements Serializable, Comparable {
* @return a byte array
*/
public byte[] getRandom() {
+
final byte[] bytes = new byte[RANDOM_BYTES_LENGTH];
- System.arraycopy(this.toBytes(), TIME_BYTES_LENGTH, bytes, 0, RANDOM_BYTES_LENGTH);
+
+ bytes[0x0] = (byte) (msb >>> 8);
+ bytes[0x1] = (byte) (msb);
+
+ bytes[0x2] = (byte) (lsb >>> 56);
+ bytes[0x3] = (byte) (lsb >>> 48);
+ bytes[0x4] = (byte) (lsb >>> 40);
+ bytes[0x5] = (byte) (lsb >>> 32);
+ bytes[0x6] = (byte) (lsb >>> 24);
+ bytes[0x7] = (byte) (lsb >>> 16);
+ bytes[0x8] = (byte) (lsb >>> 8);
+ bytes[0x9] = (byte) (lsb);
+
+ return bytes;
+ }
+
+ /**
+ * Returns the random component as a byte array.
+ *
+ * The random component is an array of 10 bytes (80 bits).
+ *
+ * @param string a canonical string
+ * @return a byte array
+ */
+ public static byte[] getRandom(String string) {
+
+ final char[] chars = toCharArray(string);
+
+ long random0 = 0;
+ long random1 = 0;
+
+ random0 |= ALPHABET_VALUES[chars[0x0a]] << 35;
+ random0 |= ALPHABET_VALUES[chars[0x0b]] << 30;
+ random0 |= ALPHABET_VALUES[chars[0x0c]] << 25;
+ random0 |= ALPHABET_VALUES[chars[0x0d]] << 20;
+ random0 |= ALPHABET_VALUES[chars[0x0e]] << 15;
+ random0 |= ALPHABET_VALUES[chars[0x0f]] << 10;
+ random0 |= ALPHABET_VALUES[chars[0x10]] << 5;
+ random0 |= ALPHABET_VALUES[chars[0x11]];
+
+ random1 |= ALPHABET_VALUES[chars[0x12]] << 35;
+ random1 |= ALPHABET_VALUES[chars[0x13]] << 30;
+ random1 |= ALPHABET_VALUES[chars[0x14]] << 25;
+ random1 |= ALPHABET_VALUES[chars[0x15]] << 20;
+ random1 |= ALPHABET_VALUES[chars[0x16]] << 15;
+ random1 |= ALPHABET_VALUES[chars[0x17]] << 10;
+ random1 |= ALPHABET_VALUES[chars[0x18]] << 5;
+ random1 |= ALPHABET_VALUES[chars[0x19]];
+
+ final byte[] bytes = new byte[RANDOM_BYTES_LENGTH];
+
+ bytes[0x0] = (byte) (random0 >>> 32);
+ bytes[0x1] = (byte) (random0 >>> 24);
+ bytes[0x2] = (byte) (random0 >>> 16);
+ bytes[0x3] = (byte) (random0 >>> 8);
+ bytes[0x4] = (byte) (random0);
+
+ bytes[0x5] = (byte) (random1 >>> 32);
+ bytes[0x6] = (byte) (random1 >>> 24);
+ bytes[0x7] = (byte) (random1 >>> 16);
+ bytes[0x8] = (byte) (random1 >>> 8);
+ bytes[0x9] = (byte) (random1);
+
return bytes;
}
diff --git a/src/test/java/com/github/f4b6a3/ulid/UlidTest.java b/src/test/java/com/github/f4b6a3/ulid/UlidTest.java
index c22d851..9a3fd19 100644
--- a/src/test/java/com/github/f4b6a3/ulid/UlidTest.java
+++ b/src/test/java/com/github/f4b6a3/ulid/UlidTest.java
@@ -281,20 +281,29 @@ public class UlidTest {
public void testGetTimeAndGetRandom() {
long time = 0;
- byte[] bytes = new byte[10];
+ byte[] bytes = new byte[Ulid.RANDOM_BYTES_LENGTH];
Random random = new Random();
for (int i = 0; i < 100; i++) {
time = random.nextLong() & TIME_MASK;
random.nextBytes(bytes);
- Ulid ulid = new Ulid(time, bytes);
+ // Instance methods
+ Ulid ulid = new Ulid(time, bytes);
assertEquals(time, ulid.getTime()); // test Ulid.getTime()
assertEquals(Instant.ofEpochMilli(time), ulid.getInstant()); // test Ulid.getInstant()
for (int j = 0; j < bytes.length; j++) {
assertEquals(bytes[j], ulid.getRandom()[j]); // test Ulid.getRandom()
}
+
+ // Static methods
+ String string = new Ulid(time, bytes).toString();
+ assertEquals(time, Ulid.getTime(string)); // test Ulid.getTime()
+ assertEquals(Instant.ofEpochMilli(time), Ulid.getInstant(string)); // test Ulid.getInstant()
+ for (int j = 0; j < bytes.length; j++) {
+ assertEquals(bytes[j], Ulid.getRandom(string)[j]); // test Ulid.getRandom()
+ }
}
}