bunkat / later

A javascript library for defining recurring schedules and calculating future (or past) occurrences for them. Includes support for using English phrases and Cron schedules. Works in Node and in the browser.
http://bunkat.github.io/later/
MIT License
2.42k stars 245 forks source link

problem with fullDate? #62

Open etodanik opened 10 years ago

etodanik commented 10 years ago

I am trying to do something like:

var available = later.parse.recur()
              .on(
                availability.days
              )
                .dayOfWeek()
                .after(
                  moment(availability.start).format('HH:mm')
                )
                .time()
                .before(
                  moment(availability.end).format('HH:mm')
                )
                .time()
              .except()
                .on(holidays)
                .fullDate();

Where days is an array of numbers, and the hours are strings (both work). The three last lines seem to produce an error (the example will work without them) after using this with schedule.js:

/node_modules/later/later.js:1151
          values[i] = values[i].getTime();
                                ^
TypeError: Object 1411160400000 has no method 'getTime'

holidays is an array of Date() objects. How would I go about feeding it to later.js? Is there any other (working) way? If I only give one date it seems to work.

etodanik commented 10 years ago

Alright, now I tried it with specific dates, and I end up getting:

/Users/danny/src/dynamo/node_modules/later/later.js:572
    tickConstraint = constraints[constraintsLen - 1].constraint;
                                                    ^
TypeError: Cannot read property 'constraint' of undefined
    at Object.later.compile (/Users/danny/src/dynamo/node_modules/later/later.js:572:53)
    at Object.later.schedule (/Users/danny/src/dynamo/node_modules/later/later.js:628:29)
    at addResourceToMap (/Users/danny/src/dynamo/node_modules/schedulejs/schedule.js:346:118)
    at buildResourceMap (/Users/danny/src/dynamo/node_modules/schedulejs/schedule.js:340:11)
    at Object.schedule.resourceManager (/Users/danny/src/dynamo/node_modules/schedulejs/schedule.js:335:15)
    at Object.schedule.create (/Users/danny/src/dynamo/node_modules/schedulejs/schedule.js:543:72)
    at /Users/danny/src/dynamo/controllers/league.js:509:26
    at Function.forEach (/Users/danny/src/dynamo/node_modules/lodash/dist/lodash.js:3297:15)
    at async.waterfall.async.each.async.each.task (/Users/danny/src/dynamo/controllers/league.js:458:11)
    at fn (/Users/danny/src/dynamo/node_modules/async/lib/async.js:582:34)
bunkat commented 10 years ago

Hi,

The fullDate constraint is a little weird because I added for a particular thing that I needed and didn't really go through making it a fully supported constraint (this is why it isn't documented yet). If you want to use it, you need to use it with the before and after modifiers for it to make sense.

Instead of on(holidays).fullDate() you will need to loop through each of your holidays and append the holiday constraints something like this:

var holiday = new Date(2014,7,12),
      holiday2 = new Date(2014,7,13);

var s = later.parse.recur().every(5).minute()
              .except()
                  .after(holiday).fullDate()
                  .before(later.day.end(holiday)).fullDate()
              .and()
                  .after(holiday2).fullDate()
                  .before(later.day.end(holiday2)).fullDate();

 > Thu Aug 14 2014 00:00:00 GMT-0700 (Pacific Daylight Time)          

This schedule basically says to recur every 5 minutes except at anytime between the start of the day on the holiday until the end of the day on the holiday. If you don't use the before and after constraints then the constraint basically means not to occur only at the exact time you've specified which is probably not what you want and doesn't actually work as you found out.

Let me know if that works for you.

etodanik commented 10 years ago

Thanks for the response! I think I'm not grasping the part of the loop syntax. I tried the following, and it didn't really work (meaning, no error, but the dates I don't like are still being scheduled on):

var h;
var available = later.parse.recur()
    .on(
      availability.days
    )
      .dayOfWeek()
      .after(
        moment(availability.start).format('HH:mm')
      )
      .time()
      .before(
        moment(availability.end).format('HH:mm')
      )
      .time()
      .except()
        .after(holidays[0]).fullDate()
        .before(later.day.end(holidays[0])).fullDate();

for(h=1;h<holidays.length;h++){
  available = available.and()
    .after(holidays[h]).fullDate()
    .before(later.day.end(holidays[h])).fullDate();
}

Is there some sort of order thing that I'm messing up? (should the 'except' start after the dayOfWeek?).

bunkat commented 10 years ago

Could you do a console.log(available.schedules) and console.log(available.exceptions) for me? It will be easier for me to see what's going on that way. Thanks!

dshimkoski commented 10 years ago

I'm having a problem with exceptions too.

var holiday = new Date(2014,7,27);
var sched = later.parse.recur()
    .on([2,3,4]).dayOfWeek()
    .except()
        .after(holiday).fullDate()
        .before(later.day.end(holiday)).fullDate();
console.log(later.schedule(sched).next(10));

I'm expecting the 27th to be excluded, but it cuts everything from the 27th onward instead...

[ Mon Aug 25 2014 10:08:03 GMT-0400 (Eastern Daylight Time),
  Tue Aug 26 2014 00:00:00 GMT-0400 (Eastern Daylight Time) ]

Schedule:

[ { d: [ 2, 3, 4 ] } ]

Exceptions:

[ { fd_a: [ 1409112000000 ], fd_b: [ 1409198399000 ] } ]
bunkat commented 10 years ago

Yeah, looks like there are bugs in the full date constraint. I don't have time to debug right now, but there is a work around for specifying holidays to exclude. You can use the month, day, and year constraints to define your holidays (which is even easier than using full date if the holidays are the same day every year).

s = {schedules: [ { d: [ 2, 3, 4 ] } ], exceptions: [ { M: [8], D: [27], Y: [2014]},  { M: [9], D: [1], Y: [2014]}]}

later.schedule(s).next(10)
[Mon Aug 25 2014 11:00:21 GMT-0700 (Pacific Daylight Time),
 Tue Aug 26 2014 00:00:00 GMT-0700 (Pacific Daylight Time),
 Tue Sep 02 2014 00:00:00 GMT-0700 (Pacific Daylight Time),
 Wed Sep 03 2014 00:00:00 GMT-0700 (Pacific Daylight Time),
 Mon Sep 08 2014 00:00:00 GMT-0700 (Pacific Daylight Time),
 Tue Sep 09 2014 00:00:00 GMT-0700 (Pacific Daylight Time),
 Wed Sep 10 2014 00:00:00 GMT-0700 (Pacific Daylight Time),
 Mon Sep 15 2014 00:00:00 GMT-0700 (Pacific Daylight Time),
 Tue Sep 16 2014 00:00:00 GMT-0700 (Pacific Daylight Time),
 Wed Sep 17 2014 00:00:00 GMT-0700 (Pacific Daylight Time)]
dshimkoski commented 10 years ago

Thanks! That turned out to be a much better approach for my app.

Including an example here for fellow travelers...

function exceptUsHolidays(schedule) {
    return schedule.except()
        // new year's and MLK day
        .on(1).month().on([1, 20]).dayOfMonth()
        // presidents day - 3rd monday in feb
        .and().on(2).month().on(2).dayOfWeek().on(3).dayOfWeekCount()
        // memorial day - last monday in may
        .and().on(5).month().on(2).dayOfWeek().last().dayOfWeekCount()
        // independence day
        .and().on(7).month().on(4).dayOfMonth()
        // labor day - 1st monday in sept
        .and().on(9).month().on(2).dayOfWeek().on(1).dayOfWeekCount()
        // columbus day - 2nd monday in oct
        .and().on(10).month().on(2).dayOfWeek().on(2).dayOfWeekCount()
        // veterans day
        .and().on(11).month().on(11).dayOfMonth()
        // thanksgiving day - 4th thursday in nov
        .and().on(11).month().on(5).dayOfWeek().on(4).dayOfWeekCount()
        // christmas day
        .and().on(12).month().on(25).dayOfMonth();
}

Later is too awesome! :heart_eyes:

bunkat commented 10 years ago

Glad to hear that worked out for you!

etodanik commented 10 years ago

That's awesome as a workaround, but let's leave this issue open until there's a working fullDate constraint.

My problem is that I'm trying to work with a non-gregorian calendar holiday system (moon calendar) - which makes the dates variable. Therefore I need to specify the exact date each time.

On Tue, Aug 26, 2014 at 5:02 AM, bill notifications@github.com wrote:

Glad to hear that worked out for you!

— Reply to this email directly or view it on GitHub https://github.com/bunkat/later/issues/62#issuecomment-53365351.