RRULE explanaiton using BYDAY and BYSETPOS - sql

I am trying to parse an RRULE and display what weeks in the month a recurrence event is valid for. I have looked at the RFC2445 doc (http://www.ietf.org/rfc/rfc2445.txt) and it's not that clear.
I know for instance the rule:
RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TH,FR,WE;BYSETPOS=10,11,12,7,8,9,1,2,3,4,5,6
Is for Wed, Thur, Friday on the 1st,2nd,3rd and 4th week of the month.
or
RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TU,MO;BYSETPOS=3,4,5,6;
Is for Monday and Tuesday on the 2nd and 3rd week of the month.
or
RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TH,WE;BYSETPOS=-1,-2
Is for Wed and Thursday on the last week of the month.
I generated these via another program, but am not sure how it actually generated them.
Thus the problem I am having is understanding how the BYSETPOS describes reoccurrence weeks for a month. The final goal is to be able to parse a RRULE such as the above and display at like so:
For: RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TH,FR,WE;BYSETPOS=10,11,12,7,8,9,1,2,3,4,5,6
Show: Thur,Friday,Wed on week:1,2,3,4
For: RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TU,MO;BYSETPOS=3,4,5,6;
Show: Tues, Monday on week:2,3
For: RRULE FREQ=MONTHLY;INTERVAL=1;BYDAY=TH,WE;BYSETPOS=-1,-2
Show: Whu,Wed on last week
The best solution would be a string in objective-c, but I can figure it out if it's another C like language. Even just a explanation of how BYSETPOS with BYDAY works would be great.

Thus the problem I am having is understanding how the BYSETPOS describes reoccurrence weeks for a month.
BYSETPOS does not represent weeks but simply the nth instance once you have calculated the instances corresponding to the remaining of the rule.
For example, FREQ=MONTHLY;INTERVAL=1;BYDAY=TU,MO corresponds to every mondays and tuesdays of the month, every month. So for each month, you first calculate a set (e.g. 9 entries if you take July 2014). Then BYSETPOS gives you the "indexes" into the set that you should keep, -1,-2 meaning the last 2 entries into the set.
Continuing with the July 2014 example, the base rule will return the following set: (1st, 7th, 8th, 14th, 15th, 21st, 22nd, 28th, 29th of July). Given a BYSETPOS=1,2,-1,-2, we will keep 1st, 7th, 28th, 29th of July.
You want to look at https://www.rfc-editor.org/rfc/rfc5545 which obsoletes RFC2245 and has a more detailed description of recurrence rules.

Good explanation Arnaud. Helped me get my own head around it.
Because this is such an unusual concept for myself and others to grasp, I have copied a wiki page I created for myself along with a short php script I've created to clearly understand by demonstration how it works.
BYSETPOS is not a rule but something that limits an existing rrule.
For instance, let's say you have an RRULE for an event that occurs twice a month on Mon and Tue forever like this:
FREQ=MONTHLY;INTERVAL=1;BYDAY=MO,TU
Now let take the example Arnaud provided above and focus only on the month of July as an example.
July 1st is the first Wed
July 7th is the following Tue followed by the 8th being the next Wed and so on.
Our RRULE above would have the event falling on July 1st, 7th, 8th, 14th, 15th, 21st, 22nd, 28th and 29th
Now let us append a BYSETPOS limiter.
FREQ=MONTHLY;INTERVAL=1;BYDAY=MO,TU;BYSETPOS=1,2,-1,-2
What is this saying exactly?
It is saying OK, we know your rule would have the event falling on July 1st, 7th, 8th, 14th, 15th, 21st, 22nd, 28th and 29th. However, we only want display the 1st, 2nd instances (1,2) of the event as well as the last (-1) and the 2nd to the last (-2).
BYSETPOS says to show ONLY those instances that are in the BYSETPOS limiter.
So if you took the array of days $moDays Array(1,7,8,14,15,21,22,28,29) and parsed it with the BYSETPOS limiter $bspLimiter=Array(1,2,-1,-2) it would look likethe following:
<?php
// 9 event days - limiting the events displayed based on the BYSETPOS limiter
$moDays = array(1,7,8,14,15,21,22,28,29);
$bspLimiter = array(1,2,-1,-2);
$keepers = [];
for($b=0;$b<count($bspLimiter);$b++){
if($bspLimiter[$b] < 0){
echo '$bspLimiter[$b] is negative value ('.$bspLimiter[$b].') so getting from back of array<br>';
$limiter=count($moDays)+$bspLimiter[$b];
$keeper=$moDays[$limiter];
$keepers[]=$keeper;
} else {
# accounting for index
$limiter = $bspLimiter[$b]-1;
$keeper=$moDays[$limiter];
$keepers[]=$keeper;
}
echo '<b>keeping '.$keeper."</b><Br>";
}
echo "<hr>";
asort($keepers);
echo $keepers=str_replace("'","",implode("', '", $keepers));
?>

Related

Is optaplanner scheduling AI suitable for optimising a college schedule?

Optaplanner school timetabling examples show different problems than what I need to solve.
The problem:
Let's have three courses: Math, English, History
All these courses offer multiple timeslots (parallels) and the student gets to choose one of them for each.
Let's say:
Math: Monday: 9:00 - 10:00, Tuesday: 10:00 - 11:00
English: Monday: 9:00 - 10:00, Tuesday: 11:00 - 12:00, 14:00 - 15:00,
Friday: 16:00 - 17:00
History: Tuesday: 10:00 - 11:00, Friday: 10:00 - 11:00
I would like to find the best possible timeslot for each of these courses. By the best I mean the one with the least amount of gaps and, more importantly, the one which lets you have the most free days.
The optimal solution for the example problem might be something like
Tuesday: Math: 9:00 - 10:00, History: 10:00 - 11:00, English: 11:00 -
12:00
leaving no gap and simultaneously giving 4 free days.
Is this possible with OptaPlanner or should I use a different solver? I noticed that the Lesson object only has a single TimeSlot instead of a list, which makes me think that this kind of timetable optimisation is not supported.
From the description, it appears your problem is "Student planning their own schedule" (whereas school timetabling is "Teachers planning the school timetable for all students").
I would model it like this:
#PlanningEntity
public class CourseSection {
private List<TimeSlot> availableTimeslots;
#PlanningId // needed for forEachUniquePair
private String courseSectionIdentifier;
#PlanningVariable(valueRangeProviderRefs = {"timeslotRange"})
private TimeSlot selectedTimeslot;
#ValueRangeProvider(id="timeslotRange")
public List<TimeSlot> getTimeslotRangeForCourse() {
return availableTimeslots;
}
// getters and setters ...
}
This takes advantage of value range provider on a planning entity, meaning each planning entity gets it own value range (and non-existing TimeSlot for the course will not be tried).
I used CourseSection, since courses could be divided into multiple sections (1 lectures + 2 tutorial, 2 lectures, etc.), and you would have one CourseSection for each of those sections. (If the course only one lecture section, then there is only one CourseSection, if the course a lecture + tutorial, there are two CourseSections, etc.).
For the minimize gaps constraint, I would use the experimental consecutive interval constraint collector. To use it, you would either need to add OptaPlanner Examples as a maven dependency or copy it from the source code of examples; it will eventually be moved into ConstraintCollectors once we are certain of the API (which is subject to change as it still in experimental). With the consecutive interval constraint collector, it will look like this:
Constraint minimizeGaps(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(CourseSection.class)
.groupBy(section -> section.getSelectedTimeslot().getDayOfWeek(),
ExperimentalConstraintCollectors.consecutiveTemporalIntervals(
section -> section.getSelectedTimeslot().getStartTime(),
section -> section.getSelectedTimeslot().getEndTime()))
.flattenLast(ConsecutiveIntervalInfo::getBreaks)
.penalize("Minimize Gaps", HardMediumSoft.ONE_SOFT);
}
For the maximize free days constraints, I would write it as "minimize working days" like this:
Constraint minimizeWorkingDays(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(CourseSection.class)
.groupBy(section -> section.getSelectedTimeslot().getDayOfWeek())
.penalize("Minimize Working Days", HardMediumSoft.ONE_MEDIUM);
}
Finally, we need to make sure no two course sections overlap:
Constraint noOverlappingCourseSections(ConstraintFactory constraintFactory) {
return constraintFactory.forEachUniquePair(CourseSection.class,
Joiners.equal(section -> section.getSelectedTimeslot().getDayOfWeek()),
Joiners.overlapping(
section -> section.getSelectedTimeslot().getStartTime(),
section -> section.getSelectedTimeslot().getEndTime()))
.penalize("Overlapping sections", HardMediumSoftScore.ONE_HARD);
}
Note in the constraints I provided, a solution with less working days is ALWAYS preferred to a solution with more working days, even if the solution with less days has a 8 hour gap. You might want to add an additional constraint on the maximum gap allowed (which you can do with a filter that checks IntervalBreak.getLength()).

how to pass a date/time reference in a call to a basic duckling server?

Any pointers on how to pass a date/time reference to a basic, vanilla duckling server?
I'm using duckling for parsing text. When looking for time expressions, I need to pass in a reference date/time.
A reference date/time gives me an anchor for expressions like "yesterday" and "today."
e.g.
reference date = April 1, 2018 => "1 week ago" = March 25, 2018.
reference time = April 1, 2018, 3pm => "in 8 hours" = April 1, 2018, 11pm
The duckling repo site has instructions on how to make a basic server run locally, that you can then call with
curl -XPOST http://0.0.0.0:8000/parse --data 'locale=en_GB&text=tomorrow at eight'
but not many more examples are provided that I could find. I can see in ExampleMain.hs that dims and lang are also options as parameters along text and locale, but nothing on reference date.
curl -XPOST http://0.0.0.0:8000/parse --data 'locale=en_GB&text=tomorrow at eight&reftime=<unix epoch in millisecond>'
Reference:
https://github.com/facebook/duckling/issues/166

How to get date of creation of Wikipedia page by API?

Wikipedia article United States presidential election, 2016 has page information which contains "Date of page creation" under "Edit history" section. How do I get this date through an API?
For this goal you need to use action query with property revisions:
https://en.wikipedia.org/w/api.php?action=query&prop=revisions&rvlimit=1&rvprop=timestamp&rvdir=newer&titles=United States presidential election, 2016
where:
rvdir=newer - sort revisions by oldest first
rvlimit=1 - get only one revision (the 1st one)
rvprop=timestamp - get only information about the revision timestamp
In your case the result will be: "2009-02-03T09:59:37Z" → 09:59, 3 February 2009.

Podio API filtering by date range

I'm trying to filter tasks by date range and I'm getting errors whatever I try. This is how my request looks like: http://api.podio.com/task?completed=true&created_on%5Bfrom%5D=2016-06-23&created_on%5Bto%5D=2016-06-28&limit=100&offset=0&sort_by=rank&sort_desc=false&space=4671314
Here I'm trying to filter by created_on and I'm suplying {from: "2016-06-23", to: "2016-06-28"} but it's always returning the same error - invalid filter. I'm trying to filter tasks that are created in the last 5 days here.
The tasks API reference can be found in their API docs.
What am I doing wrong?
Date ranges can be separated by -.
To display "all my tasks created between 1st Jan 2014 and 1st Jan 2016" :-
/task?created_on=2014-01-01-2016-01-01&responsible=0'
Podio API get task filtering by date range use below :
/task/?created_on=2017-04-25-2017-05-01&offset=0&sort_by=rank&sort_desc=false&space=xxxxxxx

Calculate end date based on # of days and start date

I am working on script where users can make certain type of orders. Now when users make an order they can choose how long they wont it to last in # of days. Once the order is placed I need to approve their order and that approval date is recorded inside my database. Now what I need is to show inside their user panel how much days their package will last since the day of my approval. So for example if I approved their order September 08, 2013 and they choosed for the order to last 7 days, I wont them to see inside they panel for every next day they login how much days they have left, so 7days, 6days, 5days, etc... all the way to "0 Days" when they come to their panel on September 16, 2013.
I have following variables for those two values:
$row_ordersResults['date'] - the date I approved the order
$row_ordersResults['drip_feed'] - # of days they wont for their order to last
I did tried to lots of combinations by myself but I am totally stuck with this and cant make it work.
Thanks for help!
The libraries at momentjs.com is pretty cool. But if you just wanted something simple to calculate the "date difference" between two time values, there is a relatively simple way to do it. I assume you wanted it done in Javascript.
All you need to do is to clear out the hour/minute/second/millisecond fields of the two dates, calculate their differences in days. Put the script below in any web browser and you'll see how it works.
<script>
function foo() {
var d1 = new Date(2013, 8, 12, 13, 40, 1, 333); // any date value, last 4 params can be anything
var d2 = new Date(2013, 9, 3, 11, 42, 32, 533);
d1.setHours(0); d1.setMinutes(0); d1.setSeconds(0); d1.setMilliseconds(0);
d2.setHours(0); d2.setMinutes(0); d2.setSeconds(0); d2.setMilliseconds(0);
daysLeft = (d2.getTime() - d1.getTime())/(24*60*60*1000);
alert('Dear customer, there is(are) ' + daysLeft + ' day(s) left on your order!' );
}
</script>
Show Remaining Days on Order
EDIT: adding PHP version
<?php
$d1 = New DateTime('2013-08-28 06:25:00');
$d2 = new DateTime(); // now
$drip = 55;
$interval = $d2->diff($d1); // time difference
$days_left = $drip - $interval->format('%a'); // in days, subtract from drip
echo "There are $days_left days left\n";
?>
I hope I don't get marked down for not suggesting a specific answer, but time and date calculations are very tedious and JavaScript's Date() provides limited options. So rather than offer some ugly code, I suggest you take a look at moment.js at momentjs.com. Once you attach the script to your pages, you can easily manage all kind of date formats, and set up a function that will allow you to do math on dates and automatically generate your date ranges - it will even let you format them in to user friendly formats like "in 3 days", which I think is what you want. If your app has anything to do with time, and most do, I can't recommend Moment highly enough.