## Where communities thrive

• Join over 1.5M+ people
• Join over 100K+ communities
• Free without limits
##### Activity
Matt Cooper
@vtbassmatt
Anyhow... back to this training. TTYL and good luck with the sprint!
Paul Ganssle
@pganssle
Thanks, enjoy the training!
Matthew Gilbert
@matthewgilbert

Was hoping to get a bit of feedback on designing a rrule. I'm wondering what the best way to create a minutely rule is but omit entire days. So for example get 5 minute intervals every weekday between some time but omit certain holidays. I thought of using something like

INTERVAL = 5
BUCKETS = int(60 / INTERVAL * 24)
WEEKDAYS = (MO, TU, WE, TH, FR)
nyd = rrule(MONTHLY, dtstart=datetime(2019, 1, 1, 0, 0), bymonth=1, byminute=range(0, 59, INTERVAL), byhour=range(0,24), bysetpos=range(1, BUCKETS + 1), byweekday=WEEKDAYS, count=300)

which works, but I'm wondering if this is some non recommended hackery. The reason I ask is because bysetpos only supports values up until 366. For minutely and secondly data you could have situations where you want to use bysetpos up to 1440 and 86400 respectively, so I'm wondering if bysetpos is not intended for this use?

Paul Ganssle
@pganssle
@matthewgilbert I'm not sure, the best thing to do would be to check the RFC.
Seems like it could just be a bug in dateutil.
One thing that may be useful would be to use an rruleset with an exrule.
So like this:
INTERVAL = 5
BUCKETS = int(60 / INTERVAL * 24)
WEEKDAYS = (MO, TU, WE, TH, FR)
rrule_base = rrule(MINUTELY, dtstart=datetime(2019, 1, 1, 0, 0), count=300, byweekday=WEEKDAYS)
rrset = rruleset()
rrset.rrule(rrule_base)
for dt in holidays:
rrset.exrule(rrule_base.replace(dtstart=dt, until=(dt + timedelta(days=1)), count=None))
Paul Ganssle
@pganssle
Not sure I fully understand what your rule is intended to do, and replacing dtstart and until will not always give you the same result as rrule.between(x, y), but you can see what I am getting at here.
Another way to do this (though possibly less efficient) would be to do something like:
for dt in holidays:
for inst in rrule_base.between(dt, dt + timedelta(days=1)):
rrset.exdate(inst)
There's video, slides and a repo of me going through similar examples as part of a talk I've given about dateutil a few times: https://ganssle.io/talks/#python-dateutil-talk
The Taiwanese Data Professionals one is the best video quality. The rrule stuff starts at 38:54
Matthew Gilbert
@matthewgilbert
Okay great much appreciated. Ya that example is just a toy example but the idea was to have something like 5 minute intervals between 9:30 a.m. and 4:00 p.m. on weekdays, but then excluding certain holidays such as the first business day of the new year. Your way of doing this definitely looks cleaner, thanks!

Following up on your comments about bysetpos and the RFC, I don't see any mention of restricting this. My guess is that it was implemented with DAILY frequency in mind? The docstrings also don't mention anything

If given, it must be either an integer, or a sequence of integers,
positive or negative. Each given integer will specify an occurrence
number, corresponding to the nth occurrence of the rule inside the
frequency period. For example, a bysetpos of -1 if combined with a
MONTHLY frequency, and a byweekday of (MO, TU, WE, TH, FR), will
result in the last work day of every month.

As a contrived example, lets say I want the 367th minute on Mondays, I could do something like
list(rrule(MINUTELY, dtstart=datetime(2019, 1, 1, 0, 0), bysetpos=367, count=3, byweekday=MO))
Matthew Gilbert
@matthewgilbert
^^^ I realise this probably isn't the approach you would want to use but just to illustrate an example of using the behaviour

In addition in playing around with this I think there may be an issue more broadly with bysetpos when using MINUTELY. This runs fine

In [11]: list(rrule(MINUTELY, dtstart=datetime(2019, 1, 1, 0, 0), bysetpos=1, count=1, byweekday=MO))
Out[11]: [datetime.datetime(2019, 1, 7, 0, 0)]

but this seems to run indefinitely

list(rrule(MINUTELY, dtstart=datetime(2019, 1, 1, 0, 0), bysetpos=2, count=1, byweekday=MO))
although possibly I am misunderstanding something. Not exactly sure what is going on but my guess is the rrule._iter yield statement is never reached? Or else the algorithm is just taking a very long time, still haven't fully grokked how _iter works
Matthew Gilbert
@matthewgilbert
If this stuff looks unexpected to you as well @pganssle let me know and I'll file an issue. Can try and dig a little deeper as well as some point to try and see what's involved with fixing
Paul Ganssle
@pganssle
@matthewgilbert Definitely seems worth hashing out in an issue.
Paul Ganssle
@pganssle
The parser needs the most love right now, a lot of stuff is stalled on that, but after that's done I'm hoping to rework the rrule internals.
I think that in most cases (and bysetpos may be an exception here), I can transform the inputs the the rule to some canonicalization so that freq=MINUTELY, interval=60 and freq=HOURLY, interval=1 "compile down" to the same thing, which I can then optimize.
RandomWolf
@RandomWolf
Quick question, how can I insr
Sorry, how can I install dateutil, skipping that it searches for packages online?
I'm on a machine that's completely cut off from the internet, and I have to painstakingly copy everything I need from my phone to the machine. Its always searching for setuptools, but I already have that installed
Paul Ganssle
@pganssle
@RandomWolf I think that is not really a dateutil question, more a pip question
It's because of the build isolation, so if you download the wheel file (.whl) for both dateutil and six, you shouldn't have to download anything to install them
pip download python-dateutil should download all the files.
torgash-ivanblch
@torgash-ivanblch
Hey,
got a problem with dateutils. Shortly:
1. dateutil.easter.easter(2020) returns Easter date calculated by EASTER_WESTERN algorithm.
2. dateutil.easter.easter(2020, 2) returns one calculated by EASTER_ORTHODOX algorithm - and that satisfies me pretty well as it's what I actually need, but...
3. dateutil.rrule.rrule(freq, count, byeaster) could be extremely useful for generating multiple occurences of Easter and Easter-related holidays if I could somehow change its default behaviour to orthodox algorithm, as it uses western by default.
Is it possible?
Paul Ganssle
@pganssle
@torgash-ivanblch I replied in the issue, but do you need any features of the recurrence other than easter?
Like you need something that is byeaster but not on Tuesdays or whatever?
Or 2 days before easter or something?
I only mention this because if you need something straightforward like "list of all easter dates", (easter.easter(y, easter.EASTER_ORTHODOX) for y in range(y_start, y_end)) should be a good start.
And if you want to use stuff like .before and .between you can create an rrule.rrulset() and then add all the easters as rdates.
You may have to convert them to datetime for it to work properly (which is not great UI).
Paul Ganssle
@pganssle
rrule is an interesting and complicated module, Part of my Pycon 2019 tutorial covers rrule and might help you find some workarounds: https://youtu.be/Xt8age1Be4E?t=7189 (starts at the part where I discuss rrule)
torgash-ivanblch
@torgash-ivanblch
@pganssle well, it's not so much about my own needs as about 3rd party projects like SwingTime for Django. They heavily depend on dateutil and particularly rrule. I found it interesting to fork swingtime and implement possibility to add some easter-offset holidays (we have some in Russia) to my calendar. But I really, really need an orthodox version of byeaster to do that, otherwise I'll have to code much more, and that's a pain in the...