Crie um número exclusivo com tempo javascript


95

Preciso gerar números de identificação exclusivos em tempo real usando javascript. No passado, eu fiz isso criando um número usando o tempo. O número seria composto de ano de quatro dígitos, mês de dois dígitos, dia de dois dígitos, hora de dois dígitos, minuto de dois dígitos, segundo de dois dígitos e milissegundos de três dígitos. Portanto, seria algo como: 20111104103912732 ... isso daria certeza suficiente de um número exclusivo para meus propósitos.

Já faz um tempo que não faço isso e não tenho mais o código. Alguém tem o código para fazer isso, ou tem uma sugestão melhor para gerar um ID único?



Você já considerou new Date().toISOString ()?
gaspard

Respostas:


66

Se você quer apenas um número único, então

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

obteria um número simples. Mas se precisar da versão legível, você precisará processar um pouco:

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: Eu não disse que é único, disse que é "único". é claro que usar um timestamp gerado no lado do cliente vai gerar enganos.
Marc B,

78
o carimbo de data / hora deve ser new Date().getTime();o date.getUTCMilliseconds()retorna um número entre 0 e 999. date.getTime()retorna milissegundos desde 1º de janeiro de 1970. (carimbo de data / hora normal). w3schools.com/jsref/jsref_obj_date.asp
Automatico

8
-1, já que a pergunta era sobre número único . O primeiro bloco de código deve ser totalmente omitido.
Andrey

Isso pode gerar 2 valores únicos: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.. Esta é a pior ideia para id único, o primeiro parágrafo deve ser removido.
gaspard

116

Uma abordagem melhor seria:

new Date().valueOf();

ao invés de

new Date().getUTCMilliseconds();

valueOf () é "provavelmente" um número exclusivo. http://www.w3schools.com/jsref/jsref_valueof_date.asp .


19
Não é um número exclusivo .. milissegundos não é granular o suficiente para ser considerado exclusivo.
Vamsi Mohan Jayanti

3
Ou simplesmente+new Date()
thdoan

1
Acabei de executar um loop for e obtive resultados duplicados com valueOf(). Acabei de usar isto - +performance.now().toString().replace('.', 7) developer.mozilla.org/en-US/docs/Web/API/Performance/now
Itzik Ben Hutta

1
@ItzikBenHutta Obteve 3 vezes o mesmo valor. Usando CPU multi-core, provavelmente uma condição de corrida com threads.
that-ben

68

O caminho mais curto para criar um número que você pode ter certeza que será único entre tantas instâncias separadas quanto você possa imaginar é

Date.now() + Math.random()

Se houver uma diferença de 1 milissegundo na chamada da função, é 100% garantido gerar um número diferente . Para chamadas de função dentro do mesmo milissegundo, você só deve começar a se preocupar se estiver criando mais do que alguns milhões de números neste mesmo milissegundo, o que não é muito provável.

Para mais informações sobre a probabilidade de obter um número repetido no mesmo milissegundo, consulte https://stackoverflow.com/a/28220928/4617597


7
Além disso, se você quiser manter todos os bits do número aleatório, pode gerá-los separadamente e mesclá-los como strings: new Date (). ValueOf (). ToString (36) + Math.random (). ToString (36) .substr (2) Isso lhe dará uma string alfanumérica de 19 caracteres, que é uma quantidade decente de entropia. Embora metade seja previsível.
Erik Pukinskis

2
Esta deve ser a resposta aceita, pois ao tentar outras respostas votadas mais altas, obtive 2 e até 3 vezes o mesmo valor em uma linha ao chamar de uma função assíncrona. Isso parece fornecer aleatoriedade suficiente para uma CPU de 8 núcleos padrão gerar 8 strings exclusivas exatamente no mesmo momento, boas o suficiente para meu uso.
that-ben

22

Isso pode ser alcançado simplesmente com o seguinte código:

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
e se for chamado duas vezes no mesmo milissegundo?
TBE

1
De fato, mas estava tudo bem para op: "isso daria certeza suficiente de um número único para meus propósitos."
Agosto Lilleaas

17

Aqui está o que eu faço quando quero algo menor do que um monte de números - mudar a base.

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

1
@blushrt true, pode causar confrontos raros. Você poderia md5 o carimbo de data / hora usando algo como code.google.com/p/crypto-js , mas para meus propósitos era "exclusivo o suficiente" e, mais importante, mais rápido.
frumbert

@frumbert, depende. O MD5 também não é resistente a colisões. Mas, no seu caso, tive problemas muito rápido por causa de toString (36) que suponho que converte o valor numérico em sua representação ascii, mas não tenho certeza, mas posso ver o problema, se você chamar seu gerador de uuid com frequência, os últimos 3 os caracteres estão mudando, então há grandes chances de você entrar em uma colisão. Você obtém chances muito melhores se apenas se limitar a novas chamadas Date.getTime (). Mas ei, se funcionou para seus propósitos, não há problema, eu precisava disso para alguns ids exclusivos apenas para o meu código do lado do cliente, acabei usando uuid node lib.
blushrt

Eu amo este! Eu ajustei (Date.now() + Math.random()).toString(36)para evitar confrontos de milissegundos. É curto e gera algo como "k92g5pux.i36"
Edward

16

Isso é executado mais rápido do que criar uma Dateinstância, usa menos código e sempre produzirá um número exclusivo (localmente):

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/

Eu lancei isso no Bower e npm: https://github.com/stevenvachon/unique-number

Você também pode usar algo mais elaborado como cuid , puid ou shortid para gerar um não-número.


1
Parece-me que somar os números aleatórios tornaria MENOS uma prova completa. Com apenas o carimbo de hora, dois números teriam que ser criados no mesmo milissegundo para serem iguais. Ao adicionar dois números aleatórios, você criou muitas combinações de números, devido à matemática, que podem terminar com o mesmo resultado quando multiplicadas. Eu sei que é improvável, mas ... não é certo?
Phil

Hmm, sim. Talvez uma combinação de Minha resposta e a resposta de abarber seja melhor.
Steven Vachon

Atualizei minha resposta. Obrigado pelo pensamento.
Steven Vachon

2
Bom esforço, não estou tentando pegar sua resposta ... mas esta nova solução não resolve o problema de "mais de um id criado no mesmo milissegundo" porque, você sabe ... é javascript, do lado do CLIENTE. Se um usuário diferente criasse um número no mesmo milissegundo exato, ele não seria refletido em uniqueNumber.previous do 'outro' usuário. A menos que você o armazene em algum lugar do servidor e verifique se há exclusividade ... simplesmente não há como uma solução puramente baseada em js como essa pode ter certeza de que está criando um número exclusivo.
Phil

Bem, isso seria um sistema mais elaborado do que apenas um número único.
Steven Vachon

12

eu uso

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

Portanto, se por acaso o código for disparado ao mesmo tempo, também haverá uma chance mínima de que os números aleatórios sejam os mesmos.


Não tenho certeza se new Date()é difícil útil. Você pode obter os mesmos números com duas datas diferentes
JMaylin

1
Quero dizer, como é melhor do que simplesmente fazer Math.random()?
JMaylin

7

Isso deve fazer:

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

1
Útil para muitos casos, embora isso realmente não gere ids "únicos" puros, caso essa função seja chamada várias vezes no mesmo milissegundo ... Mas de qualquer maneira, para a interação do usuário e da IU, isso é bom.
Benjamin Piette

1
esta deve ser a resposta aceita. Muita porcaria irrelevante que é difícil e desnecessária, e essa resposta fornece um tempo único a cada milissegundo.
gene b.

5

se você quiser um número único depois de alguns milis segundos, use Date.now(), se quiser usá-lo dentro de um for loop, use em Date.now() and Math.random()conjunto

número único dentro de um loop for

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

saída: todos os números são únicos

15598251485988384 155982514859810330 155982514859860737 155982514859882244 155982514859883316

número único sem Math.random()

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

saída :: Números são repetidos

1559825328327 1559825328327 1559825328327 1559825328328 1559825328328


4

Investigando online, descobri o seguinte objeto que cria um id único por sessão:

        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 + '.');
            }
        }            
    }

Pode ser útil para algumas pessoas.

Felicidades

Andrew


esta é a solução mais simples e à prova de erros até agora sobre esta questão. Eu tentei uma solução diferente (veja abaixo), mas ainda tenho algumas preocupações sobre ela que precisam ser desenvolvidas.
Loretoparisi

3

Isso também deve fazer:

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

Implementação muito semelhante que você pode encontrar na função lodash UniqueId, para mim, sua solução é simples e limpa.
Kamil Naja

3

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

Exemplo:

 > uniqueID()
 > "bxppcnanpuxzpyewttifptbklkurvvetigra"

2

Sempre obtenha ID único em JS

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

getUniqueId()    // Call the function

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

//"ka2high4264"

//"ka2hj115905"

//"ka2hj1my690"

//"ka2hj23j287"

//"ka2hj2jp869"

2

Em 2020, você pode usar a API Crypto no navegador para gerar valores aleatórios criptograficamente fortes.

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

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

tanto Uint8Array e Crypto.getRandomValues são suportados em todos os principais navegadores, incluindo IE11


1

Postando este snippet de código aqui para minha própria referência futura (não garantido, mas satisfatório "exclusivo" o suficiente):

// 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

Isso cria um lado do cliente chave exclusivo quase garantido de 32 caracteres, se você quiser apenas números, altere a var "chars".

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

use isto: para criar um número único em javascript

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

Realmente funciona. :)


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;
    }

Chamada 1: UniqueValue ('0')
Chamada 2: UniqueValue (UniqueValue ('0')) // será complexo

Exemplo de saída:
para (var i = 0; i <10; i ++) {console.log (UniqueValue (UniqueValue ( '0')));}
60950116113248802
26780116113248803
53920116113248803
35840116113248803
47430116113248803
41680116113248803
42980116113248804
34750116113248804
20950116113248804
03730116113248804


1

Uma vez que os milissegundos não são atualizados a cada milissegundo no nó, a seguir está uma resposta. Isso gera um número de tíquete legível exclusivo. Eu sou novo em programação e nodejs. Por favor corrija-me se eu estiver errado.

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

Assumindo que a solução proposta por @abarber é uma boa solução porque usa (new Date()).getTime()por isso tem janelas de milissegundos e soma a tickem caso de colisões neste intervalo, poderíamos considerar o uso de built-in como podemos ver claramente aqui em ação:

Em primeiro lugar, podemos ver aqui como pode haver colisões na moldura da janela 1/1000 usando (new Date()).getTime():

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

Em segundo lugar, tentamos a solução proposta que evita colisões na janela 1/1000:

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

Dito isso, poderíamos considerar o uso de funções como o nó process.nextTickque é chamado no loop de eventos como um único ticke está bem explicado aqui . É claro que no navegador não existe, process.nextTickentão temos que descobrir como fazer isso. Esta aplicação irá instalar uma nextTickfunção no navegador usando as funções mais mais perto do I / O no navegador que são setTimeout(fnc,0), setImmediate(fnc), window.requestAnimationFrame. Como sugerido aqui , poderíamos adicionar o window.postMessage, mas deixo isso para o leitor, pois ele também precisa de um addEventListener. Modifiquei as versões originais do módulo para mantê-lo mais simples aqui:

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

Portanto, temos na janela 1/1000:

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

0

Talvez ainda melhor seria usar getTime () ou valueOf (), mas dessa forma ele retorna um número único mais compreensível por humanos (representando data e hora):

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

Fácil e sempre obtenha um valor único:

const uniqueValue = (new Date()).getTime() + Math.trunc(365 * Math.random());
**OUTPUT LIKE THIS** : 1556782842762

0

Eu tenho feito assim

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

em referência à solução #Marcelo Lazaroni acima

Date.now() + Math.random()

retorna um número como este 1567507511939.4558 (limitado a 4 decimais) e fornecerá números não exclusivos (ou colisões) a cada 0,1%.

adicionar toString () corrige isso

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

retorna '15675096840820.04510962122198503' (uma string) e é tão 'lento' que você nunca obtém o 'mesmo' milissegundo, de qualquer maneira.


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

resultado de amostra "k3jobnvt_15750033412250_18299601769317408"


0

Usando toString(36), ligeiramente lento, aqui está a solução mais rápida e exclusiva:

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

0

Para obter um número único:

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(""));
}

Exemplo:

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

você pode alterar o comprimento usando:

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

A pergunta pedia um número único , não uma string aleatória.
tshimkus

-1

100% garantido para gerar um número diferente ...

var Q;
Q = {};
Q.timeInterval;

function genUniqueID(kol) {
	Q.timeInterval = setTimeout(function() {
		document.querySelector('#demo').innerHTML += new Date().valueOf() + '<br>';
		kol--;
		if (kol > 0) {
			genUniqueID(kol);
		}
	}, document.querySelector('#i2').value);
}
<div><input id="i1" type="number" value="5" style="width: 60px;"><label> - Amount</label><br>
    <input id="i2" type="number" value="10" style="width: 60px;"><label> - Millisecond interval</label></div><br>
<div>
    <button onclick="genUniqueID(document.querySelector('#i1').value);">Start</button>
    <button onclick="clearTimeout(Q.timeInterval);">Stop</button>
    <button onclick="document.querySelector('#demo').innerHTML = ''">Clear</button>
</div><br>
<div id="demo"></div>

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.