1 package Org::Element::Timestamp;
7 extends 'Org::Element';
9 our $VERSION = '0.23'; # VERSION
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');
19 our @dow = (undef, qw(Mon Tue Wed Thu Fri Sat Sun));
23 return $self->_str if $self->_str;
24 my $dt = $self->datetime;
26 if ($self->event_duration) {
28 my $min = $dt->minute;
29 my $mins = $self->event_duration / 60;
31 my $hours = int ($min2 / 60);
32 $hour2 = $hour + $hours;
36 $self->is_active ? "<" : "[",
38 $dow[$dt->day_of_week],
41 sprintf("%02d:%02d", $dt->hour, $dt->minute),
44 sprintf("%02d:%02d", $hour2, $min2),
50 $self->_warning_period ? (
52 $self->_warning_period,
55 $self->is_active ? ">" : "]",
59 sub _parse_timestamp {
61 require DateTime::Event::Recurrence;
62 my ($self, $str, $opts) = @_;
64 $opts->{allow_event_duration} //= 1;
65 $opts->{allow_repeater} //= 1;
67 my $num_re = qr/\d+(?:\.\d+)?/;
69 my $dow_re = qr/\w{1,3} | # common, chinese 四, english thu
70 \w{3}\. # french, e.g. mer.
73 $str =~ /^(?<open_bracket> \[|<)
74 (?<year> \d{4})-(?<mon> \d{2})-(?<day> \d{2}) \s+
78 (?<hour> \d{2}):(?<min> \d{2})
81 (?<hour2> \d{2}):(?<min2> \d{2}))
85 (?<repeater_prefix> \+\+|\.\+|\+)
86 (?<repeater_interval> $num_re)
87 (?<repeater_unit> [dwmy])
90 (?:\s+(?<warning_period>
92 (?<warning_period_interval> $num_re)
93 (?<warning_period_unit> [dwmy])
97 (?<close_bracket> \]|>)
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};
110 $self->is_active($+{open_bracket} eq '<' ? 1:0)
111 unless defined $self->is_active;
113 if ($+{event_duration} && !defined($self->event_duration)) {
114 $self->event_duration(
115 ($+{hour2}-$+{hour})*3600 +
116 ($+{min2} -$+{min} )*60
120 my %dt_args = (year => $+{year}, month=>$+{mon}, day=>$+{day});
121 if (defined($+{hour})) {
122 $dt_args{hour} = $+{hour};
123 $dt_args{minute} = $+{min};
128 if ($self->document->time_zone) {
129 $dt_args{time_zone} = $self->document->time_zone;
131 #use Data::Dump; dd \%dt_args;
132 my $dt = DateTime->new(%dt_args);
134 if ($+{repeater} && !$self->recurrence) {
136 my $i = $+{repeater_interval};
137 my $u = $+{repeater_unit};
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);
151 die "BUG: Unknown repeater unit $u in timestamp $str";
153 $self->recurrence($r);
154 $self->_repeater($+{repeater});
157 if ($+{warning_period}) {
158 my $i = $+{warning_period_interval};
159 my $u = $+{warning_period_unit};
161 } elsif ($u eq 'w') {
162 } elsif ($u eq 'm') {
163 } elsif ($u eq 'y') {
165 die "BUG: Unknown warning period unit $u in timestamp $str";
167 $self->_warning_period($+{warning_period});
170 $self->datetime($dt);
174 # ABSTRACT: Represent Org timestamp
181 Org::Element::Timestamp - Represent Org timestamp
189 Derived from L<Org::Element>.
193 =head2 datetime => DATETIME_OBJ
195 =head2 has_time => BOOL
197 =head2 event_duration => INT
199 Event duration in seconds, e.g. for event timestamp like this:
201 <2011-03-23 10:15-13:25>
203 event_duration is 7200+600=7800 (2 hours 10 minutes).
205 =head2 recurrence => DateTime::Event::Recurrence object
207 =head2 is_active => BOOL
211 =for Pod::Coverage as_string
215 Steven Haryanto <stevenharyanto@gmail.com>
217 =head1 COPYRIGHT AND LICENSE
219 This software is copyright (c) 2012 by Steven Haryanto.
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.