Is there an algorithm for weekly reminders ?
For example, I set a reminder for Thursday & I check the "weekly" option.
The Reminder is supposed to alert every Thursday then,but how is this done?
I thought about an idea, but I guess it's very stupid:
Get today's "day".
Get today's "date".
Get the wanted day number.
Subtract both days from each other.
using [4] get that day's date.
Increment the counter after every alert with 7.
I don't even know whether this will work or not, I'm sure there is a better way to do it, so I need your opinions before starting implementation.
PS: I use JavaScript so the functions are very limited.
It's not entirely clear what you're trying to do.
If your code needs to know whether it's Thursday, that's really easy using getDay, which gives you the day of the week:
if (new Date().getDay() === 4) {
// It's Thursday
}
The day numbers start with 0 = Sunday.
If your code needs to find the next Thursday starting on a given date:
var dt = /* ...the start date... */;
while (dt.getDay() !== 4) {
dt.setTime(dt.getTime() + 86400000)) // 86400000 = 1 day in milliseconds
}
or of course without the loop:
var dt = /* ...the start date... */;
var days = 4 - dt.getDay();
if (days < 0) {
days += 7;
}
dt.setTime(dt.getTime() + (days * 86400000));
If you have a Thursday already and you need to know the date for the next Thursday:
var nextThursday = new Date(thisThursday.getTime() + (86400000 * 7));
Related
I am working on a simple Timesheet app, I am trying to implement an auto calculator that will sum up your hours for each day (Sunday, Monday, Tuesday, etc ...). A problem I noticed is that in some cases, users will enter activities that will be within the same date time periods.
For example:
$scope.Example = [
{Description:"Example activity",Start:"2018-06-24 8:00",End:"2018-06-24 10:00",Total:2},
{Description:"Example activity2",Start:"2018-06-24 9:00",End:"2018-06-24 10:00",Total:1},
{Description:"Example activity3",Start:"2018-06-24 10:00",End:"2018-06-24 11:00",Total:1}];
$scope.Calculate_all_entries = function(){
$scope.Total.Sunday = 0;
if($scope.Example){
angular.forEach($scope.Example, function(element){
if(moment(element.Start).format("dddd") === "Sunday"){
$scope.Total.Sunday = $scope.Total.Sunday + element.Total;
}
})
}
}
In this case the total should be 3 hours and not 4 hours as we dont charge for work within the same hours. I'm need to implement a system that would check if the dates are within the same period and provide the appropriate total.
I found this in the documentation on momentjs that seemed to be close to what i need but only takes one value:
moment('2010-10-19 11:00').isBetween('2010-10-19 10:00', '2010-10-25 00:00'); // true
Would anyone know of any other methods to check wether or not the start and end time are in the same period as other entries in the same day?
Sure, you can use momentjs's unix() function to convert those date times to an integer which then can easily be used to check whether the timestamp is in between two other timestamps.
Here is an example:
var timeToCheck = moment('2010-10-19 11:00').unix();
var startTime = moment('2010-10-19 10:00').unix();
var endTime = moment('2010-10-25 00:00').unix();
console.log(timeToCheck >= startTime && timeToCheck <= endTime); // true
I'm trying to get the start of (12:00am, or, 00:00am) of the most recent Friday. This has been working:
moment().isoWeekday(5).startOf('day').toDate()
But it only works Friday->Sunday, on Monday morning it will then refer to the upcoming Friday, in which case this would work:
moment().add('-1', 'week').day(5).startOf('day').toDate()
but I need it be dynamic and done in one line if possible, to where I don't to perform any checks on the current day.
Is there a way to always get the most recent Friday? Regardless of what the current day is.
Edit I'm also trying to get this to return the current day (friday) if executed on a Friday.
If you don't want to use a library, it's pretty straight forward
var date = new Date();
while ( date.getDay() !== 5 ) date.setDate(date.getDate() -1);
console.log(date)
With moment
var date = moment();
var friday = date.day(date.day() >= 5 ? 5 :-2);
and if millisecond accuracy doesn't matter, you could call moment() twice to make it one line (but I would much raher use a variable)
var friday = moment().day(moment().day() >= 5 ? 5 :-2);
Check this:
var date = moment().utc().isoWeekday(5);
if(moment().day() < 5) {
date = date.add(-1, 'week');
}
console.log('Recent friday starts:', date.startOf('day').toDate());
console.log('Recent friday ends:', date.endOf('day').toDate());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.1/moment.js"></script>
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
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();
}
I am new to JavaScript but need to run a check to make sure it is daylight. I am using yahoo's weather API to pull sunrise and sunset. I'm just a little confused as to the best approach for comparing its results to the current time.
I am confused because it returns a time like sunset: '9:01 pm'. bsince there is a PM it is text. I can't think of a good way to compare it to the current time... RegExp, then convert to an integer maybe?
What would be the best approach to this, and why (sorry I'm trying to learn)?
Thanks in advance for any help.
Create a new Date() with the info from yahoo's api, then compare Date.now() with sunsetDate.getTime() and sunriseDate.getTime().
Passing today's date in mm/dd/yyyy format with the time as '9:01 pm' to the Date constructor will give you a valid date.
var today = new Date();
today = [today.getMonth()+1, today.getDate(), today.getFullYear()].join('/');
var yahooSunrise = '5:45 am';
var yahooSunset = '9:01 pm';
var sunrise = new Date(today + ' ' + yahooSunrise).getTime();
var sunset = new Date(today + ' ' + yahooSunset).getTime();
var now = Date.now();
var isDaylight = (now > sunrise && now < sunset);
This would work with something like this, but maybe you might need to change the timings to suite a particular climate:
function getNow() {
var now = new Date
if (now.getHours() < 5) { return "Could be still dark";}
else if (now.getHours() < 9) {return "Definitely day time";}
else if (now.getHours() < 17) { return "Definitely day time"; }
else {return "It gets dark now";}
}
alert(getNow());
One quick approach is to turn both the current time of day and the time you get back from yahoo into the value "minutes since the beginning of the day."
For example, if Yahoo gives you 9:01pm, use the pm to turn the time into 21:01. That is
21*60 + 1 = 1260 + 1 = 1261 minutes since the beginning of the day
Do this for both sunrise and suset. Then get the current time with
new Date()
and do the same kind of thing.
Then just do integer comparisons!
Hope that helps.
This sounds like a good candiidate for a regular expression on the data you get back from the service.
Something like (\d{1,2}):(\d{2})\s(AM|PM) will give you 3 capture groups.
1: The hour (1 or 2 digits)
2: The Minute (2 digits)
3: Either string "AM" or "PM"
You can then use these to parse out the actual time as integer hour and minute to compare to the current time.