Comparing dates in Javascript without Timezones - javascript

I'm attempting to get the date based on user's local settings, subtract a day from it and then compare the value with another date value that I'm putting it.
I have tried it with moment.js and even date object of Javascript, using getTime() and then comparing the two dates, but none of them worked for me.
isSame was working when I tested it earlier, but for some reason it isn't working anymore. FYI the date I'm comparing it with(activityDate), I take it from a uploaded xlsx sheet using a upload widget. I need the comparison be timezone independent as user's locale can be anything.
Can anyone point me in the right direction?
Here's the code snippet:
var currentBusinessDate = new Date();
var previousBusinessDate = moment(currentBusinessDate).subtract(1, 'days').toDate();
var previousDate = $scope.getDateCellValueStr(previousBusinessDate, 'DD-MM-YYYY'); //Output: "13-11-2017"
if (moment(activityDate).isSame(previousDate, 'day')) {
uploadData.push(temp);
count = count + 1;
}
//activityDate: "13-11-2017"
//Result: condition returns False

A simple solution could be using setUTCHours: all the dates are going to be set to the same timezone (UTC) and then you will be able to compare them.
const compareWithoutTimezone(date1, date2) => {
const date1UTC = date1.setUTCHours(0, 0, 0, 0);
const date2UTC = date2.setUTCHours(0, 0, 0, 0);
return date1UTC === date2UTC;
}

Related

Add 1 day to date from spreadsheet via Google App Script / Javascript- Month Keeps Reseting to current month

I am trying to set up a Google App Script function that grabs a date (formatted dd/mm/yy) from the last column of a spread, and creates a new column with the date + one day.
I have seen previous solutions and tried to use the same, i.e.newDate.setDate(lastDate.getDate()+1) but have had issues getting the value formatted correctly in the script. This is a variation of my code that I'm using to loop through for a year's worth of values to see what I get:
for (var i=0;i<365;i++){
var lastRow = outputSheet.getLastRow();
var newDate = new Date();
var lastDate = outputSheet.getRange(lastRow,1).getValue();
var newDateRng = outputSheet.getRange(lastRow+1,1);
Logger.log(lastDate + 1, typeof lastDate, typeof (lastDate + 1));
newDate.setDate(lastDate.getDate());
Logger.log(newDate);
newDate.setDate((newDate.getDate() + 1));
Logger.log(newDate);
var newDateFormatted = Utilities.formatDate(newDate, ss.getSpreadsheetTimeZone(), "dd/MM/YY");
Logger.log(newDateFormatted);
newDateRng.setValue(newDateFormatted);
}
With a start date of "01/03/2020", I get the following behaviour:
01/03/2020
02/05/2020
03/05/2020
...
31/05/2020
01/06/2020
02/05/2020
03/05/2020
...
31/05/2020
01/06/2020
02/05/2020
...
etc. All the way through the year. Although the day increase, the month seems to reset after the first day of the month.
As a note, I am specifically looking to pick the date off of the spreadsheet rather than using new Date as today and new Date +1 as tomorrow.
Thanks
You need to use a different variable in the loop otherwise you will always return to the same month.
Also avoid using strings for the result, keep date objects and display it properly.
The code goes like this :
function otherTest(){
var lastDate = SpreadsheetApp.getActiveSheet().getActiveCell().getValue();
var date = new Date(lastDate); // create new date object
var result = [];
for (var i=0;i<365;i++){
date=new Date(date).setDate(new Date(date).getDate()+1)
Logger.log('date='+new Date(date))
result.push([new Date(date)]);
}
SpreadsheetApp.getActiveSheet().getRange(1,2,result.length,1).setValues(result).setNumberFormat('dd/MM/yyyy');
}

MomentJS and JS Date objects not referring to the same hour

I've got a server instance (NodeJS) that receives a set of objects, and schedules them for sending push notifications to users.
Some of these objects, are periodic, and this periodicity is handled by a string like this:
90=>Mon&Tue&Thu=>16:00
Which is read as:
offset_minutes=>days_of_the_week=>initial_hour
Then, what I do is to check whether the current day matches one of the given days in the string, and then, modify the date to the given hour in the "initial_hour", and finally, substract the "offset_minutes" amount of minutes from the Date object.
Seems straightforward until now, right? Well, not that much. Let's first see the code:
const isToday = weekDays.split("&")
.map(a => {
switch (a) {
case 'Mon': return 1;
case 'Tue': return 2;
case 'Wed': return 3;
case 'Thu': return 4;
case 'Fri': return 5;
case 'Sat': return 6;
case 'Sun': return 7;
}
})
.some(v => v == currentDay);
if (isToday) {
let finalDate = moment(today)
.set("hour", Number(hour))
.set("minute", Number(mins));
if (offset) {
finalDate.subtract('minutes', Number(offset));
}
return finalDate.toDate();
Everything works well, until I do the MomentJS transformations. When I output a Date object with the ".toDate()" method, this object is always set to 2 hours before the expected time. But if I use the .toISOString() method, I get the proper time for all the occurrencies.
I guess that something is wrong with my Date objects, setting them up at a different timezone than the one I have. A couple of examples:
For the string 90=>Mon&Tue&Thu=>16:00 I get the Date object: 2019-10-14T14:00:11.852Z
For the string 30=>Mon&Tue&Wed&Thu&Fri&Sat&Sun=>18:30 I get the Date object: 2019-10-14T16:30:11.866Z
I would like to know what's the explanation for such a behavior, and if I can do something to change it so the normal Javascript Date object points to the same hour than my momentjs object, or the .toISOString() output.
Thank you!
The posted code is incomplete and doesn't demonstrate the issue described.
I've reimplemented the code without moment.js as best I can and simplified it. It seems to work fine:
function parseThing(s) {
// Parse input string
let b = s.split('=>');
let offset = +b[0];
let days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
let weekDays = b[1].split('&').map(day => days.indexOf(day));
let [hr, min] = b[2].split(':');
// Get a date for today
let date = new Date();
// If today included, return an adjusted date
if (weekDays.includes(date.getDay())) {
date.setHours(hr, min, 0, 0);
if (offset) {
date.setMinutes(date.getMinutes()+ Number(offset));
}
return date;
}
// If today isn't included, return null
return null;
}
let s0 = '90=>Mon&Tue&Thu=>16:00';
let s1 = '0=>Mon&Tue&Wed&Thu&Fri&Sat&Sun=>18:30';
console.log(parseThing(s0).toString());
console.log(parseThing(s1).toString());
Where the local day is one of those in the string (Mon, Tue, Thu) it returns a Date equivalent to a local time of 17:30, which is 90 minutes offset from 16:00, which seems to be correct.
PS I've changed Sunday to 0 as I can't see any rationale for it to be 7. Also seconds and milliseconds are zeroed too.

Javascript - Comparing dates without time

I am trying to compare two dates in javascript without the time portions. The first date comes from a jquery datepicker and the second date comes from a string.
Although I could swear that my method worked a while ago it looks like it is not working now.
My browser is Firefox but I also need my code to work in IE.
function selectedDateRetentionDaysElapsed() {
var dateSelectedDate = $.datepicker.parseDate('dd/mm/yy', $('#selectedDate').val());
// dateSelectedDate is equal to date 2015-09-30T14:00:00.000Z
var parsedRefDate = isoStringToDate('2015-11-10T00:00:00');
var reportingDate = getPredfinedDateWithoutTime(parsedRefDate);
// reportingDate is equal to date 2015-11-10T13:00:00.000Z
var businessDayCountFromCurrentReportingDate = getBusinessDayCount(dateSelectedDate,reportingDate);
// businessDayCountFromCurrentReportingDate is equal to 39.9583333333336
if (businessDayCountFromCurrentReportingDate >= 40) {
return true;
}
return false;
}
function isoStringToDate(dateStr) {
var str = dateStr.split("T");
var date = str[0].split("-");
var time = str[1].split(":");
//constructor is new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);
return new Date(date[0], date[1]-1, date[2], time[0], time[1], time[2], 0);
}
function getPredfinedDateWithoutTime(myDate) {
myDate.setHours(0,0,0,0)
return myDate;
}
My issues are...
My isoStringToDate function is returning a date with a time even though I am not specifying a time.
The setHours call on a date does not seem to be working either.
Can someone please help me with this.
The simplest way to get the number of whole days between two dates is to create two date objects for the subject dates that are set to the same time. Noon is convenient as it means the date part is unaffected by daylight saving (some places introduce it at midnight) if you happen to print out just the date part.
The following does all calculations in the time zone of the host system. UTC could be used (and the hours set to 0 as daylight saving isn't an issue at all), but it's more to type.
E.g.:
function differenceInDays(d0, d1) {
// Copy dates so don't affect originals
d0 = new Date(+d0);
d1 = new Date(+d1);
// Set to noon
d0.setHours(12,0,0,0);
d1.setHours(12,0,0,0);
// Get difference in whole days, divide by milliseconds in one day
// and round to remove any daylight saving boundary effects
return Math.round((d1-d0) / 8.64e7)
}
// Difference between 2015-11-12T17:35:32.124 and 2015-12-01T07:15:54.999
document.write(differenceInDays(new Date(2015,10,12,17,35,32,124),
new Date(2015,11,01,07,15,54,999)));

Google Form on Submit get values and format the time

I am using Google Apps Script with a Google form. When the user submits the Google Form I get a value from a question. I then take that value and make it a date object, from what I saw on this post about daylight savings I use that to determine the timezone. I run the date object through Utilities.formatDate and want to get the correctly formatted date.
example: 9:00 AM
But instead I am getting a completely different time than expected.
My question is: Can someone help me understand why the below code is outputting a time that is 3 hours different?
function onSubmit(e) {
var values = e.values;
Logger.log(values);
try {
var start1 = new Date(values[3]);
var startN = new Date(start1).toString().substr(25,6)+"00";
var startT = Utilities.formatDate(start1, startN, "h:mm a");
Logger.log(startT);
} catch(error) {
Logger.log(error);
}
}
The assumption that Utilities formatDate does not support GMT... parameter is not true.
The post you mentioned in reference is used to get calendar events and is a useful way to get the right value when you get events from another daylight saving period (getting the TZ info from the calendar event itself), for example events for next month will be in "summer time" while we are still in "winter time"...
Your issue might come from different sources depending on time zone settings of your script vs timezone of the source. Could you describe the exact configuration in which you use this script ?
In the mean time, here is a small code that demonstrates how the code is working + the logger results :
function testOnSubmit() {
var eventInfo = {};
var values = {};
values['3'] = new Date();
eventInfo['values'] = values;
Logger.log('eventInfo = '+JSON.stringify(eventInfo)+'\n\n');
onSubmit(eventInfo);
}
function onSubmit(e) {
var values = e.values;
try {
var start1 = new Date(values[3]);
Logger.log('onSubmit log results : \n');
Logger.log('start1 = '+start1)
var startN = new Date(start1).toString().substr(25,6)+"00";
Logger.log('startN = '+startN);
var startT = Utilities.formatDate(start1, startN, "h:mm a");
Logger.log('result in timeZone = '+startT);
} catch(error) {
Logger.log(error);
}
}
EDIT : additionally, about the 30 and 45' offset, this can easily be solved by changing the substring length like this :
var startN = new Date(start1).toString().substr(25,8);
the result is the same, I had to use the other version a couple of years ago because Google changed the Utilities.formatDate method at some moment (issue 2204) but this has been fixed.
EDIT 2 : on the same subject, both methods actually return the same result, the GMT string has only the advantage that you don't have to know the exact timezone name... there is also the Session.getScriptTimeZone() method. Below is a demo script that shows the resulst for 2 dates in January and July along with the log results :
function testOnSubmit() {
var eventInfo = {};
var values = {};
values['3'] = new Date(2014,0,1,8,0,0,0);
eventInfo['values'] = values;
Logger.log('eventInfo = '+JSON.stringify(eventInfo)+'\n\n');
onSubmit(eventInfo);
values['3'] = new Date(2014,6,1,8,0,0,0);
eventInfo['values'] = values;
Logger.log('eventInfo = '+JSON.stringify(eventInfo)+'\n');
onSubmit(eventInfo);
}
function onSubmit(e) {
var values = e.values;
var start1 = new Date(values[3]);
Logger.log('onSubmit log results : ');
Logger.log('start1 = '+start1)
var startN = new Date(start1).toString().substr(25,8);
Logger.log('startN = '+startN);
Logger.log('result in timeZone using GMT string = '+Utilities.formatDate(start1, startN, "MMM,d h:mm a"));
Logger.log('result in timeZone using Joda.org string = '+Utilities.formatDate(start1, 'Europe/Brussels', "MMM,d h:mm a"));
Logger.log('result in timeZone using Session.getScriptTimeZone() = '+Utilities.formatDate(start1, Session.getScriptTimeZone(), "MMM,d h:mm a")+'\n');
}
Note also that the Logger has its own way to show the date object value ! it uses ISO 8601 time format which is UTC value.
Try this instead:
var timeZone = Session.getScriptTimeZone();
var startT = Utilities.formatDate(start1, timeZone, "h:mm a");
The Utilities.formatDate function expects a time zone that is a valid IANA time zone (such as America/Los_Angeles), not a GMT offset like GMT+0700.
I am making the assumption that Session.getScriptTimeZone() returns the appropriate zone. If not, then you might need to hard-code a specific zone, or use a different function to determine it.
Additionally, the +"00" in the script you had was assuming that all time zones use whole-hour offsets. In reality, there are several that have 30-minute or 45-minute offsets.

Javascript - Convert ####-##-## to Epoch time

Is there a way to take a date object from a HTML object in the format of ####-##-## and convert it to epoch time. For example, the user inputs the value of August 12, 2012 which shows as 2012-08-12 when I print out the .val() of it, and I need to get this in Epoch time.
EDIT
Code to date:
if (hvStartDate == "") {
hvStartDate = "start"
}
else {
console.log($("#hv-start-date").val()); // => 2012-08-20
hvStartDate = new Date($("#hv-start-date").val()).getTime(); // => NaN
}
if (hvEndDate == "") {
hvEndDate = "end"
}
else {
hvEndDate = new Date($("#hv-end-date").val()).getTime(); // => NaN
}
var myTmp = new Date("2012-08-20");
console.log(myTmp.getTime()); // => NaN
Javascript's Date built-in allows you to pass a date string into its constructor, giving you a Date based on that string. From there, calling getTime( ) will give you the epoch time.
new Date($('.user-value').val()).getTime(); // => epoch time
new Date('2012-08-12').getTime(); // 1344729600000
Caveat: Beware of locale strings and locale-specific date formatting (for example, the position of days and months switch depending on locale).
EDIT: Based on your code in the comment below, here's what you need to do. Notice that you have to instantiate a new Date Object before calling getTime():
if (hvStartDate == "") {
hvStartDate = "start"
}
else {
hvStartDate = new Date($("#hv-start-date").val()).getTime();
}
Simply use the getTime() function. It returns the number of milliseconds since Epoch :
var msSinceEpoch = myDate.getTime();
Complete Date reference at MDN : https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date
EDIT : if you have to parse it too, you may :
use new Date(theString) if it has the good format
set yourself the different date fields (see reference) after having parsed it
use a date parsing library. I use this one : http://www.datejs.com/ which is very powerful for all date parsing, computing and formating.

Categories

Resources