How to check if the date is included in holidays? - javascript

i want to exclude the holiday dates from two selected dates ,
i have write the code , by checking if the range between start date and end date is included in holiday array then make the total days -1 . but is not working , so how i can do it
this is my code
const workday_count = (start: moment.Moment, end: moment.Moment, publicHolidays: Date[]) => {
const first = start.clone().endOf('week');
const last = end.clone().startOf('week');
const days = (last.diff(first, 'days') * 5) / 7;
let wfirst = first.day() - start.day();
const sta = start.toDate();
const en = end.toDate();
const range = enumerateDaysBetweenDates(sta, en);
if (start.day() === 6) --wfirst;
let wlast = end.day() - last.day();
if (end.day() === 5) --wlast;
const withOutWeekend = wfirst + Math.floor(days) + wlast;
const count = 0;
range.forEach((date) => {
if (publicHolidays.includes(date)) {
return count + 1;
}
});
return withOutWeekend;
};

it seems publicHolidays.includes(date) will always return false, so you can try publicHolidays.find() to check if date in this range
when the start day is Sunday(start.day() === 0), your wfirst would be 5 instead of 6
when the end day is Saturday(end.day() === 6), your wlast would be 5 instead of 6
Here is the code:
const workday_count = (start, end, publicHolidays) => {
const first = start.clone().endOf("week");
const last = end.clone().startOf("week");
const days = (last.diff(first, "days") * 5) / 7;
let wfirst = first.day() - start.day();
// when start is Sunday
if (start.day() === 0) --wfirst;
let wlast = end.day() - last.day();
// when end is Saturday
if (end.day() === 6) --wlast;
const sta = start.toDate();
const en = end.toDate();
const range = enumerateDaysBetweenDates(sta, en);
let withOutWeekend = wfirst + Math.floor(days) + wlast;
let count = 0;
range.forEach((date) => {
// check if the date is in publicHolidays
if (
publicHolidays.find((holiday) => holiday.getTime() === date.getTime())
) {
count++;
}
});
return withOutWeekend - count;
};
BTW, I think you can describe more detailed in your question about how is your code not working, so that we can have a better understanding of the problem. :)

Related

Extracting monthly values from data with irregular dates

I have bunch of electricity meter readings which have irregular dates. See below :
ReadingDate Meter
19/01/2021 5270
06/03/2021 5915
11/05/2021 6792
08/07/2021 7367
9/9/2021 8095
8/11/2021 8849
02/12/2021 9065
17/01/2022 9950
Now I'd like to transform this into monthly readings, using just this data, to end up with a table like this
Month Usage
2021-01 452
2021-02 393
2021-03 416
2021-04 399
2021-05 341
2021-06 297
2021-07 347
2021-08 358
2021-09 369
2021-10 389
2021-11 295
2021-12 586
2022-01 308
Now, I have a working solution, but I'm sure there's a more beautiful concise way of doing it.
What I do is to create an intermediate array that has one line for each date between first and last meter readings.
Each item in the array has 3 values :
the date
the average value for that date (calculated by counting the days between meter readings and dividing that by change in the meter.
the corresponding month
The last step then is to loop over this intermediate array and sum the values for each different month.
Here's the working code (its taken from Google Apps Script so please ignore the spreadsheet specific stuff:
var DailyAveragesArray = [['Date','Usage','Month']];
var monthlyObject = {};
var monthlyArray = [['Month','Usage']];
function calculateAverageDailyFigures() {
// give indices for the useful columns, 0 numbered
var ReadingDateColumn = 0;
var MeterReading = 1;
// Read into an array
var MeterReadingData = ss.getDataRange().getValues() // Get array of values
const sortedReadings = MeterReadingData.slice(1).sort((a, b) => a[0] - b[0]);
// from https://flaviocopes.com/how-to-sort-array-by-date-javascript/
// First calculate the number of days and average daily figure for each row
// Note we don't do this for the last row
for(i=0; i < sortedReadings.length - 1 ; i++){
var NumberOfDays = (sortedReadings[i+1][0] - sortedReadings[i][0])/(1000*3600*24);
sortedReadings[i].push(NumberOfDays);
var MeterDifference = sortedReadings[i+1][1] - sortedReadings[i][1];
var AverageDailyFigure = MeterDifference/NumberOfDays;
sortedReadings[i].push(AverageDailyFigure);
}
BuildDailyArray(sortedReadings);
}
function BuildDailyArray(sortedReadings){
// For each row in sorted , loop from the date to the next date-1 and create columns date and Usage
for(i=0; i<sortedReadings.length -1 ;i++){
for (var d = sortedReadings[i][0]; d < sortedReadings[i+1][0]; d.setDate(d.getDate() + 1)) {
var newDate = new Date(d);
var month = newDate.getFullYear() + '-' + ('0' + (newDate.getMonth() + 1)).slice(-2);
DailyAveragesArray.push([newDate,sortedReadings[i][3],month]);
// Check if the month is in the object and add value, otherwise create object an add value
if(month in monthlyObject){
monthlyObject[month] = monthlyObject[month] + sortedReadings[i][3];
} else {
Logger.log('Didnt find month so create it');
monthlyObject[month] = sortedReadings[i][3];
}
}
}
Logger.log(DailyAveragesArray.length);
Logger.log(monthlyObject);
var DailyUsageData = ss.getRange('D1:F'+DailyAveragesArray.length);
DailyUsageData.setValues(DailyAveragesArray);
BuildMonthlyArray();
}
function BuildMonthlyArray(){
const keys = Object.keys(monthlyObject);
Logger.log(keys);
keys.forEach((key, index) => {
monthlyArray.push([key,Math.round(monthlyObject[key])]);
});
var MonthlyUsageData = ss.getRange('H1:I'+monthlyArray.length);
MonthlyUsageData.setValues(monthlyArray);
}
So, my question is, how would I do this nicer, more beautifully, not so verbose ?
I'm not sure what the correct term is for what I want to do. I don't think it's resampling .
I'd appreciate any comments.
Thanks / Colm
Here is my shot on this.
The way i'm doing it:
Initializing all days and its value
Grouping by month
Calculating the average per month
Explanation a bit more precise
initDateFromString
The method initDateFromString takes a dates with the format DD/MM/YYYY and return the associated js date object
initAllDates
The method initAllDates will split the data into day and add the average value of the difference for each day
for example, for the first two readings, it will result to an array of dates looking like :
date
value
19/01/2021
14.02
20/01/2021
14.02
....
....
05/03/2021
14.02
06/03/2021
14.02
The value 14.02 comme from the following calcul :
(newReadingMeter - oldReadingMeter)/nbDaysBetweenDates
Which in this example is (5915 - 5270)/46 = 14.02
joinToMonth
The joinToMonth method will then group the days into month with all the days value summed !
const data = [{
ReadingDate: '19/01/2021',
Meter: 5270
},
{
ReadingDate: '06/03/2021',
Meter: 5915
},
{
ReadingDate: '11/05/2021',
Meter: 6792
},
{
ReadingDate: '08/07/2021',
Meter: 7367
},
{
ReadingDate: '9/9/2021',
Meter: 8095
},
{
ReadingDate: '8/11/2021',
Meter: 8849
},
{
ReadingDate: '02/12/2021',
Meter: 9065
},
{
ReadingDate: '17/01/2022',
Meter: 9950
}
]
function initDateFromString(dateString){
let dateParts = dateString.split("/");
return new Date(+dateParts[2], dateParts[1] - 1, +dateParts[0]);
}
function initAllDates(data){
let dates = []
let currentValue = data.shift()
const currentDate = initDateFromString(currentValue.ReadingDate)
data.forEach(metric => {
const date = initDateFromString(metric.ReadingDate)
const newDates = []
while(currentDate < date){
newDates.push({date: new Date(currentDate)})
currentDate.setDate(currentDate.getDate() + 1)
}
dates = dates.concat(newDates.map(x => {
return {Usage: (metric.Meter - currentValue.Meter) / newDates.length, date: x.date}}
))
currentDate.setDate(date.getDate())
currentValue = metric
})
return dates
}
function joinToMonth(dates){
return dates.reduce((months, day) => {
const month = day.date.getMonth()
const year = day.date.getFullYear()
const existingObject = months.find(x => x.month === month && x.year === year)
if (existingObject) {
existingObject.total += day.Usage
} else {
months.push({
month: day.date.getMonth(),
year: day.date.getFullYear(),
total: day.Usage,
})
}
return months;
}, []);
}
const dates = initAllDates(data)
const joinedData = joinToMonth(dates)
console.log(joinedData)

Keep count of read for each month in array of object

Suppose I have an array of object as:
const sampleArray = [{"read":true,"readDate":2021-01-15T18:21:34.059Z},
{"read":true,"readDate":2021-01-15T18:21:34.059Z},
{"read":true,"readDate":2021-02-15T18:21:34.059Z},
{"read":true,"readDate":2021-04-15T18:21:34.059Z},
{"read":true,"readDate":2021-12-15T18:21:34.059Z}]
I want to keep count of read for each month and where the month is missing it should give 0.
Expected O/P :
[2,1,0,1,0,0,0,0,0,0,0,12] => In jan -2 count, feb - 1 count, april - 1 count, dec - 1 count and rest months there is no read data.
For this I tried :
let invoiceInfoArray = [];
var d = new Date();
var n = d.getMonth();
for (let i = 0; i < sampleArray.length; i++) {
if (sampleArray[i].readDate.getMonth() + 1 == n) {
invoiceInfoArray.push(invoiceInfo[i])
}
}
Also I thought as if I check for each condition but this will also not be feasible as it will check for particular month and if not available it will automatically insert 0 for rest which is incorrect,
for (let i = 0; i < sampleArray.length; i++) {
if (sampleArray[i].readDate.getMonth() + 1 == 1) {
invoiceInfoArray.push(invoiceInfo[i])
} else if (sampleArray[i].readDate.getMonth() + 1 != 1) {
invoiceInfoArray.push(0)
} else if (sampleArray[i].readDate.getMonth() + 1 == 2) {
invoiceInfoArray.push(invoiceInfo[i])
} else if (sampleArray[i].readDate.getMonth() + 1 != 2) {
invoiceInfoArray.push(0)
}
}
I'm unable to form logic on how I can achieve my target such that I want to keep count of read for each month and where the month is missing it should give 0.
Expected O/P :
[2,1,0,1,0,0,0,0,0,0,0,1] => In jan -2 count, feb - 1 count, april - 1 count, dec - 1 count and rest months there is no read data.
Please let me know if anyone needs any further details. Any guidance will really be helpful.
Create a new array of 12 length and make the readDate as a Date object and get the month from getMonth.
You can create a new array with 12elements and prefilled with 0 as
const months = Array(12).fill(0);
// or
const months = new Array(12).fill(0);
read about Array, fill
const sampleArray = [{
read: true,
readDate: "2021-01-15T18:21:34.059Z"
},
{
read: true,
readDate: "2021-01-15T18:21:34.059Z"
},
{
read: true,
readDate: "2021-02-15T18:21:34.059Z"
},
{
read: true,
readDate: "2021-04-15T18:21:34.059Z"
},
{
read: true,
readDate: "2021-12-15T18:21:34.059Z"
},
];
const months = Array(12).fill(0);
// or
// const months = new Array(12).fill(0);
sampleArray.forEach((obj) => {
const month = new Date(obj.readDate).getMonth();
++months[month];
});
console.log(months);

Search for closest date in dates array

I have a dates array in javascript
I want to search for a date and I dont expect it to be there
but I want to get the most closest date to it
so how can I do this ?
function search_date(date) {
var m = 1;
var dateFound;
var xdate = function (m) {
mh.data.find(function (d) {
if (Math.abs((new Date(d.x)).getTime() - date.getTime()) <= 30) {
return d;
} else {
if ((new Date(d.x)).getMinutes() - date.getMinutes() <= m) {
if (Math.abs((new Date(d.x)).getSeconds() - date.getSeconds()) <= 30)
return d;
}
}
});
};
var found = false;
while(!found){
if (xdate(m) != undefined){
dateFound = xdate(m);
break;
}else{
m++;
}
}
console.log(dateFound);
}
One possibility is to break this down into some reusable parts. We need to be able to calculate the difference in two dates, and we need to be able to find the minimum value of an array based on some calculation (in this case the difference from our target date.)
Here's an approach which does that:
const dates = [new Date("2018-02-18T20:24:33.000Z"), new Date("2018-02-18T20:45:02.000Z"), new Date("2018-02-18T21:22:50.000Z"), new Date("2018-02-18T22:06:31.000Z"), new Date("2018-02-18T22:47:18.000Z")]
const timeDiff = (first) => (second) => Math.abs(first - second)
const minBy = (fn, list) => list.reduce(
({d, val}, item) => fn(item) < d ? {val: item, d: fn(item)} : {d, val},
{d: Infinity, val: null}
).val
const closestDate = (dates) => (testDate) => minBy(timeDiff(testDate), dates)
console.log(closestDate(dates)(new Date('2018-02-18T16:52:35')))

How to distinguish time from am and pm in the value of a variable?

I have the following values.
var list = "09:05, 10:05, 12:30, 16:30 , ... , ..."
The type of values ​​in the list is a regular string, not an object.
Based on this value, I want to divide from 0 to 12 am and from 13 to 23 pm.
Therefore, the result I want is as follows.(If you check the log value)
var am = am 09:05 , am 10:05
var pm = pm 12:30 , pm 16:30
It may be a simple question, but it is a very difficult problem for me as a script novice.
Please help me.
Create a sort function first
var sort = ( a, b ) => convertToMin( a ) - convertToMin( b );
var convertToMin = ( a ) => ( items = a.split( ":" ).map( Number ), items[ 0 ] * 60 + items[ 1 ] );
Now use reduce to segregate the array
var output = list.reduce( (a,b) => //using reduce to iterate, a is the accumulator and b is item in array for current iteration
( convertToMin(b) > 12*60 ? a.pm.push( b ) : a.am.push( b ), a ) ,
{ am :[], pm : [] }) ; //accumulator is initialized to { am :[], pm : [] }
output.am.sort( sort );
output.pm.sort( sort );
Demo
var list = ["09:05", "10:05", "12:30", "16:30"];
var sort = (a, b) => convertToMin(a) - convertToMin(b);
var convertToMin = (a) => (items = a.split(":").map(Number), items[0] * 60 + items[1]);
var output = list.reduce((a, b) =>
(convertToMin(b) > 12 * 60 ? a.pm.push(b) : a.am.push(b), a), {
am: [],
pm: []
});
output.am.sort(sort);
output.pm.sort(sort);
console.log(output);
Here's what I'd do to solve this problem.
Separate the values in the string into an array. I'd Google javascript split string into array. Nothing wrong with Googling stuff; even seasoned devs have to do it all the time! At least I do. :)
Then create a for loop that goes through each element of the array. A good search for how to do that is javascript for loop array.
Then for each element, split the string again (this time by the :).
Then convert the first part into a number (javascript convert string
to integer) and see whether it is bigger or smaller than 12.
You could adjusted value with am/pm time and sort it to the wanted array.
function format(v) { return ('0' + v).slice(-2); }
function getM(t) {
var v = t.split(':');
return (v[0] < 12 ? 'am' : 'pm') + ' ' + [v[0] % 12 || 12, v[1]].map(format).join(':');
}
var list = '09:05, 10:05, 12:30, 16:30',
am = [],
pm = []
result = { am: am, pm: pm };
list
.split(', ')
.map(getM)
.forEach(function (s) {
result[s.slice(0, 2)].push(s);
});
console.log(am);
console.log(pm);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Split the items using the appropriate separator, process them with a cycle then join them with the appropriate separator
var items = list.split(", ");
var ams = [];
var pms = [];
for (var index = 0; index < list.length; index++) {
var isPM = ((list[index].substring(0, 2) >= 12);
var currentArray = window[isPM ? "pms" : "ams"];
var found = false;
var val = (isPM ? "pm" : "am") + " " + items[index];
for (var innerIndex = 0; (!found) && (innerIndex < currentArray.length); innerIndex++) {
if (currentArray[innerIndex] > val) {
found = true;
currentArray.splice(innerIndex, 0, val);
}
}
if (!found) currentArray.push(val);
}
var am = ams.join(" , ");
var pm = pms.join(" , ");
Try with .split method like this,
Updated without jQuery
var list = "09:05, 10:05, 12:30, 16:30";
var options = list.split(',').map(time => {
h = time.split(':')[0];
return parseInt(h) >= 12 ? 'pm ' + time : 'am ' + time;
})
console.log(options);

Create a unique number with javascript time

I need to generate unique id numbers on the fly using javascript. In the past, I've done this by creating a number using time. The number would be made up of the four digit year, two digit month, two digit day, two digit hour, two digit minute, two digit second, and three digit millisecond. So it would look something like this: 20111104103912732 ... this would give enough certainty of a unique number for my purposes.
It's been a while since I've done this and I don't have the code anymore. Anyone have the code to do this, or have a better suggestion for generating a unique ID?
A better approach would be:
new Date().valueOf();
instead of
new Date().getUTCMilliseconds();
valueOf() is "most likely" a unique number. http://www.w3schools.com/jsref/jsref_valueof_date.asp.
The shortest way to create a number that you can be pretty sure will be unique among as many separate instances as you can think of is
Date.now() + Math.random()
If there is a 1 millisecond difference in function call, it is 100% guaranteed to generate a different number. For function calls within the same millisecond you should only start to be worried if you are creating more than a few million numbers within this same millisecond, which is not very probable.
For more on the probability of getting a repeated number within the same millisecond see https://stackoverflow.com/a/28220928/4617597
If you just want a unique-ish number, then
var timestamp = new Date().getUTCMilliseconds();
would get you a simple number. But if you need the readable version, you're in for a bit of processing:
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()
This can be achieved simply with the following code:
var date = new Date();
var components = [
date.getYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds(),
date.getMilliseconds()
];
var id = components.join("");
Here's what I do when I want something smaller than a bunch of numbers - change base.
var uid = (new Date().getTime()).toString(36)
This performs faster than creating a Date instance, uses less code and will always produce a unique number (locally):
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/
I've released this on Bower and npm: https://github.com/stevenvachon/unique-number
You could also use something more elaborate such as cuid, puid or shortid to generate a non-number.
I use
Math.floor(new Date().valueOf() * Math.random())
So if by any chance the code is fired at the same time there is also a teeny chance that the random numbers will be the same.
In 2023, you can use the in-browser Crypto API to generate cryptographically strong random values.
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());
both Uint8Array constructor and Crypto.getRandomValues are supported on all major browsers, including IE11
This should do :
var uniqueNumber = new Date().getTime(); // milliseconds since 1st Jan. 1970
if you want a unique number after few mili seconds then use Date.now(), if you want to use it inside a for loop then use Date.now() and Math.random() together
unique number inside a for loop
function getUniqueID(){
for(var i = 0; i< 5; i++)
console.log(Date.now() + ( (Math.random()*100000).toFixed()))
}
getUniqueID()
output:: all numbers are unique
15598251485988384
155982514859810330
155982514859860737
155982514859882244
155982514859883316
unique number without Math.random()
function getUniqueID(){
for(var i = 0; i< 5; i++)
console.log(Date.now())
}
getUniqueID()
output:: Numbers are repeated
1559825328327
1559825328327
1559825328327
1559825328328
1559825328328
From investigating online I came up with the following object that creates a unique id per session:
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 + '.');
}
}
}
It maybe helpful to some people.
Cheers
Andrew
This also should do:
(function() {
var uniquePrevious = 0;
uniqueId = function() {
return uniquePrevious++;
};
}());
In 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('')
Example:
> uniqueID()
> "bxppcnanpuxzpyewttifptbklkurvvetigra"
Always get unique Id in JS
function getUniqueId(){
return (new Date().getTime()).toString(36) + new Date().getUTCMilliseconds();
}
getUniqueId() // Call the function
------------results like
//"ka2high4264"
//"ka2hj115905"
//"ka2hj1my690"
//"ka2hj23j287"
//"ka2hj2jp869"
Updated for 2021, numbers and ids are not guaranteed to be unique but should be satisfactory unique enough:
(oh, and who knew something.toString(36) is even a thing πŸ™‚)
// a pseudo-random floating number based on Date.now()
const generateRandomNumber = () =>
Math.log2(Date.now()) + Math.random();
console.log("a pseudo-random floating number based on Date.now():");
console.log(generateRandomNumber());
// a locally unique-ish HTML id
const generateUniqueId = () => `_${Date.now().toString(36)}${Math.floor(Number.MAX_SAFE_INTEGER * Math.random()).toString(36)}`;
console.log("a locally unique-ish HTML id:");
console.log(generateUniqueId())
// a pseudo-random BigInt
const generateRandomBigInt = () =>
BigInt(Date.now()) * BigInt(Number.MAX_SAFE_INTEGER) +
BigInt(Math.floor(Number.MAX_SAFE_INTEGER * Math.random()));
console.log("a pseudo-random BigInt:");
console.log(generateRandomBigInt().toString());
// same but base32-encoded (each char is 5 bits)
console.log("same but base32-encoded (each char is 5 bits):");
console.log(generateRandomBigInt().toString(32));
// extracting the "Date.now" timestamp of when it was generated:
console.log('extracting the "Date.now" timestamp of when it was generated:');
console.log(Number(generateRandomBigInt() / BigInt(Number.MAX_SAFE_INTEGER)))
// generate a run of random BigInt in ascending order
function generateRandomBigIntFactory() {
let count = 0, prev = 0;
return () => {
const now = Date.now();
if (now === prev) { ++count; }
else { count = 0; prev = now; }
return (BigInt(now) * BigInt(16384) + BigInt(count)) * BigInt(Number.MAX_SAFE_INTEGER) +
BigInt(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER));
}
}
// verify the order is ascending
const generate = generateRandomBigIntFactory();
let prev = 0;
for (let i = 0; i < 65536; i++) {
const num = generate();
if (num <= prev) console.log(`error: ${prev}, ${num}`);
prev = num;
}
console.log("the last random BigInt:");
console.log(prev.toString());
use this:for creating unique number in javascript
var uniqueNumber=(new Date().getTime()).toString(36);
It really works. :)
simple solution I found
var today = new Date().valueOf();
console.log( today );
This creates an almost guaranteed unique 32 character key client side, if you want just numbers change the "chars" var.
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/
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;
}
Call 1: UniqueValue('0')
Call 2: UniqueValue(UniqueValue('0')) // will be complex
Sample Output:
for(var i =0;i<10;i++){ console.log(UniqueValue(UniqueValue('0')));}
60950116113248802
26780116113248803
53920116113248803
35840116113248803
47430116113248803
41680116113248803
42980116113248804
34750116113248804
20950116113248804
03730116113248804
Since milliseconds are not updated every millisecond in node, following is an answer. This generates a unique human readable ticket number. I am new to programming and nodejs. Please correct me if I am wrong.
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;
}
let uuid = ((new Date().getTime()).toString(36))+'_'+(Date.now() + Math.random().toString()).split('.').join("_")
sample result "k3jobnvt_15750033412250_18299601769317408"
I came across this question while trying to find a simple UID generation technique that was also sortable (so I can order by uid and items will appear in order of creation / uid generation). The major problem with most (all?) of the solutions here is that they either rely on millisecond accuracy (at best) == clashes(!) or a pseudo-random number == clashes(!) && non-sortable(!).
Technique below uses micro-second precision where available (i.e. not where fingerprinting-resistance techniques are in play, e.g. firefox) combined with an incrementing, stateful suffix. Not perfect, or particularly performant for large numbers of IDs (see example with 1,000,000 below), but it works and is reversible.
// return a uid, sortable by creation order
let increment;
let tuidPrev;
const uid = (uidPrev) => {
// get current time to microsecond precision (if available) and remove decimals
const tuid = ((performance.timing.navigationStart + performance.now()) * 1000)
// convert timestamp to base36 string
.toString(36);
// previous uid has been provided (stateful)
if (uidPrev) {
tuidPrev = uidPrev.slice(0, 10);
increment = uidPrev.length > 10 ? parseInt(uidPrev.slice(10), 36) : 0;
}
// if tuid is changed reset the increment
if (tuid !== tuidPrev) {
tuidPrev = tuid;
increment = 0;
}
// return timed uid + suffix (4^36 values) === very unique id!
return tuid + ('000' + (increment++).toString(36)).slice(-4);
}
// EXAMPLE (check the console!)
const iterations = 1000000;
const uids = [];
const uidMap = {};
const timeMap = {}
const microMap = {};
let time = performance.now();
for (let i = 0; i < iterations; i++) {
const id = uid();
uids.push(id);
uidMap[id] = i;
timeMap[Date.now()] = i;
microMap[performance.now()] = i;
}
console.log(`Time taken: ${performance.now() - time}ms`);
console.log('Unique IDs:', Object.keys(uidMap).length.toLocaleString());
console.log('Clashing timestamps:', (iterations - Object.keys(timeMap).length).toLocaleString());
console.log('Clashing microseconds:', (iterations - Object.keys(microMap).length).toLocaleString());
console.log('Sortable:', !uids.slice().sort().find((id, i) => uids[i] !== id))
The usual way in which I generate unique IDs is by using Date.now();
const ID = Date.now();
console.log(ID);
The other way is by using a library as idgp which can be installed using npm.
The link: https://www.npmjs.com/package/idgp
Assumed that the solution proposed by #abarber it's a good solution because uses (new Date()).getTime() so it has a windows of milliseconds and sum a tick in case of collisions in this interval, we could consider to use built-in as
we can clearly see here in action:
Fist we can see here how there can be collisions in the 1/1000 window frame using (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
Second we try the proposed solution that avoid collisions in the 1/1000 window:
console.log( window.mwUnique.getUniqueID() ); console.log( window.mwUnique.getUniqueID() );
VM1159:1 14696154132130
VM1159:1 14696154132131
That said we could consider to use functions like the node process.nextTick that is called in the event loop as a single tick and it's well explained here.
Of course in the browser there is no process.nextTick so we have to figure how how to do that.
This implementation will install a nextTick function in the browser using the most closer functions to the I/O in the browser that are setTimeout(fnc,0), setImmediate(fnc), window.requestAnimationFrame. As suggested here we could add the window.postMessage, but I leave this to the reader since it needs a addEventListener as well. I have modified the original module versions to keep it simpler here:
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() )
})
})
So we have in the 1/1000 window:
getUniqueID(function(c) { console.log(c); });getUniqueID(function(c) { console.log(c); });
undefined
VM1160:1 1469615416965
VM1160:1 1469615416966
Maybe even better would be to use getTime() or valueOf(), but this way it returns unique plus human understandable number (representing date and time):
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();
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();
Easy and always get unique value :
const uniqueValue = (new Date()).getTime() + Math.trunc(365 * Math.random());
**OUTPUT LIKE THIS** : 1556782842762
I have done this way
function uniqeId() {
var ranDom = Math.floor(new Date().valueOf() * Math.random())
return _.uniqueId(ranDom);
}
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));
}
in reference to #Marcelo Lazaroni solution above
Date.now() + Math.random()
returns a number such as this 1567507511939.4558 (limited to 4 decimals), and will give non-unique numbers (or collisions) every 0.1%.
adding toString() fixes this
Date.now() + Math.random().toString()
returns '15675096840820.04510962122198503' (a string), and
is further so 'slow' that you never get the 'same' millisecond, anyway.

Categories