Crea un número único con tiempo de javascript


95

Necesito generar números de identificación únicos sobre la marcha usando javascript. En el pasado, hice esto creando un número usando el tiempo. El número estaría compuesto por el año de cuatro dígitos, el mes de dos dígitos, el día de dos dígitos, la hora de dos dígitos, el minuto de dos dígitos, el segundo de dos dígitos y el milisegundo de tres dígitos. Entonces se vería algo así: 20111104103912732 ... esto daría suficiente certeza de un número único para mis propósitos.

Ha pasado un tiempo desde que hice esto y ya no tengo el código. ¿Alguien tiene el código para hacer esto o tiene una sugerencia mejor para generar una identificación única?



¿Lo has considerado new Date().toISOString ()?
gaspard

Respuestas:


66

Si solo desea un número único, entonces

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

le daría un número simple. Pero si necesita la versión legible, le espera un poco de procesamiento:

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: No dije que sea único, dije que es "único". Por supuesto, usar una marca de tiempo generada en el lado del cliente generará engaños.
Marc B

78
La marca de tiempo debe ser new Date().getTime();el que date.getUTCMilliseconds()devuelve un número entre 0 y 999. date.getTime()Devuelve milisegundos desde el 1 de enero de 1970 (marca de tiempo normal). w3schools.com/jsref/jsref_obj_date.asp
Automatico

8
-1, ya que la pregunta era sobre un número único . El primer bloque de código debe omitirse por completo.
Andrey

Esto puede generar 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 es la peor idea para una identificación única, el primer párrafo debe eliminarse.
Gaspard

116

Un mejor enfoque sería:

new Date().valueOf();

en vez de

new Date().getUTCMilliseconds();

valueOf () es "muy probablemente" un número único. http://www.w3schools.com/jsref/jsref_valueof_date.asp .


19
No es un número único. Los milisegundos no son lo suficientemente detallados para ser considerados únicos.
Vamsi Mohan Jayanti

3
O simplemente+new Date()
thdoan

1
Acabo de ejecutar un bucle for y obtuve resultados duplicados con valueOf(). Solo uso esto: +performance.now().toString().replace('.', 7) developer.mozilla.org/en-US/docs/Web/API/Performance/now
Itzik Ben Hutta

1
@ItzikBenHutta Obtuve 3 veces el mismo valor. Usando CPU de múltiples núcleos, probablemente una condición de carrera con subprocesos.
that-ben

68

La forma más corta de crear un número del que puede estar bastante seguro será único entre tantas instancias separadas como pueda imaginar es

Date.now() + Math.random()

Si hay una diferencia de 1 milisegundo en la llamada de función, está 100% garantizado para generar un número diferente . Para llamadas de función dentro del mismo milisegundo, solo debería comenzar a preocuparse si está creando más de unos pocos millones de números dentro de este mismo milisegundo, lo cual no es muy probable.

Para obtener más información sobre la probabilidad de obtener un número repetido en el mismo milisegundo, consulte https://stackoverflow.com/a/28220928/4617597


7
Además, si desea conservar todos los bits del número aleatorio, puede generarlos por separado y fusionarlos como cadenas: new Date (). ValueOf (). ToString (36) + Math.random (). ToString (36) .substr (2) Eso le dará una cadena alfanumérica de 19 caracteres que es una cantidad decente de entropía. Aunque la mitad es predecible.
Erik Pukinskis

2
Esta debería ser la respuesta aceptada, ya que al probar otras respuestas con más votos, obtuve 2 e incluso 3 veces el mismo valor en una fila cuando llamo desde una función asíncrona. Esto parece proporcionar suficiente aleatoriedad para que una CPU estándar de 8 núcleos genere 8 cadenas únicas exactamente en el mismo momento, lo suficientemente bueno para mi uso.
that-ben

22

Esto se puede lograr simplemente con el siguiente 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
¿Qué pasa si esto se llama dos veces en el mismo milisegundo?
TBE

1
De hecho, pero estaba bien para la operación: "esto daría suficiente certeza de un número único para mis propósitos".
Agosto Lilleaas

17

Esto es lo que hago cuando quiero algo más pequeño que un montón de números: cambiar de base.

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

1
@blushrt cierto, puede causar choques raros. Podrías md5 en la marca de tiempo usando algo como code.google.com/p/crypto-js , pero para mis propósitos era "suficientemente único" y, lo que es más importante, más rápido.
frumbert

@frumbert, depende. El MD5 tampoco es resistente a colisiones. Pero en su caso, me metí en problemas muy rápido debido a toString (36) que supongo que convierte el valor numérico en su representación ascii, aunque no estoy seguro, pero puedo ver el problema, si llama a su generador de uuid con suficiente frecuencia, solo los últimos 3 Los caracteres cambian, por lo que es muy probable que se produzca una colisión. Obtienes mejores probabilidades si te limitas a las nuevas llamadas Date.getTime (). Pero bueno, si funcionó para sus propósitos, no hay problema, lo necesitaba para algunos identificadores únicos solo para mi código del lado del cliente, terminé usando uuid node lib.
blushrt

¡Amo esto! Lo he ajustado (Date.now() + Math.random()).toString(36)para evitar choques de milisegundos. Es breve y genera algo como "k92g5pux.i36"
Edward

16

Esto funciona más rápido que crear una Dateinstancia, usa menos código y siempre producirá un número único (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/

He publicado esto en Bower y npm: https://github.com/stevenvachon/unique-number

También puede usar algo más elaborado como cuid , puid o shortid para generar un no número.


1
Me parece que agregar los números aleatorios en realidad lo haría MENOS prueba completa. Con solo la marca de tiempo, dos números tendrían que crearse exactamente en el mismo milisegundo para que sean iguales. Al agregar dos números aleatorios, ahora ha creado muchas combinaciones de números, debido a las matemáticas, que podrían terminar con el mismo resultado cuando se multiplican. Sé que es poco probable, pero ... ¿no es así?
Phil

Hmm si. Quizás una combinación de Mi respuesta y la respuesta de abarber sería lo mejor.
Steven Vachon

Actualicé mi respuesta. Gracias por pensar
Steven Vachon

2
Buen esfuerzo, no intentar elegir su respuesta ... pero esta nueva solución en realidad no resuelve el problema de "más de una identificación creada en el mismo milisegundo" porque, ya sabes ... es javascript, del lado del CLIENTE. Si un usuario diferente creara un número en el mismo milisegundo exacto, no se reflejaría en uniqueNumber.previous del 'otro' usuario. A menos que lo almacene en el servidor en algún lugar y verifique la singularidad ... simplemente no hay forma de que una solución puramente basada en js como esta pueda estar segura de que está creando un número único.
Phil

Bueno, ese sería un sistema más elaborado que solo un número único.
Steven Vachon

12

yo suelo

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

Entonces, si por casualidad el código se dispara al mismo tiempo, también hay una pequeña posibilidad de que los números aleatorios sean los mismos.


No estoy seguro si new Date()es útil. Puede obtener los mismos números con dos fechas diferentes
JMaylin

1
Quiero decir, ¿cómo es mejor que simplemente hacer Math.random()?
JMaylin

7

Esto debería hacer:

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

1
Útil para muchos casos, aunque esto realmente no genera identificadores "únicos" puros, en caso de que esta función se llame varias veces en el mismo milisegundo ... Pero de todos modos, para la interacción del usuario y la interfaz de usuario, eso es bueno.
Benjamin Piette

1
esta debería ser la respuesta aceptada. Mucha basura irrelevante que es difícil e innecesaria, y esta respuesta da un tiempo único por cada milisegundo.
gen b.

5

si desea un número único después de unos mili segundos, úselo Date.now(), si desea usarlo dentro de un for loop, úselo Date.now() and Math.random()juntos

número único dentro de un bucle for

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

salida :: todos los números son únicos

15598251485988384 155982514859810330 155982514859860737 155982514859882244 155982514859883316

número único sin Math.random()

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

salida :: Los números se repiten

1559825328327 1559825328327 1559825328327 1559825328328 1559825328328


4

Al investigar en línea, se me ocurrió el siguiente objeto que crea una identificación única por sesión:

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

Quizás sea útil para algunas personas.

Salud

Andrés


esta es la solución más simple y a prueba de errores hasta la fecha sobre esta pregunta. Probé una solución diferente (ver más abajo), pero todavía tengo algunas preocupaciones al respecto que necesitan un mayor desarrollo.
loretoparisi

3

Esto también debería hacer:

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

Implementación muy similar que puede encontrar en la función UniqueId de lodash, para mí, su solución es simple y limpia.
Kamil Naja

3

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

Ejemplo:

 > uniqueID()
 > "bxppcnanpuxzpyewttifptbklkurvvetigra"

2

Obtenga siempre una identificación única en JS

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

getUniqueId()    // Call the function

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

//"ka2high4264"

//"ka2hj115905"

//"ka2hj1my690"

//"ka2hj23j287"

//"ka2hj2jp869"

2

En 2020, puede utilizar la API de cifrado en el navegador para generar valores aleatorios criptográficamente fuertes.

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

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

tanto Uint8Array como Crypto.getRandomValues son compatibles con los principales navegadores, incluido IE11


1

Publicando este fragmento de código aquí para mi propia referencia futura (no garantizado, pero suficientemente "único" satisfactorio):

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

Esto crea un lado del cliente clave único casi garantizado de 32 caracteres, si solo desea que los números cambien la 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 esto: para crear un número único en 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;
    }

Llamada 1: UniqueValue ('0')
Llamada 2: UniqueValue (UniqueValue ('0')) // será compleja

Salida de muestra:
for (var i = 0; i <10; i ++) {console.log (UniqueValue (UniqueValue ( '0')));}
60950116113248802
26780116113248803
53920116113248803
35840116113248803
47430116113248803
41680116113248803
42980116113248804
34750116113248804
20950116113248804
03730116113248804


1

Dado que los milisegundos no se actualizan cada milisegundo en el nodo, la siguiente es una respuesta. Esto genera un número de ticket único legible por humanos. Soy nuevo en programación y nodejs. Por favor, corríjame si estoy equivocado.

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

Suponiendo que la solución propuesta por @abarber es una buena solución porque usa (new Date()).getTime()por lo que tiene ventanas de milisegundos y suma a ticken caso de colisiones en este intervalo, podríamos considerar el uso de built-in como podemos ver claramente aquí en acción:

Primero, podemos ver aquí cómo puede haber colisiones en el marco de la ventana 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

En segundo lugar, probamos la solución propuesta que evita colisiones en la ventana 1/1000:

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

Dicho esto, podríamos considerar usar funciones como el nodo process.nextTickque se llama en el bucle de eventos como un solo ticky está bien explicado aquí . Por supuesto, en el navegador no hay, process.nextTickasí que tenemos que averiguar cómo hacerlo. Esta aplicación se instalará una nextTickfunción en el navegador usando las mayoría de las funciones más cerca de la E / S en el navegador que son setTimeout(fnc,0), setImmediate(fnc), window.requestAnimationFrame. Como se sugiere aquí , podríamos agregar el window.postMessage, pero se lo dejo al lector ya que también necesita un addEventListener. He modificado las versiones originales del módulo para que sea más simple aquí:

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

Entonces tenemos en la ventana 1/1000:

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

0

Quizás incluso mejor sería usar getTime () o valueOf (), pero de esta manera devuelve un número único más comprensible para humanos (que representa la fecha y la 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 y siempre obtenga un valor único:

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

0

Lo he hecho de esta manera

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

en referencia a la solución #Marcelo Lazaroni anterior

Date.now() + Math.random()

devuelve un número como este 1567507511939.4558 (limitado a 4 decimales) y dará números no únicos (o colisiones) cada 0,1%.

agregar toString () corrige esto

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

devuelve '15675096840820.04510962122198503' (una cadena), y es además tan 'lento' que nunca obtienes el 'mismo' milisegundo, de todos modos.


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

resultado de muestra "k3jobnvt_15750033412250_18299601769317408"


0

Usando toString(36), un poco lento, aquí está la solución más rápida y única:

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

0

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

Ejemplo:

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

puedes cambiar la longitud usando:

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

La pregunta pedía un número único , no una cadena aleatoria.
tshimkus

-1

100% garantizado para generar un 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>

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.