Weird date issue in javascript - javascript

I have a SharePoint list with delivery date column. I have created a table to display current week and next week delivery items using javascript. Everything works fine but for couple of team members Thursday delivery items are displaying in Wednesday cell and Friday items in Thursday cell.
I am not sure why it is happening. Can anyone help me out to resolve this issue? Any help would be greatly appreciated.
Here is my code. Added alerts to verify data, I am wondering why in second and third alerts sunday is showing Monday date and in third alert monday is showing Tuesday date. Added alert messages at the bottom. Please advice.
today = moment();
sundayDate = new Date(today.startOf('week'));
sundayShortDate = sundayDate.toLocaleDateString();
sundayTitle = getFormattedDate(sundayDate);
window.alert("sundayDate ::"+sundayDate+"");
monDate = new Date(sundayDate.setDate(sundayDate.getDate() + 1));
monSDate = monDate.toLocaleDateString();
monTitle = getFormattedDate(monDate);
window.alert("sundayDate ::"+sundayDate+"; monDate::"+monDate+"");
tueDate = new Date(monDate.setDate(monDate.getDate() + 1));
tuesSDate = tueDate.toLocaleDateString();
tueTitle = getFormattedDate(tueDate);
window.alert("sundayDate ::"+sundayDate+"; monDate::"+monDate+"; tueDate::"+tueDate+"");
First window alert:
sundayDate ::Sun Aug 16 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
Second Alert:
sundayDate ::Mon Aug 17 2020 00:00:00 GMT-0400 (Eastern Daylight Time); monDate::Mon Aug 17 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
Third Alert:
sundayDate ::Mon Aug 17 2020 00:00:00 GMT-0400 (Eastern Daylight Time); monDate::Tue Aug 18 2020 00:00:00 GMT-0400 (Eastern Daylight Time); tueDate::Tue Aug 18 2020 00:00:00 GMT-0400 (Eastern Daylight Time)

As was already commented, you are mutating the dates with calls to setDate().
As you already use moment, don't switch back to Date objects, but stick to moment objects.
For example:
let today = moment();
let fmt = "dddd, MMMM Do YYYY";
let sunDate = today.startOf('week');
let sunShortDate = sunDate.format(fmt);
let monDate = sunDate.clone().add(1, "day");
let monShortDate = monDate.format(fmt);
let tueDate = monDate.clone().add(1, "day");
let tueShortDate = tueDate.format(fmt);
console.log({ sunShortDate, monShortDate, tueShortDate });
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.0/moment.min.js"></script>
Just like Date objects, also moment objects are mutable, and so you should call clone first before calling add.

You set sundayDate to sundayDate.setDate(sundayDate.getDate() + 1)
You should do:
monDate = new Date(sundayDate.getDate() + 1);
P.S.
I'm not sure if mixing moment.js and js Date is a good idea.

Related

How to set start day time to particular time in momentjs

I'm trying to set the start time of the day to a particular time. currently, in momentjs, I can get startOf day like this
let now = moment()
console.log('now', now.toString())
console.log('start Day', now.startOf('day').toString()) // Thu Oct 07 2021 00:00:00 GMT+0530
console.log('end day', now.endOf('day').toString()) //Thu Oct 07 2021 23:59:59 GMT+0530
is there any way so I can set my day start from particular time like I want to start my day from
Thu Oct 07 2021 08:00:00 GMT+0530
and end on
Thu Oct 07 2021 07:59:59 GMT+0530
You should probably write your own function in order to achieve this.
function customStartOf(momentObj) {
return momentObj.clone().startOf('day').hours(8);
}
function customEndOf(momentObj) {
// I assume that end of the day is bigger than start of the day
return momentObj.clone().endOf('day').add(1, 'days').hours(7);
}
let now = moment();
console.log('now', now.toString()) ;
console.log('start Day', now.startOf('day').toString());
console.log('end day', now.endOf('day').toString());
console.log('custom start Day', customStartOf(now).toString());
console.log('custom end day', customEndOf(now).toString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
You have to take into account the timezone.
let myDate = new Date();
const timezoneOffset = moment(myDate).utcOffset();
moment(myDate).utc().add(timezoneOffset, 'minutes').startOf('day').format();
moment(myDate).utc().add(timezoneOffset, 'minutes').endOf('day').format();

Javascript UTC timezone does not work in Firefox

Below code doesn't work with Firefox, Works perfectly fine with Chrome. Can someone please help me to find an alternate solution?
const tempDate = getStartDate['startDate']; // Returns: 2020-08-13 12:52:38
new Date(`${tempDate} UTC`);
Expected Output: Thu Aug 13 2020 08:52:38 GMT-0400 (Eastern Daylight Time)
You're trying to do:
new Date('2020-08-13 12:52:38 UTC')
Instead you should do:
new Date('2020-08-13T12:52:38Z')
See https://www.ecma-international.org/ecma-262/11.0/index.html#sec-date-time-string-format
maybe you can use moment: https://www.npmjs.com/package/moment
var d = new Date(`Wed Aug 12 2020 18:34:35 GMT-0400 (Eastern Daylight Time) UTC`);
var date = moment(d).utc().format()
console.log("date: ", date )

How to keep unique months in array of timestamps

I want to create an array that contains unique months (August 2015, September 2015 etc.). For this I defined the following function that takes an object with timestamps as keys:
export function getUniqueMonths(exps) {
//1. get all keys from expenditures
const days = Object.keys(exps)
//2. convert key strings to timestamps
const daysInt = days.map((day) => (new Date(parseInt(day))))
//3. return only the "date portion" of the timestamp
const datePortion = daysInt.map((day) => (new Date(day.toDateString()) ))
//4. set each datePortion to 1st of month
const firstOfMonth = datePortion.map((day) => new Date(day.getFullYear(), day.getMonth(), 1) )
//5. keep only unique firstOfMonths
const uniqMonths = [...(new Set(firstOfMonth))]
return uniqMonths
}
However, this function gives me an array like this:
[Sat Aug 01 2015 00:00:00 GMT+0300 (Eastern European Summer Time), Sat Aug 01 2015 00:00:00 GMT+0300 (Eastern European Summer Time), Tue Sep 01 2015 00:00:00 GMT+0300 (Eastern European Summer Time), Sat Aug 01 2015 00:00:00 GMT+0300 (Eastern European Summer Time), Sat Aug 01 2015 00:00:00 GMT+0300 (Eastern European Summer Time), ...]
I thought getting the date portion of the timestamp (step 3) and setting all dates to first of month (step 4) would do the trick. But I still have duplicates in my array.
What am I missing?
I think you might be overengineering things :) Something like
function getUniqueMonths(exps) {
const uniqueMonths = new Set();
Object.keys(exps).forEach((timestamp) => {
const date = new Date(parseInt(timestamp)); // expected to be milliseconds since 1/1/1970
uniqueMonths.add(`${date.getFullYear()}-${date.getMonth()}`);
});
return uniqueMonths;
}
should get you a Set of unique months in the form of ['2017-12', '2018-0', ...] (zero-based months as is the JavaScript standard).
If you need Date objects, those are trivial to "rehydrate".
Two Date objects are not the same object, even if they contain the same timestamp.
Instead, try:
//3. keep the year-month portion of the date
const yearMonths = daysInt.map(day => day.getFullYear()+"-"+day.getMonth());
Then you can skip 4 and just get the unique year-months from there. These will be returned as "2015-7" for August 2015, for example.

How to set date always to eastern time regardless of user's time zone

I have a date given to me by a server in unix time: 1458619200000
NOTE: the other questions you have marked as "duplicate" don't show how to get there from UNIX TIME. I am looking for a specific example in javascript.
However, I find that depending on my timezone I'll have two different results:
d = new Date(1458619200000)
Mon Mar 21 2016 21:00:00 GMT-0700 (Pacific Daylight Time)
// Now I set my computer to Eastern Time and I get a different result.
d = new Date(1458619200000)
Tue Mar 22 2016 00:00:00 GMT-0400 (Eastern Daylight Time)
So how can I show the date: 1458619200000 ... to always be in eastern time (Mar 22) regardless of my computer's time zone?
You can easily take care of the timezone offset by using the getTimezoneOffset() function in Javascript. For example,
var dt = new Date(1458619200000);
console.log(dt); // Gives Tue Mar 22 2016 09:30:00 GMT+0530 (IST)
dt.setTime(dt.getTime()+dt.getTimezoneOffset()*60*1000);
console.log(dt); // Gives Tue Mar 22 2016 04:00:00 GMT+0530 (IST)
var offset = -300; //Timezone offset for EST in minutes.
var estDate = new Date(dt.getTime() + offset*60*1000);
console.log(estDate); //Gives Mon Mar 21 2016 23:00:00 GMT+0530 (IST)
Though, the locale string represented at the back will not change. The source of this answer is in this post. Hope this helps!
Moment.js (http://momentjs.com/timezone) is your friend.
You want to do something like this:
var d = new Date(1458619200000);
var myTimezone = "America/Toronto";
var myDatetimeFormat= "YYYY-MM-DD hh:mm:ss a z";
var myDatetimeString = moment(d).tz(myTimezone).format(myDatetimeFormat);
console.log(myDatetimeString); // gives me "2016-03-22 12:00:00 am EDT"
For daylight saving, Eastern time become 4 hours behind UTC. That's why its offset is -4x60 = -240 minutes. So when daylight is not active the offset will be -300. The offset variable's value is the key point to be noted here. Kindly see this code in action in attached image.
var offset = new Date().getTimezoneOffset();// getting offset to make time in gmt+0 zone (UTC) (for gmt+5 offset comes as -300 minutes)
var date = new Date();
date.setMinutes ( date.getMinutes() + offset);// date now in UTC time
var easternTimeOffset = -240; //for dayLight saving, Eastern time become 4 hours behind UTC thats why its offset is -4x60 = -240 minutes. So when Day light is not active the offset will be -300
date.setMinutes ( date.getMinutes() + easternTimeOffset);

Array Of JS Dates How To Group By Days

I'm trying to figure out the most optimal and with as minimum amount of loops way to group my array of js dates objects from this: (Take a note this is browser console output it's actully real JS dates like new Date())
[Sat Aug 08 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sat Aug 08 2015 09:30:00 GMT+0200 (Central Europe Daylight Time), Sun Aug 09 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sun Aug 09 2015 09:30:00 GMT+0200 (Central Europe Daylight Time), Mon Aug 10 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Mon Aug 10 2015 23:00:00 GMT+0200 (Central Europe Daylight Time), Tue Aug 11 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Tue Aug 11 2015 23:00:00 GMT+0200 (Central Europe Daylight Time), Wed Aug 12 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Wed Aug 12 2015 23:00:00 GMT+0200 (Central Europe Daylight Time)]
to oragnized array with each date of the same day inside a "chunk" so I can display it on the UI "Aug 08" and show 2 or how many dates inside that day.
for example:
[{day: 'Aug 08', times:[Sat Aug 08 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sat Aug 08 2015 09:30:00 GMT+0200 (Central Europe Daylight Time)]}]
My current way I thought about doing it was
var startDays = _.map(occurences, function (date) {
return moment(date).startOf('day').format();
});
After that to get unique days:
_.uniq(startDays, true)
and after I got the unique days another loop to add the same day to this group as you can see by now you might see why I don't like it and this is why I would love to get some smart help because nothing gets to my head with this. Thank you.
Underscore has the _.groupBy function which should do exactly what you want:
var groups = _.groupBy(occurences, function (date) {
return moment(date).startOf('day').format();
});
This will return an object where each key is a day and the value an array containing all the occurrences for that day.
To transform the object into an array of the same form as in the question you could use map:
var result = _.map(groups, function(group, day){
return {
day: day,
times: group
}
});
To group, map and sort you could do something like:
var occurrenceDay = function(occurrence){
return moment(occurrence).startOf('day').format();
};
var groupToDay = function(group, day){
return {
day: day,
times: group
}
};
var result = _.chain(occurences)
.groupBy(occurrenceDay)
.map(groupToDay)
.sortBy('day')
.value();
Presuming your data is actually strings, I don't know why you think you need either of those libraries. You are just grouping strings based on substrings.
ES5 introduced reduce, which is great for accumulating things:
A helper to create an array of dates:
// Generate a dates array given a start date and how many to create:
function genDates(startDate, count) {
var d = new Date(+startDate),
dates = [d];
for (var i=0; i<count; i++) {
d = new Date(+d);
d.setHours(d.getHours() + 10);
dates.push(d);
}
return dates;
}
This answer originally dealt with strings, modified to work with Dates:
// Generate date key 'MMM dd'
// Replaces use of moment.js
function getDateKey(date) {
var d = date.getDate();
var m = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
return m[date.getMonth()] + ' ' + ((d<10?'0':'') + d);
}
// Generate an array in format [{day:'MMM dd', times:[d0, d1, ...]}, ...]
// Replaces use of underscore.js
var obj = dates.reduce(function(acc, d) {
var p = getDateKey(d)
if (!acc[0].hasOwnProperty(p)) acc[0][p] = [];
acc[0][p].push(d);
return acc;
},[{}])
.reduce(function(acc, v){
Object.keys(v).forEach(function(k){acc.push({day:k, times:v[k]})});
return acc;
},[]);
console.log(JSON.stringify(obj));
If optimal performance is the key, the above is 20 times faster than the underscore + Moment solution for an array of 5 to 100 dates. To make it faster, remove all use of iterators and libraries and use a single function with for loops. Note that the above is only one line of code longer than the solution using Moment.js and underscore.js.
If you need to grouping also by year or (and) month with day - I recommend to use my solution.
In answers above if you'll get different month or year with the same day - your grouping will be incorrect.
Look at the good solution:
_.groupBy(arrayOfDates, function (el) {
return (el.getFullYear() + '|y|') + (el.getMonth() + '|m|') + (el.getDate() + '|d|');
});
What I do here? Just create an unique keys for each date, which includes: year, month and day. And then I group an array by this unique key.
result
Why do need this optimization? If your array is not large enoguh than you probably don't need to optimize your algorithm.
I am not familiar with the given js libraries, but you can group your array by days with one loop. But you need to somehow determine the current day in the array and then create corresponding js object with a day-field and a times-array field and then add this object to your resulting array.
It will be much faster if you presort your array before implementing this algorithm.

Categories

Resources