express.js route not recognizing null value for conditional response - node.js

I am trying to render an alternative response to my express.js route when a date value in the parameter ends up being invalid. When I see an invalid date the value ends up being null so in my if statement in the middleware I test for a truthy value and if it is not truthy i serve up an alternative response.
What I get is the true value even though the value of the date is null. Here is an example:
api/timestamp/hello is my route.
A valid date should look like this: {"unix":1546214400000,"utc":"Mon, 31 Dec 2018 00:00:00 GMT"}
An invalid date like 'hello' should look like this {'error': 'Invalid Date'}
The code returns the correct value if the date is valid, but if the date is invalid I get {"unix":null,"utc":"Invalid Date"} instead of {'error': 'Invalid Date'}
Below is the code.
app.get('/api/timestamp/:date', (req,res) => {
let date = new Date(req.params.date);
if (date === null) {
res.send({'error': 'Invalid Date'});
} else {
let unix = date.getTime();
let utc = date.toUTCString();
res.send({unix, utc});
}
});
I'm relatively new to express and Node.js for that matter. Any thoughts on why the null value is not being recognized?

Q: Wouldn't it make sense to check for a valid date BEFORE you try converting it to Unix and UTC?
app.get('/api/timestamp/:date', (req,res) => {
let date = new Date(req.params.date);
if (req.params.date && date instanceOf Date) {
let unix = date.getTime();
let utc = date.toUTCString();
res.send({unix, utc});
} else {
res.send({'error': 'Invalid Date'});
}
}

The way you are building your response, node thinks it's a destructuring assignment, therefore you get the strange response.
To get what you want you can make something like this:
app.get('/api/timestamp/:date?', (req,res) => {
if(req.params.date){
let date = new Date(req.params.date);
let unix = date.getTime();
let utc = date.toUTCString();
if(unix) return res.send({unix,utc})
res.send({'error': 'Invalid Date'});
} else
res.send({'error': 'Invalid Date'});
})

Date constructor returns date to 1 January 1970 if the parameter is null and I can't think of any case it would return null.
Which means that your first check will always be false since your are using strict equality.
Probably you better be checking if req.params.date is truthy and unix is a valid timestamp
Hope this helps

Related

Day.js unable to properly format date input in nodejs and reactjs

I am trying to implement dayjs package in my node.js application. I would like my date and time to be formatted like this:
2022-09-11T17:46:00+01:00
I have my codes like this:
const dayjs = require("dayjs");
const utc = require("dayjs/plugin/utc");
const customParseFormat = require('dayjs/plugin/customParseFormat');
const dayJsUTC = dayjs.extend(utc)
const dayJsDate = dayJsUTC.extend(customParseFormat)
I am trying to check that the format comes out this way 2022-09-11T17:46:00+01:00
Here is the code:
if(!dayJsDate( 2022-09-11T17:46:00+01:00, "YYYY-MM-DD HH:mm", true).isValid()){
return res.status(500).json('invalid date')
}
It is returning invalid date. I know I am not doing it properly. How can I do it properly to scale this validation?
Also, if I want to simply create only date, hour and minute without the additional time details, how can I do that using dayjs?
Sorry for not answering your question straight, but you could get what you want by defining your own function. When you pass no args to it, it returns just time in format like you wish, when passing a string to function - it return true or false, checking format. If you pass second param as "true", function will return date, hours and minutes.
const myDate = (input, noSecondsAndOffset) => {
const
offset = -(new Date().getTimezoneOffset()),
offsetHours = '0' + offset / 60,
offsetMins = '' + offset % 60,
timeZone = `${offsetHours}:${offsetMins}${offsetMins.length === 1 ? '0' : ''}`,
currTime = `${new Date().toJSON().slice(0, -5)}+${timeZone}`,
checker = (string) => !!string.match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}:\d{2}/);
return typeof input === 'string'
? checker(string)
: !noSecondsAndOffset
? currTime
: currTime.slice(0, -9)
}

How to return the array after altering it back into json format?

I am making a discord bot where you can use the command tcp freeitem to obtain your free item.
I am trying to alter that value of an Account by adding a new item object into the account. When I map the array to replace a value, it erases the name (allAccounts) of the array of the json. More information below. Here is what I have:
const listOfAllItemNames = require(`C:/Users///censored///OneDrive/Desktop/discord bot/itemsDataList.json`)
const accountList = require(`C:/Users///censored///OneDrive/Desktop/discord bot/account.json`)
const fs = require('fs')
var accountThatWantsFreeItem = accountList.allAccounts.find(user => message.author.id === user.userId);
var randomFreeItem = listOfAllItemNames.allItems[Math.floor(Math.random() * listOfAllItemNames.allItems.length)]
if(accountThatWantsFreeItem === undefined) {message.reply('You need to make an account with tcp create!'); return; }
if(accountThatWantsFreeItem.freeItem === true) {message.reply('You already got your free one item!'); return;}
fs.readFile('C:/Users///censored///OneDrive/Desktop/discord bot/account.json', 'utf8', function readFileCallback(err,data) {
if(err){
console.error(err)
} else {
var accountsArray = JSON.parse(data)
console.log(accountsArray)
var whoSentCommand = accountsArray.allAccounts.find(user => message.author.id === user.userId)
whoSentCommand.Items.push(randomFreeItem)
whoSentCommand.freeItem = true;
var test = accountsArray.allAccounts.map(obj => whoSentCommand === obj.id || obj)
//I believe the issue is trying to map it returns a new array
console.log(test)
test = JSON.stringify(test, null, 5)
//fs.writeFile('C:/Users///censored///OneDrive/Desktop/discord bot/account.json', test, err =>{ console.error(err)} )
}
})
when I write the file back to json file, it removes the "allAccounts" identifier in this file
//json file
//array name "allAccounts" is removed, I need this still here for code to work
{
"allAccounts" : [
{
"userId": "182326315813306368",
"username": "serendipity",
"balanceInHand": 0,
"balanceInBank": 0,
"freeItem": false,
"Items": []
},
(No "allAccounts" array name)
to this: output after writing file
So, the final question is
How would I alter the array so that I only alter the account I want without editing the array name?
Please feel free to ask any questions if I was unclear.
Array.map() method returns the converted array.
So in the below line, map() method takes allAccounts array and perform actions and put the target array (not object) to the test variable.
var test = accountsArray.allAccounts.map(obj => whoSentCommand === obj.id || obj)
So for making code works, please change the code like this:
var test = {
"accountsArray": accountsArray.allAccounts.map(obj => whoSentCommand === obj.id || obj)
}
When posting questions, please please reduce the code to a minimal example that will demonstrate the problem, and use words, not code, to describe the problem.
It looks like you are expecting .map to do something other than what it does.
Please consult the documentation for Array.map().
It takes the array that you pass it (in this case accountsArray.allAccounts) and transforms it, returning the transformed array.
You have essentially done test = accountsArray.allAccounts but for some reason are expecting test to contain an Object with the key allAccounts, when in fact it will only contain an Array, because that is what you have assigned it.

Convert google.protobuf.Timestamp to ISO format in Fabric 1.4 in NodeJS

I am running a Hyperledger Fabric 1.4 chaincode and try to retrieve the history of a key with getHistoryForKey stub method. I am iterating over each entry and want to convert them for standardization in all my chaincode functions.
Now, I can handle all keys in the iterator, except the timestamp which is a google.protobuf.Timestamp. Any tries of mine fail to convert it to an ISO datetime string.
Code
// Entry method to retrieve the full history of any asset
async (stub, args) => {
const idToSearch = args.id
const historyIterator = await stub.getHistoryForKey(idToSearch)
let historyData = []
await iterate(historyData, historyIterator)
if (historyData.length === 0) throw errors.ASSET_NOT_FOUND(idToSearch)
return historyData
}
// I use node v8 and thus cannopt use for await to iterator and must write recursive helper func
const iterate = async (historyData, historyIterator) => {
const element = await historyIterator.next()
if (!element) return historyIterator.close()
const {value} = element
if (!value) return historyIterator.close()
historyData.push({
value: value.value.toString('utf8'),
isDeleted: value.is_delete,
txId: value.tx_id,
timestamp: value.timestamp // <-- WANT TO CONVERT TO ISO DATE TIME STRING
})
await iterate(historyData, historyIterator)
}
My Approaches
1. toISOString()
Regarding the documentation of the protobuf of timestamp it says "In JavaScript, one can convert a Date object to this format using the standard toISOString()". This does not work, since I get "toISOString is not a function".
2. new Date()
Further, I tried to run new Date(protobufTimestamp), which results in "Invalid Date".
3. Using the seconds
I though maybe I can utilize the seconds which are on of two keys (Object.keys(protobufTimestamp) => [seconds, nanos]) in the timestamp to create the Date. But that date object also says "Invalid Date". That could be explained since I read that Protobuf Timestamp covers the ranges from year 0 to 9999. So, maybe the conversion fails.
Question
Can someone explain me how to convert the google protobuf timestamp to an ISO timestamp in Fabric 1.4 in NodeJS?
You can try something like
new Date(protobufTimestamp.seconds * 1000).toISOString()

I am trying to get readable date from firestore

I am trying to get readable date from Timestamp data type in my firestore database.
for (var ticketDoc of ticketsSnapshot.docs) {
var timeStamp = await ticketDoc.data().TimePreferred;
console.log(timeStamp.toDate());
var time = new Date(timeStamp).toDate();
ticketDoc.data().TimePreferred = time;
tickets.push(ticketDoc.data());
}
I read the question about a similar problem at :
How do I convert a Firestore date/Timestamp to a JS Date()?
so, i tried to do same and i expect the output of readable date, although it gives me the correct result in
console.log(timeStamp.toDate());
but also it gives me an error. Console output as follow :-
2019-04-10T06:30:00.000Z
TypeError: (intermediate value).toDate is not a function
Not : I am trying to get readable date in postman
I don't know why this timestamp object doesn't have the .toDate() extension, but if it has the 'seconds' and 'nanoseconds' properties, you can turn it to a JS Data with
Date(data.seconds)
Change the following line:
var time = new Date(timeStamp).toDate();
into this:
var time = new Date(timeStamp).toDateString();
From the docs:
A string representing the date portion of the given Date object in human readable form in American English.
You can try in the following way
{{ formatDate(new Date(data.seconds*1000)) }}
You can use the format date function to display in desired format.
import moment from "moment";
format_date(value) {
if (value) {
return moment(String(value)).format("DD/MM/YYYY");
}
},
Have you tried changing this to
var time = (new Date(timeStamp)).toDateString();
If the TimePreferred field in your document is a Timestamp, you can get a valid Date object from it by simply calling toDate() on it.
So:
for (var ticketDoc of ticketsSnapshot.docs) {
var date = ticketDoc.data().TimePreferred.toDate();
}
None of these calls are asynchronous or returning a promise, so you don't need await.
From reasons that I don't know, it doesn't work at times, so a safer option would be to use the seconds and nanoseconds attributes found in the timestamp to convert it to date as follows:
const date = new Date(timestamp.seconds*1000 + timestamp.nanoseconds/100000)
// construct the date from the absolute time in milliseconds
Note:
1 second = 1000 ms
1 nanosecond = 10^-6 ms
You have to first make sure that the timestamp object is truly of type Timestamp.
to do this, after you get the Timestamp from Firebase, create the Timestamp object:
const timestampObject: Timestamp = !!timeStamp
? new Timestamp(timeStamp.seconds, timeStamp.nanoseconds)
: null;
For Angular
import { Location, DatePipe } from '#angular/common';
constructor(
public datepipe: DatePipe
) { }
const dayAsTimestamp = your_Timestamp_value;
const dayAsDate = new Date(dayAsTimestamp.seconds * 1000);
const dayAsString = this.datepipe.transform(dayAsDate, 'dd-MMM-yyyy');

Azure Mobile server update script w/ complex field type

I've got a complex data type "AzureTemplate" containing a list of children "AzureField". I've implemented my read and insert on the server side according to this article. Works great.
Needing an update as well, I copy/pasted the insert into the update so it does the same thing, but using update instead. So my update looks like this:
function update(item, user, request) {
// remove complex child object, make copy first
var fields = item.fields;
if (fields) {
delete item.fields;
}
request.execute({
success: function () {
var templateId = item.id; // "foreign key"
var fieldsTable = tables.getTable('AzureFields');
if (fields) {
// update the child fields
var updateNextField = function (index) {
if (index >= fields.length) {
// done updating fields, respond to client
request.respond();
} else {
var field = fields[index];
field.templateId = templateId;
// *** THE ID LOGGED HERE LOOKS FINE ***
console.log("updating field w/ id ", field.id);
fieldsTable.update(field, {
success: function () {
updateNextField(index + 1);
}
});
}
};
// kick off the loop saving each field
updateNextField(0);
} else {
// no fields. no need to do anything else
request.respond();
}
}
});
}
The log that prints the ID of the child "field" shows a valid field id (I save them on the client side when reading them). But I get an error that says:
Error in script '/table/AzureTemplate.update.js'. Error: Invalid id value specified. AzureTemplate/update Tue Jan 27 2015, 10:11:31 AM
I put a console.log() at the top of the AzureField.update, but that never shows up, so it's not getting in there. Also, when I update a single child "Field" directly from the client it works fine. So the AzureField.update is working. Any ideas?
var fieldsTable = tables.getTable('AzureFields');
... my table name is AzureField, not AzureFields. The above code works, hopefully it helps someone.
I have misnamed a table before and got a meaningful error about "table not existing". Not sure why the error in this case is totally unrelated.

Resources