]> git.donarmstrong.com Git - liborg-parser-perl.git/blob - lib/Org/Element/Timestamp.pm
Import original source of Org-Parser 0.23
[liborg-parser-perl.git] / lib / Org / Element / Timestamp.pm
1 package Org::Element::Timestamp;
2
3 use 5.010;
4 use locale;
5 use utf8;
6 use Moo;
7 extends 'Org::Element';
8
9 our $VERSION = '0.23'; # VERSION
10
11 has datetime => (is => 'rw');
12 has has_time => (is => 'rw');
13 has event_duration => (is => 'rw');
14 has recurrence => (is => 'rw');
15 has _repeater => (is => 'rw'); # stores the raw repeater spec
16 has _warning_period => (is => 'rw'); # stores the raw warning period spec
17 has is_active => (is => 'rw');
18
19 our @dow = (undef, qw(Mon Tue Wed Thu Fri Sat Sun));
20
21 sub as_string {
22     my ($self) = @_;
23     return $self->_str if $self->_str;
24     my $dt = $self->datetime;
25     my ($hour2, $min2);
26     if ($self->event_duration) {
27         my $hour = $dt->hour;
28         my $min = $dt->minute;
29         my $mins = $self->event_duration / 60;
30         $min2 = $min + $mins;
31         my $hours = int ($min2 / 60);
32         $hour2 = $hour + $hours;
33         $min2  = $min2 % 60;
34     }
35     join("",
36          $self->is_active ? "<" : "[",
37          $dt->ymd, " ",
38          $dow[$dt->day_of_week],
39          $self->has_time ? (
40              " ",
41              sprintf("%02d:%02d", $dt->hour, $dt->minute),
42              defined($hour2) ? (
43                  "-",
44                  sprintf("%02d:%02d", $hour2, $min2),
45              ) : (),
46              $self->_repeater ? (
47                  " ",
48                  $self->_repeater,
49              ) : (),
50              $self->_warning_period ? (
51                  " ",
52                  $self->_warning_period,
53              ) : (),
54          ) : (),
55          $self->is_active ? ">" : "]",
56      );
57 }
58
59 sub _parse_timestamp {
60     require DateTime;
61     require DateTime::Event::Recurrence;
62     my ($self, $str, $opts) = @_;
63     $opts //= {};
64     $opts->{allow_event_duration} //= 1;
65     $opts->{allow_repeater} //= 1;
66
67     my $num_re = qr/\d+(?:\.\d+)?/;
68
69     my $dow_re = qr/\w{1,3} |     # common, chinese 四, english thu
70                     \w{3}\.       # french, e.g. mer.
71                    /x;
72
73     $str =~ /^(?<open_bracket> \[|<)
74              (?<year> \d{4})-(?<mon> \d{2})-(?<day> \d{2}) \s+
75              (?:
76                  (?<dow> $dow_re) \s*?
77                  (?:\s+
78                      (?<hour> \d{2}):(?<min> \d{2})
79                      (?:-
80                          (?<event_duration>
81                              (?<hour2> \d{2}):(?<min2> \d{2}))
82                      )?
83                  )?
84                  (?:\s+(?<repeater>
85                          (?<repeater_prefix> \+\+|\.\+|\+)
86                          (?<repeater_interval> $num_re)
87                          (?<repeater_unit> [dwmy])
88                      )
89                  )?
90                  (?:\s+(?<warning_period>
91                          -
92                          (?<warning_period_interval> $num_re)
93                          (?<warning_period_unit> [dwmy])
94                      )
95                  )?
96              )?
97              (?<close_bracket> \]|>)
98              $/x
99                  or die "Can't parse timestamp string: $str";
100     # just for sanity. usually doesn't happen though because Document gives us
101     # either "[...]" or "<...>"
102     die "Mismatch open/close brackets in timestamp: $str"
103         if $+{open_bracket} eq '<' && $+{close_bracket} eq ']' ||
104             $+{open_bracket} eq '[' && $+{close_bracket} eq '>';
105     die "Duration not allowed in timestamp: $str"
106         if !$opts->{allow_event_duration} && $+{event_duration};
107     die "Repeater ($+{repeater}) not allowed in timestamp: $str"
108         if !$opts->{allow_repeater} && $+{repeater};
109
110     $self->is_active($+{open_bracket} eq '<' ? 1:0)
111         unless defined $self->is_active;
112
113     if ($+{event_duration} && !defined($self->event_duration)) {
114         $self->event_duration(
115             ($+{hour2}-$+{hour})*3600 +
116             ($+{min2} -$+{min} )*60
117         );
118     }
119
120     my %dt_args = (year => $+{year}, month=>$+{mon}, day=>$+{day});
121     if (defined($+{hour})) {
122         $dt_args{hour}   = $+{hour};
123         $dt_args{minute} = $+{min};
124         $self->has_time(1);
125     } else {
126         $self->has_time(0);
127     }
128     if ($self->document->time_zone) {
129         $dt_args{time_zone} = $self->document->time_zone;
130     }
131     #use Data::Dump; dd \%dt_args;
132     my $dt = DateTime->new(%dt_args);
133
134     if ($+{repeater} && !$self->recurrence) {
135         my $r;
136         my $i = $+{repeater_interval};
137         my $u = $+{repeater_unit};
138         if ($u eq 'd') {
139             $r = DateTime::Event::Recurrence->daily(
140                 interval=>$i, start=>$dt);
141         } elsif ($u eq 'w') {
142             $r = DateTime::Event::Recurrence->weekly(
143                 interval=>$i, start=>$dt);
144         } elsif ($u eq 'm') {
145             $r = DateTime::Event::Recurrence->monthly(
146                 interval=>$i, start=>$dt);
147         } elsif ($u eq 'y') {
148             $r = DateTime::Event::Recurrence->yearly(
149                 interval=>$i, start=>$dt);
150         } else {
151             die "BUG: Unknown repeater unit $u in timestamp $str";
152         }
153         $self->recurrence($r);
154         $self->_repeater($+{repeater});
155     }
156
157     if ($+{warning_period}) {
158         my $i = $+{warning_period_interval};
159         my $u = $+{warning_period_unit};
160         if ($u eq 'd') {
161         } elsif ($u eq 'w') {
162         } elsif ($u eq 'm') {
163         } elsif ($u eq 'y') {
164         } else {
165             die "BUG: Unknown warning period unit $u in timestamp $str";
166         }
167         $self->_warning_period($+{warning_period});
168     }
169
170     $self->datetime($dt);
171 }
172
173 1;
174 # ABSTRACT: Represent Org timestamp
175
176
177 =pod
178
179 =head1 NAME
180
181 Org::Element::Timestamp - Represent Org timestamp
182
183 =head1 VERSION
184
185 version 0.23
186
187 =head1 DESCRIPTION
188
189 Derived from L<Org::Element>.
190
191 =head1 ATTRIBUTES
192
193 =head2 datetime => DATETIME_OBJ
194
195 =head2 has_time => BOOL
196
197 =head2 event_duration => INT
198
199 Event duration in seconds, e.g. for event timestamp like this:
200
201  <2011-03-23 10:15-13:25>
202
203 event_duration is 7200+600=7800 (2 hours 10 minutes).
204
205 =head2 recurrence => DateTime::Event::Recurrence object
206
207 =head2 is_active => BOOL
208
209 =head1 METHODS
210
211 =for Pod::Coverage as_string
212
213 =head1 AUTHOR
214
215 Steven Haryanto <stevenharyanto@gmail.com>
216
217 =head1 COPYRIGHT AND LICENSE
218
219 This software is copyright (c) 2012 by Steven Haryanto.
220
221 This is free software; you can redistribute it and/or modify it under
222 the same terms as the Perl 5 programming language system itself.
223
224 =cut
225
226
227 __END__
228