用JavaScript时间创建一个唯一的数字


96

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

自从我这样做已经有一段时间了,我再也没有代码了。任何人都有执行此操作的代码,或者有更好的建议来生成唯一ID?



你考虑过了new Date().toISOString ()吗?
加斯帕德

Answers:


66

如果您只想要一个唯一的数字,那么

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()

3
@Áxel:我不是说它是独一无二的,而是说它是“独特的”。当然,使用时间戳生成的客户端会生成重复。
Marc B

79
时间戳应new Date().getTime();date.getUTCMilliseconds()返回0和999之间的数字date.getTime()返回毫秒因为1月1日1970年(正常时间戳)。w3schools.com/jsref/jsref_obj_date.asp
自动

8
-1,因为问题是关于唯一编号。第一个代码块应完全省略。
Andrey 2014年

这可以生成2个唯一值:function foo1() {console.log(new Date().getUTCMilliseconds()); console.log(new Date().getUTCMilliseconds()); }
Sharikov Vladislav

10
getUTCMilliseconds The value returned by getUTCMilliseconds() is an integer between 0 and 999.。对于唯一ID,这是最糟糕的主意,应删除第一段。
加斯帕德

118

更好的方法是:

new Date().valueOf();

代替

new Date().getUTCMilliseconds();

valueOf()是“最有可能”的唯一数字。 http://www.w3schools.com/jsref/jsref_valueof_date.asp


19
它不是唯一数字。毫秒的粒度不足以使其视为唯一。
Vamsi Mohan Jayanti 2014年

3
或者只是+new Date()
thdoan '17

1
我刚运行了一个for循环,却得到了与相同的结果valueOf()。我只是用这个- +performance.now().toString().replace('.', 7) developer.mozilla.org/en-US/docs/Web/API/Performance/now
伊茨克本Hutta

1
@ItzikBenHutta得到了相同值的3倍。使用多核CPU,可能是线程竞争的情况。
that-ben

70

您可以确定的最简单的数字创建方法是,在您想到的多个实例中,它是唯一的

Date.now() + Math.random()

如果函数调用之间存在1毫秒的差异,则保证100%生成不同的数字。对于同一毫秒内的函数调用,如果您在同一毫秒内创建了数百万个以上的数字(这不太可能),则应该开始担心。

有关在同一毫秒内获得重复数字的可能性的更多信息,请参见https://stackoverflow.com/a/28220928/4617597


7
此外,如果要保留随机数的所有位,则可以分别生成它们并合并为字符串:new Date()。valueOf()。toString(36)+ Math.random()。toString(36).substr (2)这将为您提供19个字符的字母数字字符串,这是相当不错的熵。尽管其中一半是可以预见的。
Erik Pukinskis

2
这应该是可以接受的答案,因为尝试其他获得较高投票的答案时,从异步函数中调用时,我连续得到2甚至3倍的相同值。这似乎为标准的8核CPU提供了足够的随机性,使其可以完全同时生成8个唯一的字符串,足以供我使用。
that-ben

22

只需使用以下代码即可实现:

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

var id = components.join("");

6
如果在同一毫秒内两次调用该怎么办?
TBE

1
确实,但是对于操作员来说还可以:“这将为我的目的提供足够的唯一性确定性。”
8月Lilleaas

17

当我想要一些比一堆数字小的东西时,这就是我要做的事情-改变基数。

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

1
@blushrt是的,它可能导致罕见的冲突。您可以使用code.google.com/p/crypto-js之类的东西对时间戳进行md5修改,但就我的目的而言,它“足够独特”,更重要的是,速度更快。
frumbert

@frumbert,这取决于。MD5也不防碰撞。但是在您的情况下,由于toString(36)(我认为它会将数值转换为它的ascii表示形式),我很快陷入了麻烦,虽然不确定,但是我可以看到问题,如果您经常调用uuid生成器,只能持续3个字符不断变化,因此发生碰撞的可能性很高。如果您仅坚持使用新的Date.getTime()调用,则可能会获得更好的赔率。但是,嘿,如果它能满足您的目的,没问题,我只需要为我的客户端代码提供一些唯一的ID,最终使用uuid node lib。
blushrt

我喜欢这个!我已经对其进行(Date.now() + Math.random()).toString(36)了调整,以防止毫秒级的冲突。它很短,会生成类似“ k92g5pux.i36”的内容
Edward

16

这比创建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

嗯是的 也许结合我的答案和理发师的答案是最好的。
史蒂文·瓦雄

更新了我的答案。感谢您的想法。
史蒂文·瓦雄

2
尽力而为,不要试图挑出答案...但是这个新解决方案实际上并不能解决“在同一毫秒内创建多个ID”的问题,因为,您知道,这是JavaScript,是在客户端。如果其他用户在相同的精确毫秒内创建了一个数字,则该数字不会反映在“其他”用户的uniqueNumber.previous中。除非您将其存储在服务器上的某个位置并检查其唯一性...否则,不可能像这样基于纯js的解决方案确定自己正在创建一个唯一的数字。
Phil

嗯,这将是一个比唯一编号更复杂的系统。
史蒂文·瓦雄

12

我用

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

因此,如果有机会在同一时间触发代码,那么随机数也将是相同的。


不确定new Date()是否有用。您可以在两个不同的日期得到相同的数字
JMaylin '16

1
我的意思是,这比简单地做得更好Math.random()吗?
JMaylin '16

7

这应该做:

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

1
在许多情况下很有用,尽管这样实际上并不会生成纯粹的“唯一” ID,以防万一在同一毫秒内多次调用此函数……但是无论如何,对于用户和UI交互来说,这是很好的。
本杰明·皮耶特

1
这应该是公认的答案。许多无关紧要的废话,这是困难的和不必要的,并且此答案给出了每毫秒的唯一时间。
基因b。

5

如果您想在几毫秒后再使用一个唯一编号,请使用Date.now(),如果您想在a内for loop使用该编号,请Date.now() and 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


4

通过在线调查,我想到了以下对象,该对象在每个会话中创建一个唯一的ID:

        window.mwUnique ={
        prevTimeId : 0,
        prevUniqueId : 0,
        getUniqueID : function(){
            try {
                var d=new Date();
                var newUniqueId = d.getTime();
                if (newUniqueId == mwUnique.prevTimeId)
                    mwUnique.prevUniqueId = mwUnique.prevUniqueId + 1;
                else {
                    mwUnique.prevTimeId = newUniqueId;
                    mwUnique.prevUniqueId = 0;
                }
                newUniqueId = newUniqueId + '' + mwUnique.prevUniqueId;
                return newUniqueId;                     
            }
            catch(e) {
                mwTool.logError('mwUnique.getUniqueID error:' + e.message + '.');
            }
        }            
    }

这可能对某些人有帮助。

干杯

安德鲁


这是迄今为止有关此问题的最简单且防错的解决方案。我尝试了一种不同的解决方案(请参阅下文),但是我对此仍有一些担忧,需要进一步开发。
loretoparisi

3

这也应该做:

(function() {
    var uniquePrevious = 0;
    uniqueId = function() {
        return uniquePrevious++;
    };
}());

您可以在lodash UniqueId函数中找到非常相似的实现,对我来说,您的解决方案简单明了。
卡米尔·纳雅

3

在ES6中:

const ID_LENGTH = 36
const START_LETTERS_ASCII = 97 // Use 64 for uppercase
const ALPHABET_LENGTH = 26

const uniqueID = () => [...new Array(ID_LENGTH)]
  .map(() => String.fromCharCode(START_LETTERS_ASCII + Math.random() * ALPHABET_LENGTH))
 .join('')

例:

 > uniqueID()
 > "bxppcnanpuxzpyewttifptbklkurvvetigra"

2

始终在JS中获得唯一ID

function getUniqueId(){
   return (new Date().getTime()).toString(36) + new Date().getUTCMilliseconds();
}

getUniqueId()    // Call the function

------------results like

//"ka2high4264"

//"ka2hj115905"

//"ka2hj1my690"

//"ka2hj23j287"

//"ka2hj2jp869"

2

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

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

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

Uint8ArrayCrypto.getRandomValues都支持所有主要的浏览器,包括IE11


1

在此处发布此代码段以供将来参考(不保证,但足够令人满意的“独特”):

// a valid floating number
window.generateUniqueNumber = function() {
    return new Date().valueOf() + Math.random();
};

// a valid HTML id
window.generateUniqueId = function() {
    return "_" + new Date().valueOf() + Math.random().toFixed(16).substring(2);
};

1

如果只希望数字更改“ chars”变量,则可以创建几乎保证唯一的32个字符的密钥客户端。

var d = new Date().valueOf();
var n = d.toString();
var result = '';
var length = 32;
var p = 0;
var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

for (var i = length; i > 0; --i){
    result += ((i & 1) && n.charAt(p) ? '<b>' + n.charAt(p) + '</b>' : chars[Math.floor(Math.random() * chars.length)]);
    if(i & 1) p++;
};

https://jsfiddle.net/j0evrdf1/1/


1

使用此方法:在javascript中创建唯一编号

var uniqueNumber=(new Date().getTime()).toString(36);

真的行。:)


1
    function UniqueValue(d){
        var dat_e = new Date();
        var uniqu_e = ((Math.random() *1000) +"").slice(-4)

        dat_e = dat_e.toISOString().replace(/[^0-9]/g, "").replace(dat_e.getFullYear(),uniqu_e);
        if(d==dat_e)
            dat_e = UniqueValue(dat_e);
        return dat_e;
    }

通话1:UniqueValue('0')
调用2:UniqueValue(UniqueValue('0'))//将很复杂

示例输出:
for(var i = 0; i <10; i ++){console.log(UniqueValue(UniqueValue('0')));}
60950116113248802
26780116113248803
53920116113248803
35840116113248803
47430116113248803
41680116113248803
42980116113248804
34750116113248804
20950116113248804
03730116113


1

由于毫秒不会在节点中每毫秒更新一次,因此提供了一个答案。这将生成一个唯一的人类可读票证号。我是编程和nodejs的新手。如果我错了,请纠正我。

function get2Digit(value) {
if (value.length == 1) return "0" + "" + value;
else return value;

}

function get3Digit(value) {
if (value.length == 1) return "00" + "" + value;
else return value;

}

function generateID() {
    var d = new Date();
    var year = d.getFullYear();
    var month = get2Digit(d.getMonth() + 1);
    var date = get2Digit(d.getDate());
    var hours = get2Digit(d.getHours());
    var minutes = get2Digit(d.getMinutes());
    var seconds = get2Digit(d.getSeconds());
    var millSeconds = get2Digit(d.getMilliseconds());
    var dateValue = year + "" + month + "" + date;
    var uniqueID = hours + "" + minutes + "" + seconds + "" + millSeconds;

    if (lastUniqueID == "false" || lastUniqueID < uniqueID) lastUniqueID = uniqueID;
    else lastUniqueID = Number(lastUniqueID) + 1;
    return dateValue + "" + lastUniqueID;
}

0

假设@abarber提出的解决方案是一个很好的解决方案,因为使用,(new Date()).getTime()因此它具有毫秒窗,并且求和tick在此间隔内发生冲突时,我们可以考虑使用内置函数,因为我们可以在这里清楚地看到它的作用:

拳头我们可以在这里看到使用(new Date()).getTime()以下命令在1/1000窗口框架中如何发生碰撞:

console.log( (new Date()).getTime() ); console.log( (new Date()).getTime() )
VM1155:1 1469615396590
VM1155:1 1469615396591
console.log( (new Date()).getTime() ); console.log( (new Date()).getTime() )
VM1156:1 1469615398845
VM1156:1 1469615398846
console.log( (new Date()).getTime() ); console.log( (new Date()).getTime() )
VM1158:1 1469615403045
VM1158:1 1469615403045

其次,我们尝试提出的解决方案,避免在1/1000窗口中发生冲突:

console.log( window.mwUnique.getUniqueID() ); console.log( window.mwUnique.getUniqueID() ); 
VM1159:1 14696154132130
VM1159:1 14696154132131

也就是说,我们可以考虑将像process.nextTick事件循环中被调用的节点之类的函数单独使用tick这里对此进行了详细说明。当然,在浏览器中没有,process.nextTick所以我们必须弄清楚如何做到这一点。 实现将安装nextTick使用最接近功能在那些浏览器中的I / O的浏览器功能setTimeout(fnc,0)setImmediate(fnc)window.requestAnimationFrame。如此处建议的那样我们可以添加window.postMessage,但我也将其留给读者,因为它也需要一个addEventListener。我已经修改了原始模块版本,以使其在此处更简单:

getUniqueID = (c => {
 if(typeof(nextTick)=='undefined')
nextTick = (function(window, prefixes, i, p, fnc) {
    while (!fnc && i < prefixes.length) {
        fnc = window[prefixes[i++] + 'equestAnimationFrame'];
    }
    return (fnc && fnc.bind(window)) || window.setImmediate || function(fnc) {window.setTimeout(fnc, 0);};
})(window, 'r webkitR mozR msR oR'.split(' '), 0);
 nextTick(() => {
   return c( (new Date()).getTime() )  
 })
})

所以我们在1/1000窗口中:

getUniqueID(function(c) { console.log(c); });getUniqueID(function(c) { console.log(c); });
undefined
VM1160:1 1469615416965
VM1160:1 1469615416966

0

甚至更好的方法是使用getTime()或valueOf(),但是通过这种方式,它将返回唯一的加上人类可以理解的数字(代表日期和时间):

window.getUniqNr = function() {
  var now = new Date(); 
  if (typeof window.uniqCounter === 'undefined') window.uniqCounter = 0; 
  window.uniqCounter++; 
  var m = now.getMonth(); var d = now.getDay(); 
  var h = now.getHours(); var i = now.getMinutes(); 
  var s = now.getSeconds(); var ms = now.getMilliseconds();
  timestamp = now.getFullYear().toString() 
  + (m <= 9 ? '0' : '') + m.toString()
  +( d <= 9 ? '0' : '') + d.toString() 
  + (h <= 9 ? '0' : '') + h.toString() 
  + (i <= 9 ? '0' : '') + i.toString() 
  + (s <= 9 ? '0' : '') + s.toString() 
  + (ms <= 9 ? '00' : (ms <= 99 ? '0' : '')) + ms.toString() 
  + window.uniqCounter; 

  return timestamp;
};
window.getUniqNr();

0
let now = new Date();
let timestamp = now.getFullYear().toString();
let month = now.getMonth() + 1;
timestamp += (month < 10 ? '0' : '') + month.toString();
timestamp += (now.getDate() < 10 ? '0' : '') + now.getDate().toString();
timestamp += (now.getHours() < 10 ? '0' : '') + now.getHours().toString();
timestamp += (now.getMinutes() < 10 ? '0' : '') + now.getMinutes().toString();
timestamp += (now.getSeconds() < 10 ? '0' : '') + now.getSeconds().toString();
timestamp += (now.getMilliseconds() < 100 ? '0' : '') + now.getMilliseconds().toString();


0

我已经这样

function uniqeId() {
   var ranDom = Math.floor(new Date().valueOf() * Math.random())
   return _.uniqueId(ranDom);
}

0
function getUniqueNumber() {

    function shuffle(str) {
        var a = str.split("");
        var n = a.length;
        for(var i = n - 1; i > 0; i--) {
            var j = Math.floor(Math.random() * (i + 1));
            var tmp = a[i];
            a[i] = a[j];
            a[j] = tmp;
        }
        return a.join("");
    }
    var str = new Date().getTime() + (Math.random()*999 +1000).toFixed() //string
    return Number.parseInt(shuffle(str));   
}

0

参考上面的#Marcelo Lazaroni解决方案

Date.now() + Math.random()

返回这样的数字,例如1567507511939.4558(限制为4个小数),并且每0.1%将给出非唯一数字(或碰撞)。

添加toString()可解决此问题

Date.now() + Math.random().toString()

返回“ 15675096840820.04510962122198503”(字符串),而且速度太慢,以至于无论如何您都不会得到“相同”毫秒。


0
let uuid = ((new Date().getTime()).toString(36))+'_'+(Date.now() + Math.random().toString()).split('.').join("_")

样本结果“ k3jobnvt_15750033412250_18299601769317408”


0

使用toString(36),速度稍慢,这是更快,更独特的解决方案:

new Date().getUTCMilliseconds().toString() +
"-" +
Date.now() +
"-" +
filename.replace(/\s+/g, "-").toLowerCase()

0

要获得唯一编号:

function getUnique(){
    return new Date().getTime().toString() + window.crypto.getRandomValues(new Uint32Array(1))[0];
}
// or 
function getUniqueNumber(){
    const now = new Date();
    return Number([
        now.getFullYear(),
        now.getMonth(),
        now.getDate(),
        now.getHours(),
        now.getMinutes(),
        now.getUTCMilliseconds(),
        window.crypto.getRandomValues(new Uint8Array(1))[0]
    ].join(""));
}

例:

getUnique()
"15951973277543340653840"

for (let i=0; i<5; i++){
    console.log( getUnique() );
}
15951974746301197061197
15951974746301600673248
15951974746302690320798
15951974746313778184640
1595197474631922766030

getUniqueNumber()
20206201121832230

for (let i=0; i<5; i++){
    console.log( getUniqueNumber() );
}
2020620112149367
2020620112149336
20206201121493240
20206201121493150
20206201121494200

您可以使用以下方法更改长度:

new Uint8Array(1)[0]
// or
new Uint16Array(1)[0]
// or
new Uint32Array(1)[0]

这个问题要求一个唯一的数字,而不是一个随机的字符串。
tshimkus

0

我发现的简单解决方案

今天的var = new Date()。valueOf();

console.log(今天);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.