DateTi...urrence(3pm)

πŸ“¦
version 0.19 Β· 6 versions
, in debian bookworm, debian trixie, ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’– DateTi...urrence(3pm) β€” DateTime::Event::Recurrence πŸ’–

okay bestie, so this is a page from the User Contributed Perl Documentation (that's the manual name, it's literally called DateTi...urrence(3pm) in the header, so cute, so truncated). Welcome to the glow-up of your recurrence game. ✨


🌸 NAME 🌸

DateTime::Event::Recurrence β€” it's a DateTime::Set extension that lets you create basic recurrence sets. That's it. That's the whole vibe. πŸ¦‹


✨ SYNOPSIS ✨

use DateTime;
use DateTime::Event::Recurrence;

my $dt = DateTime->new( year   => 2000,
                        month  => 6,
                        day    => 20,
                      );

my $daily_set = DateTime::Event::Recurrence->daily;

my $dt_next = $daily_set->next( $dt );

my $dt_previous = $daily_set->previous( $dt );

my $bool = $daily_set->contains( $dt );

my @days = $daily_set->as_list( start => $dt1, end => $dt2 );

my $iter = $daily_set->iterator;

while ( my $dt = $iter->next ) {
    print ' ', $dt->datetime;
}

πŸ’… DESCRIPTION πŸ’…

So this module is basically the bestie who does your scheduling for you. It hands you convenience methods so you can build DateTime::Set objects for all kinds of recurrences without losing your mind β€” stuff like "once a month" or "every day". 🌈

And if you're feeling extra? You can go full main-character and build way more complicated recurrences, like "every Monday, Wednesday and Thursday at 10:00 AM and 2:00 PM". Obsessed. πŸ‘‘


πŸŽ€ USAGE πŸŽ€

  • yearly monthly weekly daily hourly minutely secondly β€” every single one of these returns a brand new DateTime::Set object that represents the recurrence you asked for. slay.
my $daily_set = DateTime::Event::Recurrence->daily;

If you don't hand over any parameters, the set members each land at the beginning of the specified recurrence. fr fr.

Like, by default the monthly() method gives you back a set containing the first day of each month. And without parameters, the weekly() method gives you a set containing Mondays. Mondays, bestie. Every week. 😭

But β€” plot twist β€” you can pass in parameters to change where those datetimes fall. The parameters are the exact same ones you'd give to the DateTime::Duration constructor when you're specifying the length of a duration. So if you want a daily recurrence hitting at 10:30 every single day, you write this:

my $daily_at_10_30_set =
    DateTime::Event::Recurrence->daily( hours => 10, minutes => 30 );

Want every Tuesday (aka the second day of the week)? Say less:

my $weekly_on_tuesday_set =
    DateTime::Event::Recurrence->weekly( days => 2 );

A negative duration counts backwards from the end of the period. This works the same way as specified in RFC 2445 (iCal). And negative durations are so useful for stuff like the last day of each month:

my $last_day_of_month_set =
    DateTime::Event::Recurrence->monthly( days => -1 );

You can also provide multiple sets of duration arguments, like this:

    my $set = DateTime::Event::Recurrence->daily
                  ( hours =>   [ 10, 14,  -1 ],
                    minutes => [ 15, 30, -15 ],
                  );

Which specifies a recurrence happening every day at these 9 different times:

  10:15,  10:30,  10:45,   # +10h         ( +15min / +30min / last 15min (-15) )
  14:15,  14:30,  14:45,   # +14h         ( +15min / +30min / last 15min (-15) )
  23:15,  23:30,  23:45,   # last 1h (-1) ( +15min / +30min / last 15min (-15) )

Wanna make a set that recurs every thirty seconds? Easy:

    my $every_30_seconds_set =
        DateTime::Event::Recurrence->minutely( seconds => [ 0, 30 ] );

And this next one is also valid. Check the section on the interval parameter for the tea:

    my $every_30_seconds_set =
        DateTime::Event::Recurrence->secondly( interval => 30 );

πŸ’€ Invalid DateTimes πŸ’€

Invalid values get skipped at run time. No drama, they just don't show up.

For example, when days get added to a month, the result gets checked for a nonexisting day (like 31 or 30), and the invalid datetimes are skipped. Bye. πŸ™ˆ

Another example of this would be creating a set via the daily() method and specifying hours => 25. That's just not a thing, bestie. 😭

πŸ—“οΈ The days Parameter πŸ—“οΈ

The days parameter can be combined with yearly, monthly, and weekly recurrences, and that gives you six possible meanings:

# tuesday of every week
my $set = DateTime::Event::Recurrence->weekly( days => 2 );

# 10th day of every month
my $set = DateTime::Event::Recurrence->monthly( days => 10 );

# second full week of every month, on tuesday
my $set = DateTime::Event::Recurrence->monthly( weeks => 2, days => 2 );

# 10th day of every year
my $set = DateTime::Event::Recurrence->yearly( days => 10 );

# 10th day of every december
my $set = DateTime::Event::Recurrence->yearly( months => 12, days => 10 );

# second week of every year, on tuesday
my $set = DateTime::Event::Recurrence->yearly( weeks => 2, days => 2 );

Week days can also be called by name, as specified in RFC 2445 (iCal):

my $weekly_on_tuesday_set =
    DateTime::Event::Recurrence->weekly( days => 'tu' );

The days parameter defaults to "the first day". Also go read the section on the week_start_day parameter, iykyk.

# second full week of every month, on monday
my $set = DateTime::Event::Recurrence->monthly( weeks => 2 );

# second tuesday of every month
my $set = DateTime::Event::Recurrence->monthly( weeks => 2, days => "tu", week_start_day => "1tu" );

⏳ The interval and start Parameters ⏳

The interval parameter represents how often the recurrence rule repeats.

The optional start parameter says where to start counting:

my $dt_start = DateTime->new( year => 2003, month => 6, day => 15 );

my $set = DateTime::Event::Recurrence->daily
              ( interval => 11,
                hours    => 10,
                minutes  => 30,
                start    => $dt_start,
              );

So this specifies a recurrence that happens at 10:30 on the day given by start => $dt, and then every 11 days before and after $dt. Which gives us a set like this:

...
2003-06-04T10:30:00,
2003-06-15T10:30:00,
2003-06-26T10:30:00,
...

In this case, the method is what specifies the unit β€” so daily() means our unit is a day, and interval => 11 specifies the quantity of our unit. math girlie behavior. ✨

Heads up: the start parameter should have no time zone. periodt.

🌸 The week_start_day Parameter 🌸

The week_start_day represents how the 'first week' of a period gets calculated:

  • "mo", "tu", "we", "th", "fr", "sa", "su" β€” the first week is one that starts on this week-day, and has the most days in this period. Works for weekly and yearly recurrences.
  • "1mo", "1tu", "1we", "1th", "1fr", "1sa", "1su" β€” the first week is one that starts on this week-day, and has all days in this period. This works for weekly(), monthly() and yearly() recurrences.

The week_start_day defaults to "1mo", except in yearly (yearly()) recurrences, which default to "mo".

🌍 Time Zones 🌍

Recurrences are created in the 'floating' time zone, as specified in the DateTime module.

If you want to give a recurrence a time zone, you do it by calling set_time_zone() on the returned set:

my $daily = DateTime::Event::Recurrence->daily;
$daily->set_time_zone( 'Europe/Berlin' );

You can also pass a DateTime.pm object with a time zone to the set's next() and previous() methods:

my $dt = DateTime->today( time_zone => 'Europe/Berlin' );
my $next = $daily->next($dt);
Big warning, bestie: a recurrence can be affected by DST changes, so it's totally possible to specify a recurrence that creates nonexistent datetimes. And because DateTime.pm throws an exception if you ask it to create a non-existent datetime, please be careful when setting a time zone for your recurrence. 😭

It might be preferable to always use UTC for your sets, and then convert the returned object to whatever time zone you actually want. Just a thought. πŸ’…

⭐ Leap Seconds ⭐

There are no leap seconds, because the recurrences are created in the 'floating' time zone.

The value 60 for seconds (the leap second) is ignored. But if you really want the leap second, then specify the second as -1. iconic behavior, honestly. πŸ¦‹


πŸ‘‘ AUTHOR πŸ‘‘

Flavio Soibelmann Glock fglock@gmail.com


🫢 CREDITS 🫢

The API was developed with help from the people in the datetime@perl.org list. group project, but make it elegant. ✨

Special thanks to Dave Rolsky, Ron Hill and Matt Sisk for being around with ideas. πŸŽ€

If you can understand what this module does by reading the docs, you should thank Dave Rolsky. If you can't understand it, yell at him. He also helped removing weird idioms from the code. πŸ’€

Jerrad Pierce came with the idea to move interval from DateTime::Event::ICal to here. king behavior. πŸ‘‘


Copyright (c) 2003 Flavio Soibelmann Glock. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

The full text of the license can be found in the LICENSE file included with this module.


πŸ”— SEE ALSO πŸ”—

  • datetime@perl.org mailing list
  • DateTime Web page at http://datetime.perl.org/
  • DateTime - date and time :)
  • DateTime::Set - for recurrence-set accessors docs. You can use DateTime::Set to specify recurrences using callback subroutines.
  • DateTime::Event::ICal - if you need more complex recurrences.
  • DateTime::SpanSet - sets of intervals, including recurring sets of intervals.

and that's the whole page, bestie πŸ’– go forth and recur. this lil manual came to you courtesy of perl v5.34.0, dated 2022-06-13 β€” so if you're reading this, thank the ancient ones and slay. πŸŽ€βœ¨πŸ¦‹

πŸ“¦ where this page comes from