Створіть унікальний номер із часом JavaScript


95

Мені потрібно генерувати унікальні ідентифікаційні номери на льоту, використовуючи javascript. Раніше я робив це, створюючи число з використанням часу. Число складається з чотиризначного року, двоцифрового місяця, двоцифрового дня, двоцифрової години, двоцифрової хвилини, двоцифрової секунди та трицифрової мілісекунди. Тож це могло б виглядати приблизно так: 20111104103912732 ... це дало б достатню впевненість у унікальному номері для моїх цілей.

Минув деякий час, як я це зробив, і коду вже не маю. Хто-небудь має код для цього або має кращу пропозицію щодо створення унікального ідентифікатора?



Ви роздумували new Date().toISOString ()?
gaspard

Відповіді:


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
@ Аксель: Я не сказав, що це унікально, я сказав, що це "унікально". звичайно, використовуючи відмітку часу, згенеровану на стороні клієнта, буде генеруватися дублювання.
Marc B

78
timestamp має бути числом, new Date().getTime();що date.getUTCMilliseconds()повертає від 0 до 999. date.getTime()повертає мілісекунди з 1 січня 1970 р. (нормальна мітка часу). w3schools.com/jsref/jsref_obj_date.asp
Автоматично7

8
-1, оскільки питання стосувалось унікального числа. Перший блок коду слід повністю пропустити.
Андрій

Це може генерувати 2 унікальні значення:function foo1() {console.log(new Date().getUTCMilliseconds()); console.log(new Date().getUTCMilliseconds()); }
Шаріков Владислав

10
getUTCмілісекунди The value returned by getUTCMilliseconds() is an integer between 0 and 999.. Це найгірша ідея для унікального ідентифікатора, перший абзац слід видалити.
gaspard

116

Кращим підходом було б:

new Date().valueOf();

замість

new Date().getUTCMilliseconds();

valueOf () - це "швидше за все" унікальне число. http://www.w3schools.com/jsref/jsref_valueof_date.asp .


19
Це не унікальне число .. мілісекунд недостатньо детальне, щоб вважати його унікальним.
Вамсі Мохан Джаянті

3
Або просто+new Date()
thdoan

1
Я просто запустив цикл for і отримав дублікати результатів з valueOf(). Я просто використовую це - +performance.now().toString().replace('.', 7) developer.mozilla.org/en-US/docs/Web/API/Performance/now
Itzik Ben Hutta

1
@ItzikBenHutta Отримав 3 рази однакове значення. Використання багатоядерного процесора, ймовірно, гоночний стан з потоками.
той-бен

68

Найкоротший спосіб створити число, у якому ви можете бути впевнені, що буде унікальним серед стільки окремих екземплярів, скільки ви думаєте

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 символів, що є пристойною величиною ентропії. Хоча половина з них передбачувана.
Ерік Пукінськіс

2
Це має бути прийнятою відповіддю, оскільки при спробі інших відповідей з більшим голосуванням я отримував 2 і навіть 3 рази однакове значення поспіль, коли дзвонив із асинхронної функції. Здається, це забезпечує достатньо випадковості для стандартного 8-ядерного процесора, щоб генерувати 8 унікальних рядків точно в той же момент, досить добре для мого використання.
той-бен

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
Дійсно, але це було нормально для роботи: "це дало б достатню впевненість у унікальному номері для моїх цілей".
Серпень Ліллеас,

17

Ось, що я роблю, коли хочу щось менше, ніж купу цифр - міняю базу.

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

1
@blushrt правда, це може спричинити рідкісні зіткнення. Ви могли б md5 відмітити час, використовуючи щось на зразок code.google.com/p/crypto-js , але для моїх цілей це було "досить унікально", і що більш важливо, швидше.
frumbert

@frumbert, це залежить. MD5 також не стійкий до зіткнень. Але у вашому випадку у мене дуже швидко виникли проблеми через toString (36), який, як я припускаю, перетворює числове значення в його представлення ascii, хоча я не впевнений, але я бачу проблему, якщо ви досить часто дзвоните своєму генератору uuid, лише останні 3 символи змінюються, тому великі шанси, що ви зіткнетеся в зіткненні. Якщо ви просто дотримуєтесь нових дзвінків Date.getTime (), ви отримуєте набагато кращі шанси. Але привіт, якщо це спрацювало для ваших цілей, не біда, мені це знадобилося для деяких унікальних ідентифікаторів лише для мого коду на стороні клієнта, в кінцевому підсумку використовуючи uuid node lib.
blushrt

Я люблю цю! Я налаштував його (Date.now() + Math.random()).toString(36)на запобігання мілісекундним зіткненням. Він короткий і генерує щось на зразок "k92g5pux.i36"
Едвард

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

Ви також можете використовувати щось більш складне , наприклад, cuid , puid або shorttid, щоб створити не число.


1
Мені здається, що додавання випадкових чисел насправді зробить це МЕНШЕ повним доказом. Тільки з позначкою часу потрібно було б створити два числа в точно такі ж мілісекунди, щоб бути однаковими. Додавши два випадкові числа, ви завдяки математиці створили безліч комбінацій чисел, які при множенні можуть отримати однаковий результат. Я знаю, що це малоймовірно, але ... чи не так?
Філ

Хм, так. Можливо, найкращим буде поєднання Моєї відповіді та відповіді abarber.
Стівен Вашон

Оновлено мою відповідь. Дякую за думку.
Стівен Вашон,

2
Хороших зусиль, не намагаючись вибирати свою відповідь ... але це нове рішення насправді не вирішує проблему "більше, ніж один ідентифікатор, створений за ту саму мілісекунду", тому що, я знаю ... це javascript, на стороні КЛІЄНТА. Якщо інший користувач створив число за ту саму точну мілісекунду, це не відображатиметься в uniqueNumber.previous для "іншого" користувача. Якщо ви не зберігаєте його десь на сервері і не перевіряєте унікальність ... просто немає можливості, щоб подібне рішення на основі js могло бути впевненим, що воно створює унікальний номер.
Філ

Ну, це була б більш складна система, ніж просто унікальний номер.
Стівен Вашон

12

я використовую

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

Отже, якщо випадково код буде запущений одночасно, існує також маленький шанс, що випадкові числа будуть однаковими.


Не впевнений new Date(), що корисний жорсткий. Ви могли отримати однакові цифри з двома різними датами
JMaylin

1
Я маю на увазі, як це краще, ніж просто робити Math.random()?
JMaylin

7

Це повинно зробити:

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

1
Корисно для багатьох випадків, хоча це насправді не генерує чистих "унікальних" ідентифікаторів, якщо ця функція буде викликана кілька разів за одну і ту ж мілісекунду ... Але в будь-якому випадку для взаємодії користувача та інтерфейсу це добре.
Бенджамін Піетт,

1
це має бути прийнятою відповіддю. Багато безглуздого лайна, яке є складним і непотрібним, і ця відповідь дає унікальний час на кожну мілісекунду.
ген b.

5

якщо ви хочете отримати унікальний номер через кілька мілі секунд, тоді використовуйте Date.now(), якщо ви хочете використовувати його всередині, а 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()

output :: всі числа унікальні

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

Під час розслідування в Інтернеті я придумав такий об’єкт, який створює унікальний ідентифікатор за сеанс:

        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

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

як Uint8Array, так і Crypto.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

Це створює майже гарантований унікальний 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')) // буде складним

Приклад виведення:
для (вар я = 0; I <10; я ++) {console.log (UniqueValue (UniqueValue ( '0')));}
60950116113248802
26780116113248803
53920116113248803
35840116113248803
47430116113248803
41680116113248803
42980116113248804
34750116113248804
20950116113248804
03730116113248804


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випадки зіткнень в цьому інтервалі, ми могли б розглянути можливість використання вбудованого, як ми це чітко бачимо тут у дії:

Тут ми можемо побачити тут, як можуть бути зіткнення у віконній рамі 1/1000 за допомогою (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

По-друге, ми спробуємо запропоноване рішення, яке дозволяє уникнути зіткнень у вікні 1/1000:

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

Тим не менш, ми могли б розглянути можливість використання таких функцій, як вузол, process.nextTickякий викликається у циклі подій як єдиний, tickі це добре пояснено тут . Звичайно, у браузері цього немає, process.nextTickтому ми повинні розібратися, як це зробити. Ця реалізація встановить anextTick функцію в браузері , використовуючи найближчі функції введення / виводу в браузері, які 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

Легко і завжди отримуйте унікальну цінність:

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


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

-1

100% гарантовано генерує інше число ...

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>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.