Knex get formatted time from a time column and date column - node.js

I have a column defined with type time and column defined with type date.
knex.schema.createTable('receipt', function(table) {
...
table.date('t_date');
table.time('t_time');
...
});
It stores data in 24hour format in Database. eg: 22:00:00. Date as '2018-11-30'. But when I run a select query it returns.
{
...
"transactionDate": "2018-11-29T00:00:00.000Z",
"transactionTime": "1970-01-01T22:20:00.000Z",
...
}
How to get date from select query with date with format YYYY-MM-dd and time as HH:mm:ssAM/PM?

Next snippet works like a charm for me:
const { setTypeParser, builtins } = require('pg').types;
const typesToReset = [
builtins.DATE,
builtins.TIME,
builtins.TIMETZ,
builtins.TIMESTAMP,
builtins.TIMESTAMPTZ,
];
function resetPgDateParsers() {
for (const pgType of typesToReset) {
setTypeParser(pgType, val => String(val)); // like noParse() function underhood pg lib
}
}
...and call this function before using your pg or library/orm depends on pg (knex, objection etc.) requests.
sources: https://github.com/Vincit/objection.js/issues/663#issuecomment-351678734 and console.log(pg.types)

Selecting the format in which dates etc. column types are returned in javascript is done by database driver and not in knex.
For postgresql
Can we always fetch date column as string (varchar) with knex and postgres?
and for mysql
Knexjs returning mysql timestamp, datetime columns as Javascript Date object
should help.

oracleDb Users have to set this environment variable
export ORA_SDTZ='UTC'
Further info: https://community.oracle.com/docs/DOC-1008911

This solution is working fine for me with PostgreSQL 12.
Moment will also resolve the timezone.
const knex = require('knex');
const moment = require('moment');
const { setTypeParser, builtins } = require('pg').types;
setTypeParser(builtins.DATE, val => moment(val).format('YYYY-MM-DD'));
setTypeParser(builtins.TIME, val => moment(val).format('HH:mm:ss'));
setTypeParser(builtins.TIMETZ, val => moment(val).format('HH:mm:ss'));
setTypeParser(builtins.TIMESTAMP, val => moment(val).format('YYYY-MM-DD HH:mm:ss'));
setTypeParser(builtins.TIMESTAMPTZ, val => moment(val).format('YYYY-MM-DD HH:mm:ss'));
const db = knex({
client: 'pg',
connection: {
host : 'localhost',
user : 'MHamzaRajput',
password : 'My#pass#123',
database : 'my_db',
}
})

var data = {
"transactionDate": "2018-11-29T00:00:00.000Z",
"transactionTime": "1970-01-01T2:22:00.000Z"
}
var date = data.transactionDate.split("T")[0];
var time = data.transactionTime.split("T")[1].split(".000Z")[0];
let h = parseInt(time.split(":")[0]);
let m = time.split(":")[1];
let s = time.split(":")[2];
let suffix = "AM";
if(h >= 12){
h = h==12 ? 12: h%12;
suffix = "PM";
}
time =("0" + h).slice(-2)+":"+m+":"+s+"/"+suffix;
console.log(date);
console.log(time);

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

TypeScript NodeJS application Error: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.ts(7017)

This is time.ts file:
exports.getMinute = (timestamp: number) => {
const milliSecond = timestamp * 1000;
const dateObject = new Date(milliSecond);
const minute = dateObject.toLocaleString('en-us',{minute : "number"});
return minute;
};
exports.getHour = (timestamp: number) => {
const milliSecond = timestamp * 1000;
const dateObject = new Date(milliSecond);
const hour = dateObject.toLocaleString('en-us',{hour : "number"});
return hour;
};
exports.getDay = (timestamp: any) => {
const milliSecond = timestamp ;
const dateObject = new Date(milliSecond);
const day = dateObject.getDate();
return day;
};
exports.getMonth = (timestamp: any) => {
const milliSecond = timestamp ;
const dateObject = new Date(milliSecond);
const month = dateObject.getMonth();
return month;
};
exports.getYear = (timestamp: any) => {
const milliSecond = timestamp ;
const dateObject = new Date(milliSecond);
const year = dateObject.getFullYear();
return year;
};
exports.fullTime = (timestamp: any) => {
let day = this.getDay(timestamp);
const year = this.getYear(timestamp);
let month = this.getMonth(timestamp);
month ++
return `${year}`+'-'+`${month<=9 ? '0'+ month : month }` + '-' + `${day<=9 ? '0'+ day : day }`;
};
I get the following errors:
Element implicitly has an 'any' type because type 'typeof globalThis'
has no index signature.ts(7017)
Element implicitly has an 'any' type because type 'typeof globalThis'
has no index signature.ts(7017)
Element implicitly has an 'any' type because type 'typeof globalThis'
has no index signature.ts(7017)
For these lines of code:
let day = this.getDay(timestamp);
const year = this.getYear(timestamp);
let month = this.getMonth(timestamp);
Also these errors:
Type '"number"' is not assignable to type '"numeric" | "2-digit" |
undefined'.ts(2322)
Type '"number"' is not assignable to type '"numeric" | "2-digit" |
undefined'.ts(2322)
At these lines of the code:
const minute = dateObject.toLocaleString('en-us',{minute : "number"});
const hour = dateObject.toLocaleString('en-us',{hour : "number"});
I don't know what does it mean and how can I fix them?
There are a few things you can do to remove the errors.
exports. is more of a javascript construct, which you usually don't use with typescript. So, I would replace it with export const in all cases in your file, for example:
export const getDay = (timestamp: any) => {
const milliSecond = timestamp;
const dateObject = new Date(milliSecond);
const day = dateObject.getDate();
return day;
};
Regarding usage of this, you usually want to use this when you are located in context of a class, but in your case you have separate functions. So, after changing all export statements, just call the functions directly:
let day = getDay(timestamp);
const year = getYear(timestamp);
let month = getMonth(timestamp);
As for toLocaleString, this is typescript trying to tell you that the value number that you used for minute and hour properties is not a correct value that it supports, and it suggests that you replace it with either numeric, 2-digit, or just not define it (which defaults to undefined). So, statements like this should work:
const minute = dateObject.toLocaleString('en-us', { minute: 'numeric' });
const hour = dateObject.toLocaleString('en-us', { hour: 'numeric' });
IDE usually also gives you hints, for example hovering over a property would tell you what type that property expects. In case of minute it looks like this, which is a union type of 2 string values or undefined. Try hovering over other properties to give you a better idea of what type they expect.
Hope this helps :)

How to parse JSON Date object in NodeJS?

How to parse json date like /Date(1391802454790-0700)/ to (01/31/2014 11:44 AM) in NodeJS.
JSON Date Object:
{
...,
"BirthDate":"\/Date(1391802454790-0700)\/",
...
}
I tried below code but it doesn't work:
var jsondate = "/Date(1391802454790-0700)/";
const data = JSON.parse(jsondate);
console.log(data);
let obj = {
birthday: "/Date(1391802454790-0700)/",
};
let regex = /\(([^)]+)\-\d+/g;
let match = regex.exec(obj.birthday);
if (match) {
console.log(match[1]);
console.log(new Date(Number(match[1]))); // 2014-02-07T19:47:34.790Z - You can use libs to format date
}
uhmm, You just gotta use the value of Birthdate and replace the unwanted characters so you can obtain 1391802454790 part; after that you just need to create a valid date out of this 1391802454790 in the desired format with new Date():
let data = {
...,
"BirthDate":"\/Date(1391802454790-0700)\/",
...
};
let birthdate = data.Birthdate;
birthdate = birthdate.replace("/Date(", "").replace("-0700)/", "");
let formatedBirthdate = new Date(birthdate);

How to handle conditional prepared statements using prisma and postgresql?

I have a search query that its parameters changes depending on the client input.
await prisma.$queryRaw(`SELECT column FROM table ${condition ? `WHERE column = '${condition}'` :' ' } `)
how can I write this query using prepared statement and avoiding duplicate queries. The only solution I came up with is the following:
const result = condition ? await prisma.$queryRaw(`SELECT column FROM table WHERE column = $1`,condition) : await prisma.$queryRaw(`SELECT column FROM table`)
The goal from this is to avoid sql injections from the first query.
EDIT
after trying the solution suggested by #Ryan I got the following error:
Raw query failed. Code: `22P03`. Message: `db error: ERROR: incorrect binary data format in bind parameter 1`
here's my implementation:
const where = Prisma.sql`WHERE ${searchConditions.join(' AND ')}`;
const fetchCount = await prisma.$queryRaw`
SELECT
COUNT(id)
FROM
table
${searchConditions.length > 0 ? where : Prisma.empty}
`;
that will translate to the following in the prisma logs:
Query:
SELECT
COUNT(id)
FROM
table
WHERE $1
["column = something"]
SOLUTION
I had to do a lot of rework to achieve what I want. Here's the idea behind it:
for every search condition you need to do the following:
let queryCondition = Prisma.empty;
if (searchFilter) {
const searchFilterCondition = Prisma.sql`column = ${searchFilter}`;
queryCondition.sql.length > 0
? (queryCondition = Prisma.sql`${queryCondition} AND ${streamingUnitCondition}`)
: (queryCondition = searchFilterCondition);
}
afterwards in the final search query you can do something of this sort:
SELECT COUNT(*) FROM table ${queryCondition.sql.length > 0 ? Prisma.sql`WHERE ${queryCondition}` : Prisma.empty}
You can do it like this:
import { Prisma } from '#prisma/client'
const where = Prisma.sql`where column = ${condition}`
const result = await prisma.$queryRaw`SELECT column FROM table ${condition ? where : Prisma.empty}`
Here is my working version, using Prima.join :
import { Prisma } from '#prisma/client'
const searchConditions: Prisma.Sql[] = []
if (q) {
searchConditions.push(Prisma.sql`column = ${q}`)
}
const where = searchConditions.length ?
Prisma.sql`where ${Prisma.join(searchConditions, ' and ')}` :
Prisma.empty
await prisma.$queryRaw(
Prisma.sql`
select *
from table
${where}
`
)

Firebase NodeJS SDK: Query by value on nested object

I have a collection/table that is structured like this:
{
UsedPromos: {
"userid_1": {
"product_1_1": "promo_1_1",
"product_1_2": "promo_1_2",
...
"product_1_n": "promo_1_n",
},
"userid_2": {
"product_2": "promo_2"
},
...
"userid_m": {
...
}
}
}
How can I query an exact match to some "promo_x_y"? I have tried this so far:
const admin = require("firebase-admin");
admin.initializeApp(...);
const ref = admin.database().ref("/UsedPromos");
ref.orderByValue()
.equalTo("promo_x_y")
.once("child_added")
.then((snapshot) => {
console.log(`{key: ${snapshot.key}, value: ${snapshot.val()}}`);
return snapshot
});
But it didn't return anything.
If you are looking for all products that are part of the promotion promo_x_y, you need to adjust your query one level deeper than what you are currently doing.
Currently you are comparing the values of user_1, user_2, and so on to the value "promo_x_y". You get no results, because no entry /UsedPromos/user_1 = "promo_x_y" exists.
/UsedPromosByUser/{user}/{product} = {promo} (your current structure)
To fix this, you will need to search an individual user's list of products. Using the below snippet will log each product that has a value of "promo_x_y".
const admin = require("firebase-admin");
admin.initializeApp(/* ... */);
const ref = admin.database().ref("/UsedPromos");
const userToSearch = "user_1";
ref.child(userToSearch)
.orderByValue()
.equalTo("promo_x_y")
.once("child_added")
.then((snapshot) => {
// snapshot.val() will always be "promo_x_y", so don't bother logging it.
console.log(`${snapshot.key} uses "promo_x_y"`);
return snapshot;
});
Depending on your use case, it may be better to use a "value" event instead.
const admin = require("firebase-admin");
admin.initializeApp(/* ... */);
const ref = admin.database().ref("/UsedPromos");
const userToSearch = "user_1";
ref.child(userToSearch)
.orderByValue()
.equalTo("promo_x_y")
.once("value")
.then((querySnapshot) => {
const productKeys = [];
// productSnapshot.val() will always be "promo_x_y", so don't bother logging it.
querySnapshot.forEach((productSnapshot) => productKeys.push(productSnapshot.key));
console.log(`The following products have a value of "promo_x_y" for user "${userToSearch}": ${productKeys.join(", "}`);
return productKeys;
});
If you are looking to find all products, across all users, that use "promo_x_y", you should create an index in your database instead of using a query.
/UsedPromosByPromo/{promo}/{user}/{product} = true
OR
/UsedPromosByPromo/{promo}/{product}/{user} = true
Instead of using true in the above structure, you could store a timestamp (time of purchase, time promo expires, etc)

Resources