Rrule: рдПрдХ рджрд┐рди рдХреЗ рдЕрдиреБрд╕рд╛рд░ рд╕рдкреНрддрд╛рд╣ рдХреЗ рджрд┐рди рдХреА рдкрд╛рд▓реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдЖрд╡рд░реНрддреА рдШрдЯрдирд╛рдПрдБ

рдХреЛ рдирд┐рд░реНрдорд┐рдд 22 рдорд╛рд░реНрдЪ 2020  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: jakubroztocil/rrule

  • [x] рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдЖрдкрдиреЗ рдкрд╣рд▓реЗ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдХреЗ рд▓рд┐рдП рдореМрдЬреВрджрд╛ рдореБрджреНрджреЛрдВ рдХреЛ рджреЗрдЦрд╛ рд╣реИ
    рдПрдХ рдирдпрд╛ рдмрдирд╛рдирд╛
  • [x] рд╕рдорд╕реНрдпрд╛ рдХреЛ рдкреБрди: рдкреНрд░рд╕реНрддреБрдд рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдХреЛрдб рдирдореВрдирд╛ред рдЕрдкрдиреЗ рд╕рднреА рдЗрдирдкреБрдЯ рдорд╛рдиреЛрдВ рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд░рдирд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ
    рд╕рдЯреАрдХ RRule рд╕реНрдЯреНрд░рд┐рдВрдЧ рдФрд░ рддрд┐рдерд┐рдпреЛрдВ рдЬреИрд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВред
  • [x] рдЕрдкреЗрдХреНрд╖рд┐рдд рдЖрдЙрдЯрдкреБрдЯ
  • [x] рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЖрдЙрдЯрдкреБрдЯ
  • [x] rrule рдХрд╛ рд╡рд╣ рд╕рдВрд╕реНрдХрд░рдг

    • 2.6.4

  • [x] рдЖрдкрдХрд╛ рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо

    • рд▓рд┐рдирдХреНрд╕

  • [x] рдЖрдкрдХрд╛ рд╕реНрдерд╛рдиреАрдп рд╕рдордпрдХреНрд╖реЗрддреНрд░ (рдмрдЧ рджрд┐рдЦрд╛рдиреЗ рд╡рд╛рд▓реА рдорд╢реАрди рдХреА рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рд╕реЗ $ date рдЪрд▓рд╛рдПрдБ)

    • рдпреВрд░реЛрдк/рдкреЗрд░рд┐рд╕ рд▓реЗрдХрд┐рди рд╕рдордп рдХреНрд╖реЗрддреНрд░ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░ рджрд┐рдП рдЧрдП рд╣реИрдВред рдиреАрдЪреЗ рджреЗрдЦреЗрдВ


рдореИрдВ рдЕрдЧрд▓реЗ рдордВрдЧрд▓рд╡рд╛рд░ рдХреЛ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рддрд┐рдерд┐ (рдпреВрд░реЛрдк/рдкреЗрд░рд┐рд╕ рдореЗрдВ 1 рдлрд░рд╡рд░реА 2020) рдХреЗ рдмрд╛рдж рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред
рдлрд┐рд░ рднреА рдШрдЯрдирд╛рдПрдБ рдмреБрдзрд╡рд╛рд░ рд╕реЗ рд╢реБрд░реВ рд╣реЛрддреА рд╣реИрдВ рдпрджрд┐ рд╡реЗ рдЕрднреА рднреА рдЙрд╕ рд╕рдордп рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рд╣реИрдВред
рд╕рдордп рдХреНрд╖реЗрддреНрд░ рдЕрдореЗрд░рд┐рдХрд╛/рдиреНрдпреВрдпреЙрд░реНрдХ рдХреЗ рд▓рд┐рдП рдШрдЯрдирд╛рдУрдВ рдХреА рдЧрдгрдирд╛ рдХрд░рдирд╛ рдЕрдкреЗрдХреНрд╖рд┐рдд рд╣реИред

рдХреГрдкрдпрд╛ рдиреАрдЪреЗ рджрд┐рдП рдЧрдП рд╕реНрдирд┐рдкреЗрдЯ рдХреА рдЬрд╛рдВрдЪ рдХрд░реЗрдВред рдореЗрд░реЗ рдирд┐рд╖реНрдХрд░реНрд╖ рд╣реИрдВ:

// problem: events should be on Tuesday but are shifted by one day:
// Tue Feb 04 2020 00:00:00 GMT+0100 (Central European Standard Time) ...
$ TZ=Europe/Paris node zone.js Europe/Paris
rule:
DTSTART;TZID=Europe/Paris:20200131T230000
RRULE:FREQ=WEEKLY;BYDAY=TU;COUNT=2
events:
Wed Feb 05 2020 00:00:00 GMT+0100 (Central European Standard Time)
Wed Feb 12 2020 00:00:00 GMT+0100 (Central European Standard Time)
luxon:
Sat Feb 01 2020 00:00:00 GMT+0100 (Central European Standard Time)

// timezone America/New_York shows correct result
$ TZ=America/New_York node zone.js America/New_York
rule:
DTSTART;TZID=America/New_York:20200201T050000
RRULE:FREQ=WEEKLY;BYDAY=TU;COUNT=2
events:
Tue Feb 04 2020 00:00:00 GMT-0500 (Eastern Standard Time)
Tue Feb 11 2020 00:00:00 GMT-0500 (Eastern Standard Time)
luxon:
Sat Feb 01 2020 00:00:00 GMT-0500 (Eastern Standard Time)

// crossing timezones show correct result
$ TZ=America/New_York node zone.js Europe/Paris
rule:
DTSTART;TZID=Europe/Paris:20200201T050000
RRULE:FREQ=WEEKLY;BYDAY=TU;COUNT=2
events:
Mon Feb 03 2020 18:00:00 GMT-0500 (Eastern Standard Time)
Mon Feb 10 2020 18:00:00 GMT-0500 (Eastern Standard Time)
luxon:
Sat Feb 01 2020 00:00:00 GMT-0500 (Eastern Standard Time)

// UTC shows correct result
$ TZ=UTC node zone.js UTC
rule:
DTSTART:20200201T000000Z
RRULE:FREQ=WEEKLY;BYDAY=TU;COUNT=2
events:
Tue Feb 04 2020 00:00:00 GMT+0000 (Coordinated Universal Time)
Tue Feb 11 2020 00:00:00 GMT+0000 (Coordinated Universal Time)
luxon:
Sat Feb 01 2020 00:00:00 GMT+0000 (Coordinated Universal Time)
const { DateTime } = require('luxon')
const { RRule } = require('rrule/dist/es5/rrule-tz.js')

const dtstart = new Date(2020, 1, 1, 0)
const tzid = process.argv[2] || 'Europe/Paris'

const rule = new RRule({
  freq: RRule.WEEKLY,
  dtstart,
  tzid,
  byweekday: [RRule.TU],
  count: 2
})

console.log('rule:\n' + rule.toString())
console.log('events:\n' + rule.all().map(d => d.toString()).join('\n'))

const datetime = DateTime.fromJSDate(dtstart).setZone(tzid)
console.log('luxon:\n' + datetime.toJSDate().toString())

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

рд╣реИрд▓реЛ, рдпрд╣рд╛рдБ рдПрдХ рд╣реА рдореБрджреНрджрд╛
рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреЗ рд▓рд┐рдП: "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR;UNTIL=20200430T040000Z"

rule.all() TU,WE,TH,FR,SA рджрд┐рдЦрд╛рддрд╛ рд╣реИ

рд╕рднреА 3 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рд╣реИрд▓реЛ, рдпрд╣рд╛рдБ рдПрдХ рд╣реА рдореБрджреНрджрд╛
рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреЗ рд▓рд┐рдП: "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR;UNTIL=20200430T040000Z"

rule.all() TU,WE,TH,FR,SA рджрд┐рдЦрд╛рддрд╛ рд╣реИ

рдЕрдкрдбреЗрдЯ: рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдпреВрдЯреАрд╕реА рдЗрдирдкреБрдЯ рдХреЗ рд╕рд╛рде-рд╕рд╛рде рдЬреЗрдПрд╕ рдбреЗрдЯ рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЗ рд╕рдВрдмрдВрдз рдореЗрдВ rrule.js рдХреЗ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдореЗрд░рд╛ рднреНрд░рдо рдерд╛ред

рдЬреИрд╕рд╛ рдХрд┐ рдЕрдиреНрдп рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ, рдпрд╣ рднреНрд░рдо рдХрд╛рдлреА рд╕рд╛рдорд╛рдиреНрдп рд▓рдЧрддрд╛ рд╣реИ:
(1) TZID рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛
(2) DTSTART рдХреЛ рд╕рд╣реА рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдЗрдирдкреБрдЯ рдХрд░рдирд╛ (рдпреВрдЯреАрд╕реА рдХреЗ рдмрдЬрд╛рдп рд╕рдордп рдХреНрд╖реЗрддреНрд░ рдХреЗ рд▓рд┐рдП рд╕реНрдерд╛рдиреАрдп рдпрд╛ рдХрдВрдкреНрдпреВрдЯрд░ рдХреЗ рд▓рд┐рдП рд╕реНрдерд╛рдиреАрдп)
(3) рд╕рд╣реА рддрд┐рдерд┐рдпреЛрдВ рдХреЛ рдЗрдирдкреБрдЯ рдХрд░рдирд╛ rrule.between() ред рдпрджрд┐ рдПрдХ TZID рдШреЛрд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдареАрдХ рдЙрд╕реА рддрд░рд╣ рдЬреИрд╕реЗ рдЖрдкрдХреЛ рддрд╛рд░реАрдЦреЛрдВ рдХреЗ рдмрд╛рд╣рд░ рдЖрдиреЗ рдкрд░ рдорд╛рд▓рд┐рд╢ рдХрд░рдиреА рдкрдбрд╝рддреА рд╣реИ - DateTime.fromJSDate(date).toUTC().setZone('local', { keepLocalTime: true }) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдЖрдкрдХреЛ between() (рд╕рдВрднрд╡рддрдГ after/before рд░реВрдк рдореЗрдВ рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рддрд┐рдерд┐рдпреЛрдВ рдХреА рдорд╛рд▓рд┐рд╢ рдХрд░рдиреА рд╣реЛрдЧреА рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ) DateTime.fromMillis(posixTime).setZone('utc', { keepLocalTime: true }) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ред

рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдХреЗ рд╕рд╛рде рдореЗрд░реА рдкрд░реЗрд╢рд╛рдиреА рдХреЗ рдмрд╛рд╡рдЬреВрдж, рдФрд░ рдЕрдирд┐рдпрдВрддреНрд░рд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд┐рд░рд╛рд╢рд╛ рдХреЗ рдмрд╛рд╡рдЬреВрдж, рдореИрдВ рдмрд╣реБрдд рдЖрднрд╛рд░реА рд╣реВрдВ рдХрд┐ рдпрд╣ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдореМрдЬреВрдж рд╣реИред рдирд┐рд░реНрдорд╛рддрд╛ рдФрд░ рд╕рднреА рдЕрдиреБрд░рдХреНрд╖рдХреЛрдВ рдФрд░ рдпреЛрдЧрджрд╛рдирдХрд░реНрддрд╛рдУрдВ рдХреЛ рдзрдиреНрдпрд╡рд╛рджред рдмрд┐рд▓реНрдХреБрд▓ рд╡реИрд╕реЗ рд╣реА рдЬреИрд╕реЗ luxon рд╕реЗ рд╕реАрдЦрд╛ рд╕рдмрдХ рдХреЗ рд╣рд┐рд╕рд╛рдм рд╕реЗ рд╡рд┐рдХрд╕рд┐рдд moment , рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдПрдХ rrule рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХреА рдЕрдЧрд▓реЗ рдЪрд░рдг рдХреЗ рдХрдВрдзреЛрдВ рдкрд░ рдирд┐рд░реНрдорд╛рдг рдХрд░реЗрдЧрд╛ rrule.js ред

рдореВрд▓ рдкреЛрд╕реНрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ "рдореБрджреНрджрд╛", рдЬреЛ рдореИрдВрдиреЗ рдиреАрдЪреЗ рдХрд╣рд╛ рд╣реИ рдЙрд╕рдХреА рдЕрд╡рд╣реЗрд▓рдирд╛ рдХрд░реЗрдВред
рдпрд╣ рднреА рдЕрдиреБрднрд╡ рдХрд░ рд░рд╣рд╛ рд╣реИ рдХрд┐ рдпрд╣ рдореБрджреНрджрд╛ рдХреНрдпрд╛ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИред

import { rrulestr } from 'rrule';

const twoWeeks = 1209600000;
const myrrule = ["DTSTART:20200104T000000Z", "RRULE:FREQ=WEEKLY;BYDAY=FR"]
rrulestr(myrrule.join('\n'))
    .between(new Date(Date.now() - twoWeeks), new Date(Date.now() + twoWeeks))

рдпрд╣ рдЧреБрд░реБрд╡рд╛рд░ рдХреЛ рд╣реЛрдиреЗ рд╡рд╛рд▓реА рддрд┐рдерд┐рдпреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рджреЗрддрд╛ рд╣реИред
рдореИрдВрдиреЗ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд┐рдпрд╛ рд╣реИ рдХрд┐ DTSTART UTC рд╣реИред

рд╡рд┐рдЪрд╛рд░рд╛рдзреАрди рдШрдЯрдирд╛ рд╢реБрдХреНрд░рд╡рд╛рд░ рдХреЛ 18:00-0600 (рдкрд╣рд╛рдбрд╝ рд╕рдордп) рдкрд░ рд╣реЛрддреА рд╣реИ, рдЬреЛ рд╢рдирд┐рд╡рд╛рд░ 00:00-рдпреВрдЯреАрд╕реА рдХреЗ рд╕рдорд╛рди рд╣реИ, рд▓реЗрдХрд┐рди rrule.between() рдЕрдЬреАрдм рддрд░рд╣ рд╕реЗ @ рдЧреБрд░реБрд╡рд╛рд░ 18:00-0600 рдкрд░ рд▓реМрдЯрддрд╛ рд╣реИред

рдореИрдВ рдпрд╣ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдб рдХреЛ рд╡рд┐рдЪреНрдЫреЗрджрд┐рдд рдХрд░рдиреЗ рдХрд╛ рд╕рд╣рд░реНрд╖ рдкреНрд░рдпрд╛рд╕ рдХрд░реВрдБрдЧрд╛ рдХрд┐ рд╕рдорд╕реНрдпрд╛ рдХрд╣рд╛рдБ/рдХреИрд╕реЗ рд╣реЛ рд░рд╣реА рд╣реИред рдЕрдЧрд░ рдХреЛрдбрдмреЗрд╕ рд╕реЗ рдЕрдзрд┐рдХ рдкрд░рд┐рдЪрд┐рдд рдХрд┐рд╕реА рдХреЗ рдкрд╛рд╕ рдореБрдЭреЗ рд╕рд╣реА рджрд┐рд╢рд╛ рдореЗрдВ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╕реБрдЭрд╛рд╡ рд╣реИрдВ, рддреЛ рдореБрдЭреЗ рдмрддрд╛рдПрдВ, рдзрдиреНрдпрд╡рд╛рдж!

@davidgoli рд╣реЗ рдбреЗрд╡рд┐рдб! рдореИрдВ рдкрд┐рдЫрд▓реЗ 5 рджрд┐рдиреЛрдВ рд╕реЗ рдирд┐рдпрдо рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдпрд╣ рдкрддрд╛ рдирд╣реАрдВ рд▓рдЧрд╛ рд╕рдХрддрд╛ рдХрд┐ рдЯрд╛рдЗрдордЬрд╝реЛрди рдХреЗ рд╕рд╛рде рдХреИрд╕реЗ рдХрд╛рдо рдХрд┐рдпрд╛ рдЬрд╛рдПред рдЕрдЧрд░ рдореИрдВ рдЕрдкрдирд╛ рд╕рдордп рд░рд╛рдд 9 рдмрдЬреЗ рдбрд╛рд▓рддрд╛ рд╣реВрдВ, рддреЛ рдпрд╣ 4am UTC рд╕рдордп рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рдПрдХ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдХрд╛рд░рдг рдмрдирддрд╛ рд╣реИ рдЬрдм рдореИрдВ рдХреБрдЫ рджрд┐рдиреЛрдВ рдореЗрдВ рдкреБрдирд░рд╛рд╡рд░реНрддреА рдИрд╡реЗрдВрдЯ рд╕реЗрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ, рд╢реБрдХреНрд░рд╡рд╛рд░ рдХреЛ рдХрд╣реЗрдВред рддреЛ рдлрд┐рд░ рдпрд╣ рд╢реБрдХреНрд░рд╡рд╛рд░ рдХреЛ рд╕реБрдмрд╣ 4 рдмрдЬреЗ рджреЛрд╣рд░рд╛рддрд╛ рд╣реИ, рдФрд░ рдЬрдм рдЗрд╕реЗ рдореЗрд░реЗ рд╕рдордп рдХреНрд╖реЗрддреНрд░ рдореЗрдВ рд╡рд╛рдкрд╕ рдЕрдиреБрд╡рд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рдЧреБрд░реБрд╡рд╛рд░ рд░рд╛рдд 9 рдмрдЬреЗ рд╣реЛрддрд╛ рд╣реИ рдЬрдм рдореИрдВ рдЗрд╕реЗ рд╢реБрдХреНрд░рд╡рд╛рд░ рдХреЛ рдЪрд╛рд╣рддрд╛ рдерд╛ред рдХреНрдпрд╛ рдЖрдкрдХреЗ рдкрд╛рд╕ рдЗрд╕рдХреЗ рд▓рд┐рдП рдХреЛрдИ рд╕реБрдЭрд╛рд╡ рд╣реИ? рдореИрдВрдиреЗ tzid рдХреЗ рд╕рд╛рде рдкреНрд░рдпрд╛рд╕ рдХрд┐рдпрд╛ рд▓реЗрдХрд┐рди рдореИрдВ рдЗрд╕реЗ рдХрд╛рдо рдкрд░ рдирд╣реАрдВ рд▓рд╛ рд╕рдХрддрд╛ред рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдирд╣реАрдВ рд╣реИ рдХрд┐ рдореБрдЭреЗ рд▓рдХреНрд╕рди рдХреЛ рдХреИрд╕реЗ рд╢рд╛рдорд┐рд▓ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП? рдореИрдВрдиреЗ рдкреИрдХреЗрдЬ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░ рд▓рд┐рдпрд╛ рд╣реИред

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

shorlbeck picture shorlbeck  ┬╖  21рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

grigio picture grigio  ┬╖  7рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

shavenwalrus picture shavenwalrus  ┬╖  7рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

anthwinter picture anthwinter  ┬╖  11рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

espen picture espen  ┬╖  10рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ