How to save a birthdate in Mongoose without throwing validation error - node.js

In my User model in Mongoose, I have a simple dob field with no format validation:
dob: {
type: Date,
alias: 'birthdate'
},
Elsewhere in my code I am formatting three separate user-entered fields for day, month, and year. I am returning this as a new Date() but with a format of YYYY-MM-DD to avoid any weird timezone complications. The date is the date and time doesn't matter.
exports.formatDob = function (day, month, year) {
let dob = new Date( parseInt(year), parseInt(month) - 1, parseInt(day), 0, 0, 0, 0 );
return new Date(dob, '<YYYY-MM-DD>');
}
When I try to save this formatted date into Mongoose, I get the following error in my console:
(node:32307) UnhandledPromiseRejectionWarning: ValidationError: User
validation failed: dob: Cast to Date failed for value "Invalid Date"
at path "dob"
What am I doing wrong?

You can use Momentjs it's always recommended when it comes to working with dates.
However we can work around this just as easy as working with the Date obj api available methods for example if we want to return the format YYYY-MM-DD from a Date object we can just do the following:
let dob = new Date( parseInt(year), parseInt(month) - 1, parseInt(day));
return dob.getFullYear() + '-' + (dob.getMonth() + 1) + '-' + dob.getDate();
let dob = new Date();
console.log( dob.getFullYear() + '-' + (dob.getMonth() + 1) + '-' + dob.getDate() );
Notice we have added + 1 to getMonth method because it returns a value for 0-11 and also we have added this expression inside parentheses so it is not evaluated as a string.

Related

How to set time in Netsuite using suitescript 2.0?

I can set time for timeofday type fields both UI/API.
I can set time for the time type field INITIAL TIME BUDGET as 16:55 using colon(:) separator in UI for Task.
I could not set time for that field as below using suitescript,
function load(recordType, id) {
return record.load({
type: recordType,
id: id
});
}
var recordType = "task"
var id = "123"
var objectRecord = load(recordType, id);
objectRecord.setValue("estimatedtime", "16:55");
var updatedId = objectRecord.save({});
I get this error
You have entered an Invalid Field Value 16:55 for the following field: estimatedtime
I tried the following cases,
"16:55" - Invalid Field Value
16:55 - UNEXPECTED_ERROR
16.55 - No error, but set as "estimatedtime":"16:33"
How to set time for time type field?
You need to create a Date object. For example, say you pass "13:00", you'll need to do something like:
dateStr = "13:00";
d = new Date();
dateParts = dateStr.split(":");
d.setHours(+dateParts[0]);
d.setMinutes(+dateParts[1]);
And then:
objectRecord.setValue("estimatedtime", d);
you have to set only hour value.
Format has to 24 hours.
objectRecord.setValue("estimatedtime", 23);

Wrong date format with toLocaleString on server side

Using this on a server side (a Firebase function, nodejs )
var d=new Date();
var date = d.toLocaleString('default', { month: 'long'}) + ", " + d.getFullYear();
I am expecting to get March, 2020 , since this is what i get on the JS client side, but instead when run on the server side i get - M03, 2020 .
I tried the following code:
const date = require('date-and-time');
var d = new Date();
var myDate = d.toLocaleString('default', { month: 'long'}) + ", " + d.getFullYear();
console.log(myDate);
Output:
March, 2020
Now, if you are trying to store a Javascript Date object into Firebase, this object will be stored as a Timestamp object. I think this would explain the reason why you are noticing some discrepancies in the format.
Optionally, you can convert the Date object to String and store it in Firebase as such. This is more human-readable than ISO 8601 and Timestamp - 0001-01-01T00:00:00Z
You can read more about this in the following documentation about Timestamp and Data types. Moreover, there exists a Timestamp built-in method toDate() that returns a new Date corresponding to a certain timestamp, if conversion is needed.

How to determine two date is same day at local time in nodejs?

Here are two date, 2015-11-10 09:00:00+08:00 and 2015-11-10 01:00:00+08:00 is same day in China. But they are different day in UTC.
So... How can I determine two UTC date is same day at different timezone in node.js?
Sorry for my ambiguous description and poor English.
I have two strings: start_time and end_time. And clint upload two other strings: timezone_str, utc_time_str.
I want to determine the client time is between start and end time.
e.g
start_time: 2015-11-10 00:00:00
end_time: 2015-11-11 00:00:00
utc_time_str: 2015-11-10 02:00:00Z
timezone_str: America/New_York
except client_time.isBetween(start_time, end_time) == false.
Thanks to #Matt Johnson's answer, moment-timezone can solve my problem.
client_time = moment(utc_time_str).tz(timezone_str);
start = moment.tz(start_time, timezone_str);
end = moment.tz(end, timezone_str);
client_time.isBetween(start, end) === false
The most reliable way would be to use the parseZone function in moment.js to retain the provided offset. Then use the isSame function with the 'day' argument, which tests for same year, month, and day.
var m1 = moment.parseZone("2015-11-10 09:00:00+08:00");
var m2 = moment.parseZone("2015-11-10 01:00:00+08:00");
if (m1.isSame(m2, 'day')) {
// ...
}
With this approach, it does not matter what offset was given, nor does it matter what the time zone is on the computer where the code is running. It simply compares the two dates as provided.
calculate local "hours" like this
var d1 = new Date('2015-11-10 09:00:00+08:00')
var d2 = new Date('2015-11-10 01:00:00+08:00')
var h1 = d1.getHours() - d1.getTimezoneOffset() / 60
var h2 = d2.getHours() - d2.getTimezoneOffset() / 60
var date1 = d1.getDate() + (h1 >= 24? 1: 0)
var date2 = d2.getDate() + (h2 >= 24? 1: 0)
just compare date1 and date2
Solution without MomentJS
If you have the timezone string of the user that is in accordance with the tz database, such as "America/New_York" — which you can get client side for example by doing: const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
Then you could, for each date, create a new date with the timezone offset added to the original date, for example by doing const dateInTimezone = new Date(new Date(myDate).toLocaleString("en-US", { timeZone: timezone }));
And then reset the time values to exactly midnight of the same day by doing dateInTimezone.setHours(0, 0, 0, 0);
Then you could compare the milliseconds since Epoch values (date we start counting UTC from) of the two dates to see whether they start in the same day or not: const isSameDay = startOfDate1.valueOf() === startOfDate2.valueOf();
Ideally, your starting dates would always be in UTC, since both your server and client could be in all sorts of timezones. So before storing the data, convert the original date to its UTC version in milliseconds since Epoch, by doing myOrignalDate.valueOf() or myOrignalDate.getTime() — this way, you will ensure that timezone offsets added later will be true.
Example
function isSameDayInTimezone(d1, d2, timezone) {
const start_of_d1 = new Date(new Date(d1).toLocaleString("en-US", { timeZone: timezone })).setHours(0, 0, 0, 0).valueOf();
const start_of_d2 = new Date(new Date(d2).toLocaleString("en-US", { timeZone: timezone })).setHours(0, 0, 0, 0).valueOf();
return start_of_d1 === start_of_d2;
}
/* Initialize dates. Note that this will be the UTC time as milliseconds since
Epoch of the date in whichever timezone it was originally captured in. If I
capture it in my timezone, it would currently be UTC/GMT+3, hence if I were
to want to perform server-side actions taking into account my timezone, I'd
also need to capture my tz database timezone string first, to then be able
to, server-side, add my timezone offset to the captured UTC time. */
const date1 = new Date('August 31, 2022 20:16:00').valueOf();
const date2 = new Date('August 31, 2022 23:50:00').valueOf();
const date3 = new Date('August 31, 2022 00:00:00').valueOf();
const date4 = new Date('August 30, 2022 15:00:00').valueOf();
const fixedTimezone = "Europe/Tallinn";
const localTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
/* With fixed timezone */
console.log(isSameDayInTimezone(date1, date2, fixedTimezone));
console.log(isSameDayInTimezone(date1, date3, fixedTimezone));
console.log(isSameDayInTimezone(date1, date4, fixedTimezone));
/* With local timezone */
console.log(isSameDayInTimezone(date1, date2, localTimezone));
console.log(isSameDayInTimezone(date1, date3, localTimezone));
console.log(isSameDayInTimezone(date1, date4, localTimezone));
Voila, no MomentJS needed.

Query date with offset in AQL

I have this document:
{
paymentDate: '2015-08-08T23:41:23.909Z'
}
my local time is GMT+7 hence the date above is 2015-08-09 6:41:23 in my local time.
I want to send this query below, and receive above document
{
date: '2015-08-09',
offset: '+7'
}
What is the best way to achive that in AQL ?
as can be read in the documentation about dates, ArangoDBs native format JSON doesn't know a special date format, and thus its suggested to store dates as strings.
Best practice is to store UTC in the Database and convert it into the users timezone in the application.
Therefore a query would use FILTER and string comparison to select ranges:
arangosh> db._create("exampleTime");
[ArangoCollection 729616498254, "exampleTime" (type document, status loaded)]
arangosh> var timestamps = ["2014-05-07T14:19:09.522","2014-05-07T21:19:09.522","2014-05-08T04:19:09.522","2014-05-08T11:19:09.522","2014-05-08T18:19:09.522"];
arangosh> for (i = 0; i < 5; i++) db.exampleTime.save({value:i, ts: timestamps[i]})
arangosh> db._query("FOR d IN exampleTime FILTER d.ts > '2014-05-07T14:19:09.522' and d.ts < '2014-05-08T18:19:09.522' RETURN d").toArray()
[
{
"value" : 2,
"ts" : "2014-05-08T04:19:09.522",
"_id" : "exampleTime/729617284686",
"_rev" : "729617284686",
"_key" : "729617284686"
},
{
"value" : 1,
"ts" : "2014-05-07T21:19:09.522",
"_id" : "exampleTime/729617088078",
"_rev" : "729617088078",
"_key" : "729617088078"
},
{
"value" : 3,
"ts" : "2014-05-08T11:19:09.522",
"_id" : "exampleTime/729617481294",
"_rev" : "729617481294",
"_key" : "729617481294"
}
]
If your local time in timezone GMT+7 is 2015-08-09 6:41:23, the JavaScript code new Date().toISOString() would return "2015-08-08T23:41:23.000Z" in that moment. As you can see, it returns UTC time. Your computer needs to have the correct date, time and timezone configured of course.
If you want to query for a date in the past or future, and that date is in local time, you can construct an ISO8601 string with timezone offset specified. Let's say we want to know what 2011-01-01 2:00:00 in GMT+7 is in UTC time:
// timezone offset: 07 hours, 00 minutes (+0700)
new Date("2011-01-01T02:00:00+0700").toISOString()
// result: "2010-12-31T19:00:00.000Z"
The same works in AQL:
RETURN DATE_ISO8601("2011-01-01T02:00:00+0700")
// result: "2010-12-31T19:00:00.000Z"
If you already have a datetime string without timezone offset (2011-01-01T02:00:00), but want to assume it's your local time, you can do the following in JS to append the timezone offset:
// Should return -420 for your timezone GMT+7.
// You can supply an offset in minutes manually as well of course.
var offset = new Date().getTimezoneOffset()
var offsetHours = offset / 60 | 0
var offsetMinutes = Math.abs(offset % 60)
var offsetStr = ((offsetHours < 0) ? "+" : "-") + // GMT + or -?
((Math.abs(offsetHours) < 10) ? "0" : "") + // leading zero for single digit
Math.abs(offsetHours) + // hour portion
((offsetMinutes < 10) ? "0" : "") + // leading zero for single digit
offsetMinutes // minute portion
var dateStr = "2011-01-01T02:00:00" + offsetStr
console.log(dateStr)
console.log(new Date(dateStr).toISOString())
// on a GMT+7 machine, result should be:
// "2011-01-01T02:00:00+0700"
// "2010-12-31T19:00:00.000Z"
If the date string is in local time, but Zulu timezone offset was somehow added, you could correct it by 7 hours like this:
// It should had been +0700 and not +0000
var d = new Date("2015-08-09T06:41:23Z").getTime() - 7 * 60 * 60 * 1000
// result: 1439077283000, which is 2015-08-08T23:41:23.000Z
// or in a really hacky way:
new Date("2015-08-09T06:41:23Z".replace("Z", "+0700"))
//edit
this seems to work too:
var d = new Date("2015-08-09T06:41:23Z")
d.setHours(d.getHours() - 7)
This seems to work reliably even if you cross start or end datetime of DST, at least in Firefox. There was a bug in Chrome however, which led to completely off date calculations: https://code.google.com/p/v8/issues/detail?id=3116

How do I display todays date in Node.js Jade?

I am new to Node.js and Jade and I have tried to use #{Date.now()} and it's giving me numbers. How do I display the date in mm/dd/yy format?
You can use moment.js
First, add moment to your express application locals
express = require('express');
...
app = express();
app.locals.moment = require('moment');
Then you can use moment within a jade template like this:
p #{moment(Date.now()).format('MM/DD/YYYY')}
Moment takes Date.now() by default, so yo can also write:
p #{moment().format('MM/DD/YYYY')}
Sources:
Making use of utility libraries in server-side Jade templates
Moment.js
This is old, but I do the following:
return (new Date()).toLocaleDateString()
Returns a date 'mm/dd/yyyy' format, in no additional libs required.
Or you could use the moment.js library to handle dates and format them accordingly to your needs
I actually started using date-util which is 2 parts both clientside and server side.
URL https://github.com/JerrySievert/node-date-utils
Using within a Browser
<script type="text/javascript" src="date-utils.min.js"></script>
Using with Node.js
$ npm install date-utils
require('date-utils');
Note: This did not work in the REPL before Node.js 0.6 due to how Node.js handles context in the REPL.
Static Methods
Date.today(); // today, 00:00:00
Date.yesterday(); // yesterday, 00:00:00
Date.tomorrow(); // tomorrow, 00:00:00
Date.validateDay(day, year, month); // true/false whether a date is valid
Date.validateYear(year); // true/false whether a year is valid
Date.validateMonth(month); // true/false whether a month is valid
Date.validateHour(hour); // true/false whether an hour is valid
Date.validateMinute(minute); // true/false whether a minute is valid
Date.validateSecond(second); // true/false whether a second is valid
Date.validateMillisecond(millisecond); // true/false whether a millisecond is valid
Date.compare(date1, date2); // -1 if date1 is smaller than date2, 0 if equal, 1 if date2 is smaller than date1
Date.equals(date1, date2); // true/false if date1 is equal to date2
Date.getDayNumberFromName(name); // su/sun/sunday - 0, mo/mon/monday - 1, etc
Date.getMonthNumberFromName(name); // jan/january - 0, feb/february - 1, etc
Date.isLeapYear(year); // true/false whether the year is a leap year
Date.getDaysInMonth(monthNumber); // number of days in the month
Instance Methods
d.clone(); // returns a new copy of date object set to the same time
d.getMonthAbbr(); // abreviated month name, Jan, Feb, etc
d.getMonthName(); // fill month name, January, February, etc
d.getUTCOffset(); // returns the UTC offset
d.getOrdinalNumber(); // day number of the year, 1-366 (leap year)
d.clearTime(); // sets time to 00:00:00
d.setTimeToNow(); // sets time to current time
d.toFormat(format); // returns date formatted with:
// YYYY - Four digit year
// MMMM - Full month name. ie January
// MMM - Short month name. ie Jan
// MM - Zero padded month ie 01
// M - Month ie 1
// DDDD - Full day or week name ie Tuesday
// DDD - Abbreviated day of the week ie Tue
// DD - Zero padded day ie 08
// D - Day ie 8
// HH24 - Hours in 24 notation ie 18
// HH - Padded Hours ie 06
// H - Hours ie 6
// MI - Padded Minutes
// SS - Padded Seconds
// PP - AM or PM
// P - am or pm
d.toYMD(separator); // returns YYYY-MM-DD by default, separator changes delimiter
d.between(date1, date2); // true/false if the date/time is between date1 and date2
d.compareTo(date); // -1 if date is smaller than this, 0 if equal, 1 if date is larger than this
d.equals(date); // true/false, true if dates are equal
d.isBefore(date); // true/false, true if this is before date passed
d.isAfter(date); // true/false, true if this is after date passed
d.getDaysBetween(date); // returns number of full days between this and passed
d.getHoursBetween(date); // returns number of hours days between this and passed
d.getMinutesBetween(date); // returns number of full minutes between this and passed
d.getSecondsBetween(date); // returns number of full seconds between this and passed
d.add({ milliseconds: 30,
minutes: 1,
hours: 4,
seconds: 30,
days: 2,
weeks: 1,
months: 3,
years: 2}); // adds time to existing time
d.addMilliseconds(number); // add milliseconds to existing time
d.addSeconds(number); // add seconds to existing time
d.addMinutes(number); // add minutes to existing time
d.addHours(number); // add hours to existing time
d.addDays(number); // add days to existing time
d.addWeeks(number); // add weeks to existing time
d.addMonths(number); // add months to existing time
d.addYears(number); // add years to existing time
You will need to use the methods on the Date object to achieve what you're after. See https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date
For example, the code below should do what you need:
var dateNow = new Date();
var dd = dateNow.getDate();
var monthSingleDigit = dateNow.getMonth() + 1,
mm = monthSingleDigit < 10 ? '0' + monthSingleDigit : monthSingleDigit;
var yy = dateNow.getFullYear().toString().substr(2);
var formattedDate = mm + '/' + dd + '/' + yy;
So if you were using say jade with express and node you could do something like:
res.render('jadeTemplateName', {
dateNow: function() {
var dateNow = new Date();
var dd = dateNow.getDate();
var monthSingleDigit = dateNow.getMonth() + 1,
mm = monthSingleDigit < 10 ? '0' + monthSingleDigit : monthSingleDigit;
var yy = dateNow.getFullYear().toString().substr(2);
return (mm + '/' + dd + '/' + yy);
}
})
and in your jade template say if you wanted to add the date to a span:
span Today's date is #{dateNow()}
add the class .post-date to a tag holding the date
document.addEventListener('DOMContentLoaded', function() {
var list = document.getElementsByClassName('post-date');
// get the number of selected elements
// iterate over elements and output their HTML content
for (var i=0; i<list.length; i++){
//console.log(list[i].innerHTML);
var string=list[i].innerHTML;
var length = 15;
var trimmedString = string.substring(0, length);
list[i].innerHTML=trimmedString ;
}
})
I found a solution
1.Create a function in pug using - syntax
2.pass the varible to the function when pug.js is binding variables to the pug template
-function prettyDate(dateString){
-var date = new Date(dateString);
-var d = date.getDate();
-var monthNames = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun","Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
-var m = monthNames[date.getMonth()];
-var y = date.getFullYear();
-return d+' '+m+' '+y;
-}
3.span.post-date #{prettyDate(val.date)};

Resources