Moment js - days remaining - incorrect value coming back - javascript

https://jsfiddle.net/yg4bk1wh/
I am trying to create a tool that reports the days remaining -
moment(1583884740000).diff(moment(), 'days')
but this is reporting incorrectly - almost as if the month index is not taken into consideration.
-- also if the days became negative - would want to obtain the value without the polarisation - so intead of "10 days remaining" -- it reads "finished 30 days ago"
-- https://www.calendar-12.com/days_between_dates
scenario 1
Start Date - February 12th
End Date - March 10th
total days between the two dates - 27 days
remaining days from now until end day - 33 days
^ campaign has yet to start
scenario 2
Start Date -January 6
End Date - March 10th
total days between the two dates - 64 days
remaining days from now until end day - 33 days
so the campaign has been running (64-33) = 31 days [totaldays-remaining days]
as such the campaign is (31/64 * 100) % complete [48%]

In your jsfiddle, you're formatting the date wrong, which returns a wrong display date.
See snippet:
console.log(moment(1583884740000).format('MMMM d YYYY'))
console.log(moment(1583884740000).format('MMMM D YYYY'))
<script src="https://unpkg.com/moment#2.24.0/min/moment.min.js"></script>
moment(1583884740000).format('MMMM D YYYY') returns 'March 11 2020' which is the correct amount of days after today.

In your line with days remaining, you are using the current date instead of your first date. moment() will return the current date and time.
m[2] = ["days remaining", moment(1583884740000).diff(moment(), 'days')];
Put your first timestamp in and the result will be 27 days remaining, which is correct.
m[2] = ["days remaining", moment(1583884740000).diff(moment(1581465600000), 'days')];
Here's a working fork of your fiddle: https://jsfiddle.net/bd91mjs7/2/
To solve your text problem you could calculate your remaining days beforehand and change the text accordingly:
let daysLeft = moment(1583884740000).diff(moment(1581465600000);
let daysLeftLabel = daysLeft < 0 ? 'finished ago' : 'days remaining'
var m = [];
m[0] = ["moment(date1)", moment(1581465600000).format('MMMM D YYYY')];
m[1] = ["moment(date2)", moment(1583884740000).format('MMMM D YYYY')];
m[2] = [daysLeftLabel, Math.abs(daysLeft), 'days')];
Note: Math.abs() returns the absolute value, so that you don't get "-X days ago"
I'm not sure about the
"10 days remaining" -- it reads "finished 30 days ago"
part though, in my example it would read "days ago 10" instead of "days remaining -10". You may need to change the logic yourself there.
Update: as #nsevens stated, you are also using the wrong date format. Instead of d, which gets you the day of the week, you should use D which returns the day of the month (https://momentjs.com/docs/#/displaying/format/). I updated my example above.

Related

get week number from date in whole week base in javascript

I have searched the web and found the script to get the week number in year. However my counting is difference. The below image is the week number I want to get. When I tested using '1/5/2015', my code got week number is 2, but the week number should be 1 in my requirement. Would someone can help me. Thanks in advance.
I found the javascript at IamSilviu/Get week number
There is my code:
function myWeekNumber(thisDate) {
var dt = new Date(thisDate)
var onejan=new Date(dt.getFullYear(), 0, 2);
return Math.ceil((((dt - onejan) / 86400000) + onejan.getDay() + 1) / 7); }
The algorithm you're trying to implement seems to be that:
Weeks start on Sunday
The first week of the year is the one that has any days in the year, e.g. 1 Jan 2016 was a Friday, so the first week of 2016 started on Sunday 27 December 2015
In this case, it's best to use UTC methods to avoid daylight saving issues:
function getWeekNumberNonISO(d) {
// Create UTC equivalent for 23:59:59.999 on the passed in date
var sat = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(),23,59,59,999));
// Set to Saturday at end of week
sat.setUTCDate(sat.getUTCDate() + 6 - sat.getUTCDay());
// Get first day of year
var firstDay = new Date(Date.UTC(sat.getUTCFullYear(), 0, 1));
// Set to Sunday on or before, i.e. first day of first week in year
firstDay = firstDay.setUTCDate(firstDay.getUTCDate() - firstDay.getUTCDay());
// Week number is difference in dates divided by ms/week rounded
return Math.round((sat - firstDay)/(6.048e8));
}
// Get week number for Mon 5 Jan 2015
console.log(getWeekNumberNonISO(new Date(2015,0,5))); // 2
// Get week number for Sat 31 Dec 2011
console.log(getWeekNumberNonISO(new Date(2011,11,31))); //53
// Get week number for Sat 1 Jan 2011
console.log(getWeekNumberNonISO(new Date(2011,0,1))); // 1
// Get week number for Sun 2 Jan 2011
console.log(getWeekNumberNonISO(new Date(2011,0,2))); // 2
Js has function inbulid function which can be used to fetch the date from the given date of the week getweek().
var week=date.getWeek()

Display a date fortnightly using javascript

This is my first time posting a question on here however I am a long term user of StackOverflow.
I am very new to Javascript and am currently trying to solve a few issues I am having on a website I am creating for my university course.
I am trying to make a little information box on the website's dashboard that simply tells you when your next rubbish bin collection day is. This is currently every 2 weeks on a Friday, the next being 1st April. I was wondering if there was a simple way for me to display the next bin collection date until it's the day of the bin collection, where the text would change to say 'bin collection today!' and after about 6pm it would change to the next collection date in a fortnight.
Sorry if this is extremely poorly worded! The website will only be used in the UK so I don't need to worry about time zones.
Any help would be very much appreciated!
Many thanks,
Emily
Below is some code to show how it might be done, hopefully there are sufficient comments.
As far as I know, some parts of the UK observe daylight saving but the following should not be affected by any change of timezone since it uses local date methods.
Any date can be used for the start of the cycle, I've chosen 10 June 2011 totally randomly. Also, any time of day can be used to change the message on the final day from "put your bins out today" to the standard "next cycle is in x days".
The algorithm is calculate the number of milliseconds to the next full fortnight from the start date by subtracting the number of milliseconds from the last full fortnight from the milliseconds per fortnight. Then the remainder is converted to full days.
To save ambiguity on the day before the cycle ends (in this case, a Thursday) the message says the cycle ends "tomorrow" rather than in 1 day, and on the day itself, up to 18:00 or 6 pm it says the cycle ends today. After that, it says the cycle ends in 14 days or less.
// Date objects are based on milliseconds (8.64e7 per day)
// Calculate milliseconds for a fortnight
var msPerFortnight = 8.64e7 * 14;
// Any date can be the start of the fortnightly cycle
// Make Friday 10 June 2011 first day of cycle,
// Cycles end on 25 March, 6 April 2016.
// Note months are zero based so June is 5
var firstDayOfCycle = new Date(2011, 5, 10);
// Time of day to stop showing "put bins out today" message on start/end day
// 18 is 6 pm
var endHour = 18;
// Get the day name for the cycle start/end
var dayName = ['Sunday','Monday','Tuesday','Wednesday','Thursday',
'Friday','Saturday'][firstDayOfCycle.getDay()];
// Convert end hour to convenient format with am/pm
var endHourNeat = (endHour % 12 || 12) + ' ' + (endHour < 12? 'am' : 'pm');
// Get a date for now
var now = new Date();
// Get milliseconds to next full fortnight by
// msPerFortnight minus milliseconds since last full fortnight
var m = msPerFortnight - ((new Date() - firstDayOfCycle) % msPerFortnight);
// Calculate time remaining full days
var daysLeft = Math.ceil(m / 8.64e7);
// Create a human friendly message
var message;
// If more then one day left, or after 18:00 on last day, show this message
if (daysLeft == 14 && now.getHours() < endHour) {
message = 'Today is ' + dayName + ', so please put your bins out before ' + endHourNeat + '!';
} else if (daysLeft > 1 ) {
message = 'Put your bins out on ' + dayName + ' in ' + daysLeft +
' day' + (daysLeft == 1?'':'s') + ' time.';
} else if (daysLeft == 1) {
message = 'Put your bins out tomorrow, on ' + dayName + '.';
}
document.write(message);
You can even add the date of the end of the cycle and add ordinal, so it might read "Put your bins out on Friday the 25th, in 3 days time". But I'll leave that up to you.
A possible solution is to use Unix epoch, because they give you your time in seconds from 1/1/1970. By using this we can find how far we are into a fortnight. I found that Math.floor(Date.parse("2016-04-01")/86400000)%14equals 8.
Then your code might be:
var days_into_fortnight=Math.floor(Date.now()/86400000)%14;
var string_to_show;
var days_to_collection;
if (days_into_fortnight==8){
string_to_show="Bin collection!";
}
else{
if(days_into_fortnight<8){
days_to_collection=8-days_into_fortnight;
}
else{
days_to_collection=22-days_into_fortnight;
}
string_to_show=days_to_collection.toString()+" day(s) to collection!";
}
Edit:spelling

How to use moment to find first monday 18 month ago

I am writing some javascript and came across moment library.I would like to use the moment to get the first Monday of 18 Month ago. How would I do it?
I know 18 months ago it is
moment().subtract(18, 'months');
But how would I know the first Monday of that time.
Thanks ahead of time!
You can do this in one line.
moment().subtract(18,'months').startOf('month').add(6 - moment().day("Monday").day() ,'days').startOf('week').day(1);
Find the moment 18 months ago, get the start date of that month, add 6 days since in worst case the first of that month is a tuesday(results in a date which is in the week that includes the first monday) and then get the start of that week.
Voila, all in one line.
1st edit: corrected the calculation to be locale independent and always return a Monday and not beginning of week since that is locale dependent.
2nd edit: locales makes it a bit more complicated. Adding 6 days to a Monday with a locale where the week ends on Saturday will move into another week thus we need to adapt the algorithm to take the Monday week number into consideration, i.e. subtract moment().day("Monday").day() which gives the locale dependent week day number of a Monday(0 or 1). Changed in the code above.
cleaner and more reusable IMHO ;)
var monday = moment().day('Monday').weekday();
var searchFirstMonday = moment().subtract(18, 'months').startOf('month');
while (searchFirstMonday.weekday() !== monday){
searchFirstMonday.add(1, 'day');
}
If you go back 18 months, get the first day of that month, then the Monday of that week, you'll get close:
moment().subtract(18, 'months').startOf('month').day(1)
To make sure the Monday is in the right month, you need to break that down a bit:
var month = moment().subtract(18, 'months');
var firstMonday = month.startOf('month').day(1);
if (firstMonday.month() != month.month()) {
firstMonday = firstMonday.add(7, 'days');
}
If anyone wants to do the same without any libraries.
Not sure if this is the best way to do it :P
var now = new Date();
//Get year and month
var month = now.getMonth();
var year = now.getFullYear();
//Months to go back
var monthsIntoPast = 18;
//Day of week we're looking for
var firstWeekDay= 2;
//Loop for one week
for(var x = 0; x < 7; x++) {
//Go back 18 months to first day + x of the month
var past = new Date(year, month - monthsIntoPast, 2 + x);
//First monday
if(past.getDay() == firstWeekDay) {
//First monday 18 months ago
alert(past.toUTCString())
break;
}
}
You use the following code to get what you need:
// Subtract 18 months from the current date, then get the first day of the month
var date = moment().subtract(18, 'months').startOf('month');
// Get current month
var month = date.month();
// Get monday of the first week of the month
var firstMonday = moment(date).weekday(0);
// Check if the first day of the month is not Monday
// and first monday of first week is in the desired month
if( date.weekday() != 0 && firstMonday.month() != month ){
// Add 1 week if needed
firstMonday.add(1, 'weeks');
}
The example above consideres Monday as the first day of the week. If Monday is not the first day of the week (day with index 0), you can get the correct index using moment.weekdays()
var moment = require('moment');
date = moment().subtract(18, 'months').startOf('month');
First we get the the current date and subtract 18 months. Then we find the start of the month, which as of today is
_d: Tue Jul 01 2014 00:00:00 GMT-0800 (AKDT),
So now we need to adjust for the next Monday. We get the current day of the week with date.day() which will give us a number between 0-7 with 0 being last Sunday and 7 being next Sunday. In this case, the first is on a Tuesday.
>date.day();
2
So we take the offset of the day of the week and subtract it from 8. Why 8 you say? Because if you count every number including 0 and 7 there are 8 numbers. (Think arrays)
//since it's not monday we add the offset
date = date.add(8-date.day(), 'days');
In your code you'd want to check if the First day returned actually IS a Monday so as to not get the second Monday of the month. So the whole thing might look like
date = moment().subtract(18, 'months').startOf('month');
if(date.day() > 1){ //check if it's Monday
//since it's not monday we add the offset
date = date.add(8-date.day(), 'days');
}
returns
_d: Mon Jul 07 2014 00:00:00 GMT-0800 (AKDT),

Calculate difference between dates in javascript

I am aware that this question was asked multiple times before but the suggested solutions were always something like
var diff = date1 - date2;
My problem is that I want to get the difference in years, months, day, ... ,seconds.
So for example 5y 3m 39d 12h 39i 32s
But simply dividing the difference is too inaccurate for my purpose.
So I can't assume that every month has 30.4375*24*60*60*1000 milliseconds.
I need the exact difference!
So if date1 is the 1st of february and date2 is the 1st of march, it should display 1m not 28d (or 29d in leap years)!
Thank you.
First you need to find out which date is bigger, subtract the dates, and if they turn out to be negative borrow from the larger digit (similar to elementary multi-digit subtraction).
function DateDiff(a,b){
if(b>a){ // We want a-b to be positive
var c=b;
b=a;
a=c;
}
var s=a.getSeconds()-b.getSeconds();
var mi=a.getMinutes()-b.getMinutes();
var h=a.getHours()-b.getHours();
var d=a.getDate()-b.getDate(); // Subtract days
var m=a.getMonth()-b.getMonth(); // Subtract months
var y=a.getYear()-b.getYear(); // Subtract years
if(s<0){
mi--;
s+=60;
}
if(mi<0){
h--;
mi+=60;
}
if(h<0){
d--;
h+=24;
}
if(d<0){ // Need to borrow from months
m--;
d+=new Date(1900+b.getYear(),1+b.getMonth(),0).getDate();
}if(m<0){ // Need to borrow from years
y--;
m+=12;
}
return [y,m,d,h,mi,s];
}
console.log('Mar 1 - Feb 2 (Leap Year):', DateDiff(new Date(2016,1,2),new Date(2016,2,1)));
console.log('Mar 1 - Feb 2 (Reg Year): ',DateDiff(new Date(2015,1,2),new Date(2015,2,1)));
console.log('Feb 1, 2017 - Feb 2, 2016: ',DateDiff(new Date(2017,1,1),new Date(2016,1,2)));
console.log('5:00 - 4:59: ', DateDiff(new Date(2015,7,1,17), new Date(2015,7,1,16,59)));
You can use moment.js to achieve this: ( MomentJS Doc )
var start = moment(date1);
var end = moment(date2);
var diff = end.diff(start)
If you want specific things like difference in days, you can do:
var diff = end.diff(start, 'days')
For what you are describing, you will want to hold the year/month/day in three different variables and directly compare the years using
var yeardiff = date1.GetFullYear() - date2.GetFullYear();
var monthdiff = date1.GetMonth() - date2.GetMonth();
var daydiff = date1.GetDate() - date2.GetDate();
However, you are going to have to do a lot of checking in this. For example, 8/2/2012 - 7/20/2012 is going to give you a 1 month and -18 days, then you have to convert that into days based on the number of days in July. Because of these issues, the other conversion in the OP is actually easier.
Not using any library you could do
function mydiff(aa,bb){var a,b;
if(aa<bb) a=aa,b=bb;
else a=bb,b=aa;
var am=a.getMonth(),ay=a.getFullYear();
var dd=b.getDate()-a.getDate();
var dm=b.getMonth()-am-(dd<0?1:0);
return b.getFullYear()-ay-(dm<0?1:0)+'y, '
+ ((12+dm)%12)+'m, '
+((dd<0?new Date(ay, am+1, 0).getDate():0)+dd)+'d';
}
dd contains the difference 'b minus a in days of month' which can be negative. In that case the month-difference dm has to be reduced by 1 and the (negative) day-difference must be increased by the number of days of the preceding month of date b. I got the formula for "number of days in a particular month" from here. Similar action has to take place with the month- and year-differences dm and dm.
A few samples:
mydiff(new Date(2014,1,2),new Date(2014,2,1)) // "0y, 0m, 27d"
mydiff(new Date(2012,1,1),new Date(2012,2,1)) // "0y, 1m, 0d" (leap year)
mydiff(new Date(2012,1,2),new Date(2012,2,1)) // "0y, 0m, 28d" (leap year)
mydiff(new Date(2014,11,31),new Date(2015,0,1)) // "0y, 0m, 1d" (different years)
mydiff(new Date(2012,10,30),new Date(2013,1,28)) // "0y, 2m, 28d" (different years)
The last example shows that this kind of "calculation" has its limits: compared to "normal" months 28 days are not a full month. On the other hand, compared to the current month February 28 days is a full month. So it could also be argued that a correct response should be "0y, 3m, 0d".

moment.js thinks that 2013-12-31 is week 1, not week 53

The moment.js library is awesome, and I use it almost all the time, but I recently ran into something interesting. I'm trying to plot data by week of the year, and one of the data points was 2013-12-31, moment.js tells me this is week 1? Is there a better way to handle this? either with 53, null, -1, or something?
moment('2013-12-31').week()
(returns) 1
I thought maybe using isoWeek or format would get around this, but they all return the same value of 1, despite the documentation saying it goes to 53.
moment('2013-12-31').isoWeek()
(returns) 1
+moment('2013-12-31').format('w')
(returns) 1
Anyone have any ideas on this? (short of making a test whether the week computed has a min/max date that covers the date value I passed it)
It is because the week from the 30th december 2013 is considered to be the 1st week of 2014 as you may see on this page epoch converter
And according to momentjs documentation:
The week with January 1st in it is the first week of the year.
I had a problem at my work where we used .format('YYYY WW') for some comparison logic.
That doesn't really make sense, as you should probably use .format('gggg WW') in such cases.
moment('2013-12-31').format('YYYY w'); // Returns 2013 1
moment('2013-12-31').format('gggg w'); // Returns 2014 1
https://momentjs.com/docs/#/displaying/format/
This is expected behavior. According to the ISO 8601 standard, 2013 is not a year with 53 weeks.
The long years, with 53 weeks in them, can be described by any of the following equivalent definitions:
any year starting on Thursday (dominical letter D or DC) and any leap year starting on Wednesday (ED)
any year ending on Thursday (D, ED) and any leap year ending on Friday (DC)
years in which 1 January and 31 December (in common years) or either (in leap years) are Thursdays
(source)
2013 started and ended on a Tuesday so therefore it is not a "long year" and 2013-12-31 is considered part of the first week of 2014.
If you want that week to be the 53rd, you'll have to write custom code for it as the ISO standard won't agree with you!
Moment.js docs aren't that straightforward with this I had to move from WW-YYYY to WW-GGGG
moment(2019-12-30T00:20:53.380Z).format(WW-YYYY) // Gave me 01-2019 incorrectly
moment(2019-12-30T00:20:53.380Z).format(WW-GGGG) // Gave me 01-2020 correctly
Findings
If your doing locale weeks, use ww & gggg
If your doing ISO weeks, use WW & GGGG
A mix of w/W & Y is incorrect usage
I had the same problem with the calculation of the week number, starting from the date of Sunday.
Finally I was able to solve the problem by calculating the week number starting not from Sunday but from Monday.
moment(date).isoWeekday(1).week()
Better right a custom method which will convert date into week and that can be customized easily.
//value : (MMM DD YYYY format)
function getEpiWeek(value) {
Date.prototype.getWeek = function () {
var target = new Date(this.valueOf());
// ISO week date weeks start on monday, so correct the day number
var dayNr = (this.getDay() + 7) % 7;
// Set the target to the thursday of this week so the
// target date is in the right year
target.setDate(target.getDate() - dayNr + 3);
// ISO 8601 states that week 1 is the week with january 4th in it
var jan4 = new Date(target.getFullYear(), 0, 4);
// Number of days between target date and january 4th
var dayDiff = (target - jan4) / 86400000;
if (new Date(target.getFullYear(), 0, 1).getDay() < 4) {
return 1 + Math.ceil(dayDiff / 7);
}
else { // jan 4th is on the next week (so next week is week 1)
return Math.ceil(dayDiff / 7);
}
};
var weekNumber = new Date(value).getWeek()
var year = getYear(value, weekNumber);
return weekNumber + ' ' + year;
}
function getYear(value, weekNumber) {
var year = parseInt(value.split(' ')[2]);
if (value.split(' ')[0] == 'Jan') {
if (weekNumber > 40) {
year = year - 1;
}
}
if (value.split(' ')[0] == 'Dec') {
if (weekNumber < 2) {
year = year + 1;
}
}
return year.toString();
}
Personally solved my ordering issue using :
if(d.month()==0) {
week = d.week();
}else{
week=d.isoWeek();
}

Categories

Resources