使用Javascript时间创建唯一数字

137

我需要使用JavaScript动态生成唯一的ID号码。过去,我是通过使用时间来创建一个数字来实现这一点的。该数字由四位数年份、两位数月份、两位数日期、两位数小时、两位数分钟、两位数秒和三位数毫秒组成。因此它看起来像这样:20111104103912732... 这足以提供我所需的唯一数字的确定性。

已经有一段时间了,我没有这个代码了。是否有人可以提供这个代码,或者有更好的建议来生成唯一ID?


5
可能是如何在Javascript中创建GUID / UUID?的重复问题。 - August Lilleaas
你考虑过使用 new Date().toISOString() 吗? - Anna B
39个回答

144

32
这不是一个唯一的数字.. 毫秒并不精细到足以被视为唯一的。 - Vamsi Mohan Jayanti
5
或者简单地使用 +new Date() - thdoan
1
我刚刚运行了一个for循环,使用valueOf()时得到了重复的结果。 我只是使用了这个 - +performance.now().toString().replace('.', 7) https://developer.mozilla.org/en-US/docs/Web/API/Performance/now - Itzik Ben Hutta
3
@ItzikBenHutta 三次得到了相同的值。使用多核 CPU,可能是线程之间的竞争条件导致的。 - that-ben

138

创建一个数字,并且可以很确信这个数字在你所想象的独立实例中是唯一的,最短的方法是:

Date.now() + Math.random()
如果函数调用之间存在1毫秒的差异,那么绝对会生成一个不同的数字。如果在同一毫秒内创建超过几百万个数字,才应该开始担心重复的数字问题,但这种情况并不常见。
有关在同一毫秒内获得重复数字的概率,请参见https://dev59.com/cYfca4cB1Zd3GeqPhVXJ#28220928

9
如果您想保留随机数的所有位数,您可以将它们分别生成并合并为字符串:new Date().valueOf().toString(36) + Math.random().toString(36).substr(2)这将给您一个19个字符的字母数字字符串,具有相当不错的熵值。但其中一半是可预测的。 - Erik Pukinskis
4
这应该是被接受的答案,因为在尝试其他投票更高的答案时,当从异步函数调用时,我连续两次甚至三次得到了相同的值。这似乎为标准的8核CPU提供了足够的随机性,可以在完全相同的时刻生成8个唯一的字符串,对我的使用来说足够好。 - that-ben
7
еңЁжҲ‘зңӢжқҘпјҢжңҖеҘҪзҡ„и§ЈеҶіж–№жі•жҳҜдҪҝз”ЁMath.floor(Date.now() * Math.random())гҖӮеҰӮжһңдҪ еңЁеҫӘзҺҜдёӯеҸӘдҪҝз”ЁDate.now()пјҢдјҡеҮәзҺ°йҮҚеӨҚпјҢдҪҶжҳҜдҪҝз”ЁMath.random()еҸҜд»Ҙи®©е®ғдҝқжҢҒе”ҜдёҖжҖ§гҖӮ - Eugene P.
2
我在一个100万项的循环中进行了检查,并且它通过了。这对我来说非常独特:https://stackblitz.com/edit/js-unique-id - Eugene P.
1
这种方法被普遍唯一词典排序标识符(ulid)所使用 https://github.com/ulid/spec - Marcelo Lazaroni
显示剩余4条评论

84

如果你只需要一个相对唯一的数字,那么

var timestamp = new Date().getUTCMilliseconds();

如果你只需要一个简单的数字,那么可以直接获得。但是如果你需要可读版本,就需要进行一些处理:

var now = new Date();

timestamp = now.getFullYear().toString(); // 2011
timestamp += (now.getMonth < 9 ? '0' : '') + now.getMonth().toString(); // JS months are 0-based, so +1 and pad with 0's
timestamp += ((now.getDate < 10) ? '0' : '') + now.getDate().toString(); // pad with a 0
... etc... with .getHours(), getMinutes(), getSeconds(), getMilliseconds()

4
@Áxel:我并没有说它是独一无二的,我说它是“类似独一无二的”。当然,使用客户端生成的时间戳会产生重复。 - Marc B
92
时间戳应该是 new Date().getTime();date.getUTCMilliseconds() 返回一个介于 0 和 999 之间的数字。date.getTime() 返回自 1970 年 1 月 1 日以来的毫秒数(常规时间戳)。http://www.w3schools.com/jsref/jsref_obj_date.asp - Automatico
10
由于问题涉及到“唯一”数字,所以第一个代码块应该完全省略。 - Andrey
13
getUTCMilliseconds() 返回值是0到999之间的整数,这是用作唯一标识符的最糟糕的想法。建议删除第一段内容。 - Anna B
1
(Math.random().toString().replace('.',Math.random().toString().replace('.',''))) 这将在快速循环内提供唯一的数字。 - Md. A. Apu
显示剩余6条评论

26

使用以下代码可以简单地实现:

var date = new Date();
var components = [
    date.getYear(),
    date.getMonth(),
    date.getDate(),
    date.getHours(),
    date.getMinutes(),
    date.getSeconds(),
    date.getMilliseconds()
];

var id = components.join("");

9
如果在同一毫秒内调用此函数两次会怎样? - TBE
2
的确,但对于操作员来说这是可以的:“这将为我的目的提供足够的唯一数字确定性。” - August Lilleaas
上面的代码不比 var id = Date.now().toString() 更好。 - kien_coi_1997

25

当我想要比一堆数字更小的东西时,我会改变进制。

var uid = (new Date().getTime()).toString(36)

1
@blushrt 是的,它可能会导致罕见的冲突。您可以使用类似 https://code.google.com/p/crypto-js/ 的工具对时间戳进行 md5 加密,但对于我的目的来说,这已经足够“独特”,更重要的是,速度更快。 - frumbert
@frumbert,这要看情况。MD5也不具备碰撞抗性。但在你的情况下,由于toString(36),我很快就遇到了麻烦。我假设它将数字值转换为其ASCII表示形式,但不确定。我可以看到问题所在,如果你经常调用uuid生成器,只有最后3个字符会改变,因此发生碰撞的可能性很高。如果你只是坚持使用new Date.getTime()调用,你会得到更好的机会。但是,如果它对你的目的起作用,那就没有问题。我只需要为我的客户端代码使用一些唯一的ID,最终使用了uuid节点库。 - Simon Polak
1
我喜欢这个!我已经调整了它为(Date.now() + Math.random()).toString(36),以防止毫秒冲突。它很短,生成类似于“k92g5pux.i36”的东西。 - Edward

17

使用这种方法比创建一个Date实例更快,代码更少,并且始终会产生一个唯一的数字(本地):

function uniqueNumber() {
    var date = Date.now();

    // If created at same millisecond as previous
    if (date <= uniqueNumber.previous) {
        date = ++uniqueNumber.previous;
    } else {
        uniqueNumber.previous = date;
    }

    return date;
}

uniqueNumber.previous = 0;

jsfiddle:http://jsfiddle.net/j8aLocan/

我已将此发布至Bower和npm:https://github.com/stevenvachon/unique-number

你还可以使用更为复杂的工具(如cuidpuidshortid)来生成非数字。


1
在我看来,添加随机数实际上会使其不太可靠。只使用时间戳,必须在完全相同的毫秒内创建两个数字才能相同。通过添加两个随机数,您现在已经创建了许多数字组合,由于数学运算,这些数字组合可能在乘法时得到相同的结果。我知道这很不可能,但是...是吗? - Phil
嗯,是的。也许结合我的回答和abarber的回答会更好。 - Steven Vachon
更新了我的答案。感谢您的想法。 - Steven Vachon
2
不是针对你的回答挑刺,你的努力值得肯定...但是这个新方案并没有解决“在同一毫秒内创建多个id”的问题,因为,你知道的...它是JavaScript,在客户端运行。如果另一个用户在完全相同的毫秒内创建了一个数字,它不会反映在“其他”用户的uniqueNumber.previous中。除非你将其存储在服务器上并检查唯一性...否则,像这样纯粹基于js的解决方案无法确定它是否创建了唯一的数字。 - Phil
那将是一个比仅有唯一编号更为复杂的系统。 - Steven Vachon
我喜欢这个作为一个简单的本地唯一ID生成器。快速而简便。我已经将它与@frumbert的base36解决方案结合起来。 - Ian

17

我使用

Math.floor(new Date().valueOf() * Math.random())

所以,如果代码在同一时间被触发,那么有一点可能性随机数会相同。


不确定 new Date() 很有用。你可以通过两个不同的日期得到相同的数字。 - JMaylin
2
我的意思是,它比仅执行 Math.random() 函数好在哪里? - JMaylin

14

2023年,您可以使用浏览器内置的Crypto API生成具有加密强度的随机值。

function getRandomNumbers() {
  const typedArray = new Uint8Array(10);
  const randomValues = window.crypto.getRandomValues(typedArray);
  return randomValues.join('');
}

console.log(getRandomNumbers());
// 1857488137147725264738

function getRandomNumbers() {
  const typedArray = new Uint8Array(10);
  const randomValues = window.crypto.getRandomValues(typedArray);
  return randomValues.join('');
}

console.log(getRandomNumbers());

无论在哪个主流浏览器中,包括IE11,都支持Uint8Array构造函数和Crypto.getRandomValues函数。


10

这样就可以了:

var uniqueNumber = new Date().getTime(); // milliseconds since 1st Jan. 1970

1
虽然这并不会真正生成纯粹的“唯一”ID,但在同一毫秒内多次调用此函数时,它对许多情况都很有用... 但无论如何,对于用户和UI交互来说,这是很好的。 - Benjamin Piette
1
这应该是被接受的答案。很多无关紧要的东西,难以理解且不必要,而这个答案提供了每毫秒独特的时间。 - gene b.

9

如果你想在几毫秒后得到一个唯一的数字,那么可以使用Date.now(),如果你想在一个for循环中使用它,那么可以将Date.now()Math.random()结合使用。

在for循环中获取唯一数字

function getUniqueID(){
    for(var i = 0; i< 5; i++)
      console.log(Date.now() + ( (Math.random()*100000).toFixed()))
}
getUniqueID()

输出:所有数字都是唯一的

15598251485988384 155982514859810330 155982514859860737 155982514859882244 155982514859883316

不使用Math.random()生成唯一数字

function getUniqueID(){
        for(var i = 0; i< 5; i++)
          console.log(Date.now())
    }
    getUniqueID()

输出:: 数字重复出现

1559825328327 1559825328327 1559825328327 1559825328328 1559825328328


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接