moment.js reverse .fromNow() - node.js

So i'm working with moment.js.
I see you can translate a date into a human-friendly format using moment().fromNow();
Is there a way to do the opposite?
For example, I want to turn this --> "2 weeks ago" into a normal date format or UNIX timestamp.
I sifted through the documentation but couldnt find anything. Any direction would help, thanks.

Depending on how complicated/different the input strings can be, you could do this:
//parse out the number and the duration
var inputString = "2 weeks ago";
var myRegExp = /^(\d+)\s(\w+)\sago$/;
var results = myRegExp.exec(inputString);
var num = results[1];
var duration = results[2];
moment().subtract(duration,num).toString() //or whatever format you prefer
Note this will work for input strings of the format "number duration ago".
Hope that helps!

In some cases .fromNow() returns string like "30+ days ago". The regex provided in above solution doesn't handle to parse that properly.
Here's the updated regex to handle that case:
var myRegExp = /^(\d+)\+?\s(\w+)\sago$/;

Here is the method that I used to reverse it for the current moment.js locale. I tested it on a few locales and it should work for every locale but it might not.
Change the last two .toString() functions to .valueOf() to get numerical values.
Moment actually doesn't have the week name data for all languages right now, so the function will assume that the string is a week if it could not find the value.
Some languages use translation functions instead of having built in values so the script will not work on those either! If you manually specify your language data then it should work.
//test en locale
moment.locale("en");
console.log(reversefromNow("5 days ago"));
console.log(reversefromNow("in 5 days"));
//test ja locale
moment.locale("ja");
console.log(reversefromNow("5 日前"));
console.log(reversefromNow("5 日後"));
function reversefromNow(input) {
let relativeLocale = JSON.parse(JSON.stringify(moment.localeData()._relativeTime));
let pastfutureObject = {
future: relativeLocale.future,
past: relativeLocale.past
};
delete relativeLocale.future;
delete relativeLocale.past;
//detect if past or future
let pastfuture;
for (const [key, value] of Object.entries(pastfutureObject)) {
if (input.indexOf(value.replace("%s", "")) != -1) {
pastfuture = key;
}
}
//detect the time unit
let unitkey;
for (const [key, value] of Object.entries(relativeLocale)) {
if (input.indexOf(value.replace("%d", "")) != -1) {
unitkey = key.charAt(0);
}
}
//if its not in the data, then assume that it is a week
if (unitkey == null) {
unitkey = "w";
}
const units = {
M: "month",
d: "day",
h: "hour",
m: "minute",
s: "second",
w: "week",
y: "year"
};
//Detect number value
const regex = /(\d+)/g;
let numbervalue = input.match(regex) || [1];
//Add if future, subtract if past
if (pastfuture == "past") {
return moment().subtract(numbervalue, units[unitkey]).valueOf();
} else {
return moment().add(numbervalue, units[unitkey]).valueOf();
}
}

Related

fs.readFileSync gives duplicated results when reading JSON files in node.js

I got two JSON files that I'm processing:
sorted/apr-total2.json
sorted/may-total2.json
There are files for other months of the year, but for debugging purposes I'm focusing on these two because they are causing the problem.
They contain simple data in the following format:
[
["John", 1403],
["Peter", 1159],
...
]
However, John is available only in sorted/apr-total2.json file and not in sorted/may-total2.json.
My code is the following:
let months = ["apr", "may"];
let dataToSort = {};
function getDataFromJSONFile(month) {
let jsonData = fs.readFileSync(`sorted/${month}-total2.json`);
let convertedData = JSON.parse(jsonData);
return convertedData;
}
function arrayToObject(data) {
data.forEach((user) => {
dataToSort[user[0].toString()] = user[1];
});
return dataToSort;
}
for (let i in months) {
let currentMonth = months[i];
console.log("Current month is " + currentMonth);
let getDataForMonth = getDataFromJSONFile(currentMonth);
let convertedMonth = arrayToObject(getDataForMonth);
if (convertedMonth.hasOwnProperty("John") == true) {
console.log(true);
}
}
My output is the following:
Current month is apr
true
Current month is may
true
This isn't correct, since user John isn't available in sorted/may-total2.json. So why is this happening? It seems that the object convertedMonth is causing the issue.
If I add the following code at the end of the for loop and delete the ConvertedMonth object properties:
for (let item in convertedMonth) {
delete convertedMonth[item];
}
It works as intended:
Current month is apr
true
Current month is may
I want to know why this object is causing the issue, because I reused the same code in another place of my project.
Your arrayToObject function uses a single global dataToSort, so any entries will be accumulated and overwritten there. See:
> let dataToSort = {};
> function arrayToObject(data) {
... data.forEach((user) => {
... dataToSort[user[0].toString()] = user[1];
... });
... return dataToSort;
... }
> arrayToObject([["foo", 123]])
{ foo: 123 }
> arrayToObject([["foo", 456], ["bar", 567]])
{ foo: 456, bar: 567 }
Your program simplifies to something like
let months = ["apr", "may"];
for (let currentMonth of months) {
console.log("Current month is " + currentMonth);
let jsonData = JSON.parse(fs.readFileSync(`sorted/${month}-total2.json`));
let convertedMonth = Object.fromEntries(jsonData);
if (convertedMonth["John"]) {
console.log(true);
}
}
which
uses for..of for correct and simpler iteration over the months
uses Object.fromEntries to convert an array of 2-arrays into a plain object (which is what your arrayToObject did)

How get Lot/Serial number in Netsuite SuiteScript 2.0 for Inventory Adjustment Transaction?

I'm trying to get the serial numbers from a inventory adjustment in a user event script. The following code works very well for me when the amount to adjust is positive, but not when it is negative.
var invDet = transaction.getSublistSubrecord({sublistId:'inventory',
fieldId:'inventorydetail',
line:x});
for(var y = 0; y = invDet.getLineCount('inventoryassignment'); y++) {
var lotNumber = invDet.getSublistValue({sublistId:'inventoryassignment',
fieldId:'receiptinventorynumber',
line:y});
log.debug('lotNumber', lotNumber);
}
When adjust quantity is negative, receiptinvetorynumber is empty
I have tried using field id equal to 'issueinventorynumber' or 'binnunber' but the returned value is empty.
I found the following comment in a NetsuiteHub forum...
In 2.0 the getValue call returns the internal ID of the serial/lot number and the getText equivalent does not work. Depending on the exact logic you need to execute for the obtained numbers you might need to call a subsequent saved search to obtain the actual serial/lot numbers and not internal IDs (an 'inventorynumber' search will do the trick).
I tried this...
try{
var internalId = invdet.getSublistValue({sublistId:'inventoryassignment',fieldId:'internalid', line:y});
search.create({type:'inventorynumber', filters:[
['internalid', 'is', internalId]
], columns:['inventorynumber']}).run().each(function (result) {
binText = result.getValue('inventorynumber');
log.debug('binText', binText);
});
} catch(e) {
log.debug('Error', e.message);
throw e.message;
}
I am too inexperienced to make this work. I appreciate any help you can give me.
Thanks.
The challenge is that this area of the NetSuite API is not well documented. However, I pushed through it through trial and error and search hours.
var invDet = transaction.getSublistSubrecord({sublistId:'inventory',
fieldId:'inventorydetail',
line:x});
for(var y = 0; y = invDet.getLineCount('inventoryassignment'); y++) {
var Qty = invdet.getSublistValue({sublistId:'inventoryassignment',
fieldId:'quantity',
line:y});
var lotNumber = '';
if(Qty < 0)
{
var ivnNumId = nvdet.getSublistValue({sublistId:'inventoryassignment',
fieldId:'issueinventorynumber',
line:y});
if(ivnNumId !== '')
{
var invNum = record.load({type: 'inventorynumber',id:ivnNumId});
lotNumber = invNum.getValue({fieldId: 'inventorynumber'});
}
}
else
{
lotNumber = invdet.getSublistValue({sublistId:'inventoryassignment',
fieldId:'receiptinventorynumber',
line:y});
}
log.debug('lotNumber', lotNumber);
}
This information was very helpful in ss1.0
I hope it is useful to someone

java.lang.NumberFormatException: For input string: "16000$" in kotlin

I want to make display show "16000$" before click increase btn or decrease btn.
when I make code like this error caused by :java.lang.NumberFormatException: For input string: "16000$ . but I should display $. Lets check my code and help me plz.
var productprice = findViewById<TextView>(R.id.productPrice)
productprice.text= intent.getStringExtra("price")+"$"
var price = productPrice.text.toString().toInt()
var inc_val= price
var getPrice = price
decrease.isEnabled=false
increase.setOnClickListener {
increaseInteger()
getPrice+= inc_val
productprice.text=getPrice.toString()+"$"
}
decrease.setOnClickListener {
decreaseInteger()
getPrice -= inc_val
productprice.text=getPrice.toString()+"$"
}
You are trying to parse the string with "$" to int, Hence you are getting NumberFormatException.
Try this instead:
var productprice = findViewById<TextView>(R.id.productPrice)
productprice.text= intent.getStringExtra("price")+"$"
var price = parseInt(intent.getStringExtra("price"))
var inc_val= price
var getPrice = price
decrease.isEnabled=false
increase.setOnClickListener {
increaseInteger()
getPrice+= inc_val
productprice.text=getPrice.toString()+"$"
}
decrease.setOnClickListener {
decreaseInteger()
getPrice -= inc_val
productprice.text=getPrice.toString()+"$"
}
var price = productPrice.text.toString().toInt() - you try to convert "16000$" to Int here. Please get substring here first.
Formally, right code is:
val priceText = productPrice.text.toString()
val price = priceText.substring(0, priceText.length - 1).toInt()
However really I advice you to store value internally. You price is part of model. E.g. you can avoid text parsing and just read value from model. E.g. code will be like this:
var price = intent.getIntExtra("price") // we store int value here, not String
var inc_val= price
decrease.isEnabled=false
displayPrice()
increase.setOnClickListener {
intent.setIntExtra(intent.getIntExtra("price") + inc_val) // read, update, save
displayPrice()
}
decrease.setOnClickListener {
intent.setIntExtra(intent.getIntExtra("price") - inc_val) // read, update, save
displayPrice()
}
/*this function just shows price*/
fun displayPrice() {
val price = intent.getIntExtra("price")
productprice.text= "$price\$"
}

Handsontable numeric cell globalization

I'm relatively new to js and now have to implement a handsontable into our project.
This worked well so far, but I am hitting a roadblock with globalization.
Basically, we use comma as a decimal seperator, but when I try and copy something like "100,2" into a cell designated as 'numeric,' it will show as 1002.
If the same value is entered in a cell designated as 'text' and the type is changed to numeric afterwards, the value will be shown correctly.
For this I already had to add 'de' culture to the table sourcecode.(basically copying 'en' and changing the values currently relevant to me.)
numeral.language('de', {
delimiters: {
thousands: '.',
decimal: ','
},//other non-relevant stuff here
When I copy the values directly from the table and insert them to np++ they show as 100.2 etc. However, when inserting them into handsontable the arguments-array looks as follows:
[Array[1], "paste", undefined, undefined, undefined, undefined]
0: Array[4]
0: 1 //row
1: 1 //column
2: "100.2" //previous value
3: 1002 //new value
Here's what I have tried currently:
hot.addHook("beforeChange", function () {
if (arguments[1] === "paste") {
hot.updateSettings({
cells: function (row, col, prop) {
var cellProperties = {
type: 'numeric',
language: 'en'
};
return cellProperties;
}
});
//hot.updateSettings({
// cells: function (row, col, prop) {
// var cellProperties = {
// type: 'text',
// };
// return cellProperties;
// }
//});
}
}, hot);
hot.addHook("afterChange", function () {
if (arguments[1] === "paste") {
ChangeMatrixSettings(); //reset cell properties of whole table
}
}, hot);
I hope I've made my problem clear enough, not sure if I missed something.
Are there any other ways to get the correct values back into the table? Is this currently not possible?
Thanks in advance.
You asked more than one thing, but let me see if I can help you.
As explained in handsontable numeric documentation, you can define a format of the cell. If you want '100,2' to be shown you would format as follows
format: '0.,'
You can change that to what you really need, like if you are looking for money value you could do something like
format: '0,0.00 $'
The other thing you asked about is not on the latest release, but you can check it out how it would work here
I have since implemented my own validation of input, due to other requirements we have for the table mainly in regards to showing invalid input to user.
function validateInputForNumeric(parameter) {
var value = parameter[3];
var row = parameter[0];
var col = parameter[1];
if (decimalSeperator === '') {
var tmpculture = getCurrCulture();
}
if (value !== null && value !== "") {
if (!value.match('([a-zA-Z])')) {
if (value.indexOf(thousandSeperator) !== -1) {
value = removeAndReplaceLast(value, thousandSeperator, ''); //Thousandseperators will be ignored
}
if (value.indexOf('.') !== -1 && decimalSeperator !== '.') {
//Since numeric variables are handled as '12.3' this will customize the variables to fit with the current culture
value = removeAndReplaceLast(value, '.', decimalSeperator);
}
//Add decimalseperator if string does not contain one
if (numDecimalPlaces > 0 && value.indexOf(decimalSeperator) === -1) {
value += decimalSeperator;
}
var index = value.indexOf(decimalSeperator)
var zerosToAdd = numDecimalPlaces - (value.length - index - 1);
for (var j = 0; j < zerosToAdd; j++) {
//Add zeros until numberOfDecimalPlaces is matched for uniformity in display values
value += '0';
}
if (index !== -1) {
if (numDecimalPlaces === 0) {
//Remove decimalseperator when there are no decimal places
value = value.substring(0, index)
} else {
//Cut values that have to many decimalplaces
value = value.substring(0, index + 1 + numDecimalPlaces);
}
}
if (ErrorsInTable.indexOf([row, col]) !== -1) {
RemoveCellFromErrorList(row, col);
}
} else {
AddCellToErrorList(row, col);
}
}
//console.log("r:" + row + " c:" + col + " v:" + value);
return value;
}
The inputParameter is an array, due to handsontable hooks using arrays for edit-events. parameter[2] is the old value, should this be needed at any point.
This code works reasonably fast even when copying 2k records from Excel (2s-4s).
One of my main hindrances regarding execution speed was me using the handsontable .getDataAtCell and .setDataAtCell methods to check. These don't seem to handle large tables very well ( not a critique, just an observation ). This was fixed by iterating through the data via .getData method.

Which algorithm to find the only one duplicate word in a string?

This is very common interview question:
There's a all-english sentence which contains only a duplicate word, for example:
input string: today is a good day is true
output: is
I have an idea:
Read every character from the string, using some hash function to compute the hash value until get a space(' '), then put that hash value in a hash-table.
Repeat Step 1 until the end of the string, if there's duplicate hash-value, then return that word, else return null.
Is that practical?
Your approach is reasonable(actually the best I can think of). Still take into account the fact that a collision may appear. Even if the hashes are the same, compare the words.
It would work, but you can make your life a lot easier.
Are you bound to a specific programming language?
If you code in c# for example, i would suggest you use the
String.Split function (and split by " ") to transform your sentence into a list of words. Then you can easily find duplicates by using LINQ (see How to get duplicate items from a list using LINQ?) or by iterating through your list.
You can use the Map() function, and also return how many times the duplicate word is found in the string.
var a = 'sometimes I feel clever and sometimes not';
var findDuplicateWord = a => {
var map = new Map();
a = a.split(' ');
a.forEach(e => {
if (map.has(e)) {
let count = map.get(e);
map.set(e, count + 1);
} else {
map.set(e, 1);
}
});
let dupe = [];
let hasDupe = false;
map.forEach((value, key) => {
if (value > 1) {
hasDupe = true;
dupe.push(key, value);
}
});
console.log(dupe);
return hasDupe;
};
findDuplicateWord(a);
//output
/* Native Browser JavaScript
[ 'sometimes', 2 ]
=> true */

Resources