File Coverage

blib/lib/Acme/PM/Berlin/Meetings.pm
Criterion Covered Total %
statement 52 52 100.0
branch 19 20 95.0
condition 8 11 72.7
subroutine 8 8 100.0
pod 0 2 0.0
total 87 93 93.5


line stmt bran cond sub pod time code
1             # -*- perl -*-
2              
3             #
4             # Author: Slaven Rezic
5             #
6             # Copyright (C) 2010,2012,2015,2016,2017,2020 Slaven Rezic. All rights reserved.
7             # This package is free software; you can redistribute it and/or
8             # modify it under the same terms as Perl itself.
9             #
10             # Mail: slaven@rezic.de
11             # WWW: http://www.rezic.de/eserte/
12             #
13              
14             package Acme::PM::Berlin::Meetings;
15              
16 2     2   104144 use strict;
  2         14  
  2         90  
17             our $VERSION = '202008.24';
18              
19 2     2   12 use Exporter 'import'; # needs Exporter 5.57
  2         4  
  2         81  
20             our @EXPORT = qw(next_meeting);
21              
22 2     2   1810 use DateTime;
  2         1018136  
  2         1049  
23              
24             sub next_meeting {
25 1   50 1 0 122 my $count = shift || 1;
26 1         9 my $dt = DateTime->now(time_zone => 'local');
27 1         5114 map { $dt = next_meeting_dt($dt) } (1 .. $count);
  1         5  
28             }
29              
30             sub next_meeting_dt {
31 11     11 0 14166 my $dt = shift;
32 11         36 my $dt_berlin = $dt->clone->set_time_zone('Europe/Berlin');
33              
34             # Regular exception: December meeting is in January
35 11 100 66     15239 if ($dt_berlin->month == 1 && $dt_berlin->day < 10) {
36 2         31 my $dec_meeting = _get_dec_meeting($dt_berlin);
37 2 100       9 if ($dec_meeting > $dt_berlin) {
38 1         77 return $dec_meeting;
39             }
40             }
41              
42             # Exceptions
43             {
44             # August 2020 (last Wed -> last Tue)
45 10         140 my $dt_aug_2020 = DateTime->new(year=>2020, month=>8, day=>25, hour=>19, time_zone=>"Europe/Berlin");
  10         34  
46 10         6684 my $dt_aug_2020_from = DateTime->new(year=>2020, month=>7, day=>29, hour=>19, time_zone=>"Europe/Berlin");
47 10         6578 my $dt_aug_2020_until = DateTime->new(year=>2020, month=>8, day=>26, hour=>19, time_zone=>"Europe/Berlin");
48 10 100 100     6530 if ($dt_berlin > $dt_aug_2020_from && $dt_berlin < $dt_aug_2020) {
    100 66        
49 2         349 return $dt_aug_2020;
50             } elsif ($dt_berlin >= $dt_aug_2020 && $dt_berlin < $dt_aug_2020_until) {
51 1         290 $dt_berlin = $dt_aug_2020_until;
52             }
53             }
54              
55             # Regular meetings
56 8         1012 my $last_wed_of_month = _get_last_wed_of_month($dt_berlin);
57 8 100       29 if ($last_wed_of_month <= $dt_berlin) {
58 3         236 $dt_berlin->add(months => 1, end_of_month => 'limit');
59 3         4385 $last_wed_of_month = _get_last_wed_of_month($dt_berlin);
60             }
61 8 100       380 if ($last_wed_of_month->month == 12) {
62 2         16 return _get_dec_meeting($last_wed_of_month);
63             }
64 6         56 $last_wed_of_month;
65             }
66              
67             sub _get_last_wed_of_month {
68 11     11   26 my $dt_berlin = shift;
69 11         34 my $last_day_of_month = DateTime->last_day_of_month(year => $dt_berlin->year, month => $dt_berlin->month, time_zone => 'Europe/Berlin');
70 11         7158 my $dow = $last_day_of_month->day_of_week;
71 11 100       70 my $last_wed_of_month = $last_day_of_month->add(days => $dow < 3 ? -$dow-4 : -$dow+3);
72 11         8037 _adjust_hour($last_wed_of_month);
73 11         8160 $last_wed_of_month;
74             }
75              
76             sub _get_dec_meeting {
77 4     4   8 my $dt = shift;
78 4         10 $dt = $dt->clone;
79 4 100       42 if ($dt->month == 12) {
80 2         14 $dt->add(months => 1); # end_of_month does not matter
81             }
82 4         2892 $dt->set(day => 3);
83 4         2897 my $dow = $dt->day_of_week;
84 4 50       32 $dt->add(days => $dow < 4 ? -$dow+3 : -$dow+10);
85 4         5549 _adjust_hour($dt);
86 4         2902 $dt;
87             }
88              
89             sub _adjust_hour {
90 15     15   53 my $dt = shift;
91 15 100       42 if ($dt->year >= 2016) {
92 6         46 $dt->set(hour => 19);
93             } else {
94 9         66 $dt->set(hour => 20);
95             }
96             }
97              
98             1;
99              
100             __END__
101              
102             =head1 NAME
103              
104             Acme::PM::Berlin::Meetings - get the next date of the Berlin PM meeting
105              
106             =head1 SYNOPSIS
107              
108             use Acme::PM::Berlin::Meetings;
109             next_meeting(1)
110              
111             Or use the bundled script:
112              
113             berlin-pm
114              
115             =head1 NOTES
116              
117             This module knows about special Berlin.PM traditions like postponing
118             the December meeting to the first or second week in January.
119              
120             =head1 AUTHOR
121              
122             Slaven Rezic
123              
124             =head1 SEE ALSO
125              
126             L<Acme::PM::Barcelona::Meeting>, L<Acme::PM::Paris::Meetings>.
127              
128             =cut