line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package DateTime::Format::ISO8601::Format; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY |
4
|
|
|
|
|
|
|
our $DATE = '2020-08-21'; # DATE |
5
|
|
|
|
|
|
|
our $DIST = 'DateTime-Format-ISO8601-Format'; # DIST |
6
|
|
|
|
|
|
|
our $VERSION = '0.004'; # VERSION |
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
625635
|
use 5.010001; |
|
1
|
|
|
|
|
11
|
|
9
|
1
|
|
|
1
|
|
16
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
26
|
|
10
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
637
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
sub new { |
13
|
12
|
|
|
12
|
1
|
69705
|
my ($class, %args) = @_; |
14
|
|
|
|
|
|
|
|
15
|
12
|
|
|
|
|
28
|
my $self = {}; |
16
|
|
|
|
|
|
|
|
17
|
12
|
100
|
|
|
|
48
|
if (defined(my $time_zone = delete $args{time_zone})) { |
18
|
6
|
|
|
|
|
11
|
$self->{time_zone} = do { |
19
|
6
|
50
|
|
|
|
16
|
if (ref $time_zone) { |
20
|
0
|
|
|
|
|
0
|
$time_zone; |
21
|
|
|
|
|
|
|
} else { |
22
|
6
|
|
|
|
|
42
|
require DateTime::TimeZone; |
23
|
6
|
|
|
|
|
34
|
DateTime::TimeZone->new(name => $time_zone); |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
}; |
26
|
|
|
|
|
|
|
} |
27
|
11
|
|
|
|
|
618
|
$self->{second_precision} = delete $args{second_precision}; |
28
|
11
|
100
|
|
|
|
34
|
if (keys %args) { |
29
|
1
|
|
|
|
|
20
|
die "Unknown attribute(s): ".join(", ", sort keys %args); |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
10
|
|
|
|
|
34
|
bless $self, $class; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub _format_date_or_time_or_datetime { |
36
|
40
|
|
|
40
|
|
90
|
my ($self, $which, $dt) = @_; |
37
|
|
|
|
|
|
|
|
38
|
40
|
100
|
|
|
|
112
|
if ($self->{time_zone}) { |
39
|
20
|
|
|
|
|
66
|
$dt = $dt->clone->set_time_zone($self->{time_zone}); |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
|
42
|
40
|
|
|
|
|
4003
|
my ($s_date, $s_time); |
43
|
|
|
|
|
|
|
|
44
|
40
|
100
|
100
|
|
|
172
|
if ($which eq 'date' || $which eq 'datetime') { |
45
|
24
|
|
|
|
|
81
|
$s_date = $dt->ymd('-'); |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
40
|
100
|
100
|
|
|
493
|
if ($which eq 'time' || $which eq 'datetime') { |
49
|
32
|
|
|
|
|
96
|
$s_time = $dt->hms(':'); |
50
|
32
|
100
|
100
|
|
|
349
|
if (($dt->nanosecond && |
|
|
|
100
|
|
|
|
|
51
|
|
|
|
|
|
|
!defined($self->{second_precision}) || |
52
|
|
|
|
|
|
|
$self->{second_precision})) { |
53
|
14
|
|
|
|
|
114
|
my $s_secfrac; |
54
|
14
|
100
|
|
|
|
36
|
if (!defined($self->{second_precision})) { |
55
|
6
|
|
|
|
|
15
|
$s_secfrac = sprintf("%s", $dt->nanosecond / 1e9); |
56
|
|
|
|
|
|
|
} else { |
57
|
8
|
|
|
|
|
33
|
$s_secfrac .= sprintf("%.$self->{second_precision}f", |
58
|
|
|
|
|
|
|
$dt->nanosecond / 1e9); |
59
|
|
|
|
|
|
|
} |
60
|
14
|
|
|
|
|
170
|
$s_time .= substr($s_secfrac, 1); # remove the "0" part |
61
|
|
|
|
|
|
|
} |
62
|
32
|
|
|
|
|
198
|
my $tz = $dt->time_zone; |
63
|
32
|
100
|
|
|
|
202
|
if ($tz->is_floating) { |
|
|
100
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# do nothing, no time zone designation |
65
|
|
|
|
|
|
|
} elsif ($tz->is_utc) { |
66
|
12
|
|
|
|
|
104
|
$s_time .= "Z"; |
67
|
|
|
|
|
|
|
} else { |
68
|
12
|
|
|
|
|
81
|
my $offset_secs = $tz->offset_for_datetime($dt); |
69
|
12
|
50
|
|
|
|
792
|
my $sign = $offset_secs >= 0 ? "+" : "-"; |
70
|
12
|
|
|
|
|
25
|
my $h = int(abs($offset_secs) / 3600); |
71
|
12
|
|
|
|
|
26
|
my $m = int((abs($offset_secs) - $h*3600) / 60); |
72
|
12
|
|
|
|
|
49
|
$s_time .= sprintf "%s%02d:%02d", $sign, $h, $m; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
40
|
100
|
|
|
|
139
|
if ($which eq 'date') { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
77
|
8
|
|
|
|
|
56
|
return $s_date; |
78
|
|
|
|
|
|
|
} elsif ($which eq 'time') { |
79
|
16
|
|
|
|
|
100
|
return $s_time; |
80
|
|
|
|
|
|
|
} elsif ($which eq 'datetime') { |
81
|
16
|
|
|
|
|
107
|
return $s_date . 'T' . $s_time; |
82
|
|
|
|
|
|
|
} else { |
83
|
0
|
|
|
|
|
0
|
die "BUG: Unknown which '$which'"; # shouldn't happen |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub format_date { |
88
|
8
|
|
|
8
|
1
|
30
|
my ($self, $dt) = @_; |
89
|
8
|
|
|
|
|
23
|
$self->_format_date_or_time_or_datetime('date', $dt); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub format_time { |
93
|
16
|
|
|
16
|
1
|
57
|
my ($self, $dt) = @_; |
94
|
16
|
|
|
|
|
42
|
$self->_format_date_or_time_or_datetime('time', $dt); |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
sub format_datetime { |
98
|
16
|
|
|
16
|
1
|
56
|
my ($self, $dt) = @_; |
99
|
16
|
|
|
|
|
38
|
$self->_format_date_or_time_or_datetime('datetime', $dt); |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
1; |
103
|
|
|
|
|
|
|
# ABSTRACT: Format DateTime object as ISO8601 date/time string |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
__END__ |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=pod |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=encoding UTF-8 |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=head1 NAME |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
DateTime::Format::ISO8601::Format - Format DateTime object as ISO8601 date/time string |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=head1 VERSION |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
This document describes version 0.004 of DateTime::Format::ISO8601::Format (from Perl distribution DateTime-Format-ISO8601-Format), released on 2020-08-21. |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=head1 SYNOPSIS |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
use DateTime::Format::ISO8601::Format; |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
my $format = DateTime::Format::ISO8601::Format->new( |
124
|
|
|
|
|
|
|
# time_zone => '...', # optional, default is DateTime object's time zone |
125
|
|
|
|
|
|
|
# second_precision => 3, # optional, default is undef |
126
|
|
|
|
|
|
|
); |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
my $dt_floating = DateTime->new(year=>2018, month=>6, day=>23, hour=>19, minute=>2, second=>3); |
129
|
|
|
|
|
|
|
my $dt_floating_frac = DateTime->new(year=>2018, month=>6, day=>23, hour=>19, minute=>2, second=>3, nanosecond=>0.456e9); |
130
|
|
|
|
|
|
|
my $dt_utc = DateTime->new(year=>2018, month=>6, day=>23, hour=>19, minute=>2, second=>3, time_zone=>'UTC'); |
131
|
|
|
|
|
|
|
my $dt_sometz = DateTime->new(year=>2018, month=>6, day=>23, hour=>19, minute=>2, second=>3, time_zone=>'Asia/Jakarta'); |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
Formatting dates: |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
say $format->format_date($dt_floating); # => 2018-06-23 |
136
|
|
|
|
|
|
|
say $format->format_date($dt_floating_frac); # => 2018-06-23 |
137
|
|
|
|
|
|
|
say $format->format_date($dt_utc); # => 2018-06-23 |
138
|
|
|
|
|
|
|
say $format->format_date($dt_sometz); # => 2018-06-23 |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# effect of setting time_zone attribute to 'Asia/Jakarta' (which has the offset +07:00): |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
say $format->format_date($dt_floating); # => 2018-06-23 |
143
|
|
|
|
|
|
|
say $format->format_date($dt_floating_frac); # => 2018-06-23 |
144
|
|
|
|
|
|
|
say $format->format_date($dt_utc); # => 2018-06-24 |
145
|
|
|
|
|
|
|
say $format->format_date($dt_sometz); # => 2018-06-23 |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
Formatting times: |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
say $format->format_time($dt_floating); # => 19:02:03 |
150
|
|
|
|
|
|
|
say $format->format_time($dt_floating_frac); # => 19:02:03.456 |
151
|
|
|
|
|
|
|
say $format->format_time($dt_utc); # => 19:02:03Z |
152
|
|
|
|
|
|
|
say $format->format_time($dt_sometz); # => 19:02:03+07:00 |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# effect of setting time_zone attribute to 'Asia/Jakarta' (which has the offset of +07:00): |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
say $format->format_time($dt_floating); # => 19:02:03+07:00 |
157
|
|
|
|
|
|
|
say $format->format_time($dt_floating_frac); # => 19:02:03.456+07:00 |
158
|
|
|
|
|
|
|
say $format->format_time($dt_utc); # => 02:02:03+07:00 |
159
|
|
|
|
|
|
|
say $format->format_time($dt_sometz); # => 19:02:03+07:00 |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# effect of setting second_precision to 3 |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
say $format->format_time($dt_floating); # => 19:02:03.000 |
164
|
|
|
|
|
|
|
say $format->format_time($dt_floating_frac); # => 19:02:03.456 |
165
|
|
|
|
|
|
|
say $format->format_time($dt_utc); # => 19:02:03.000Z |
166
|
|
|
|
|
|
|
say $format->format_time($dt_sometz); # => 19:02:03.000+07:00 |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
Formatting date+time: |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
say $format->format_datetime($dt_floating); # => 2018-06-23T19:02:03 |
171
|
|
|
|
|
|
|
say $format->format_datetime($dt_floating_frac); # => 2018-06-23T19:02:03.456 |
172
|
|
|
|
|
|
|
say $format->format_datetime($dt_utc); # => 2018-06-23T19:02:03Z |
173
|
|
|
|
|
|
|
say $format->format_datetime($dt_sometz); # => 2018-06-23T19:02:03+07:00 |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=head1 DESCRIPTION |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
This module formats L<DateTime> objects as ISO8601 date/time strings. It |
178
|
|
|
|
|
|
|
complements L<DateTime::Format::ISO8601>. |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=head2 time_zone |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
Optional. Used to force the time zone of DateTime objects to be formatted. |
185
|
|
|
|
|
|
|
Either string containing time zone name (e.g. "Asia/Jakarta", "UTC") or |
186
|
|
|
|
|
|
|
L<DateTime::TimeZone> object. Will be converted to DateTime::TimeZone |
187
|
|
|
|
|
|
|
internally. |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
The default is to use the DateTime object's time zone. |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
DateTime object with floating time zone will not have the time zone designation |
192
|
|
|
|
|
|
|
in the ISO8601 string, e.g.: |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
19:02:03 |
195
|
|
|
|
|
|
|
2018-06-23T19:02:03 |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
DateTime object with UTC time zone will have the "Z" time zone designation: |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
19:02:03Z |
200
|
|
|
|
|
|
|
2018-06-23T19:02:03Z |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
DateTime object with other time zones will have the "+hh:mm" time zone |
203
|
|
|
|
|
|
|
designation: |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
19:02:03+07:00 |
206
|
|
|
|
|
|
|
2018-06-23T19:02:03+07:00 |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=head2 second_precision |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
Optional. A non-negative integer. Used to control formatting (number of |
211
|
|
|
|
|
|
|
decimals) of the second fraction. The default is to only show fraction when they |
212
|
|
|
|
|
|
|
exist, with whatever precision C<sprintf("%s")> outputs. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=head1 METHODS |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=head2 new |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
Usage: |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
DateTime::Format::ISO8601::Format->new(%attrs) => obj |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=head2 format_date |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
Usage: |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
$format->format_date($dt) => str |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=head2 format_time |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
Usage: |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
$format->format_time($dt) => str |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=head2 format_datetime |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
Usage: |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
$format->format_datetime($dt) => str |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=head1 HOMEPAGE |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
Please visit the project's homepage at L<https://metacpan.org/release/DateTime-Format-ISO8601-Format>. |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=head1 SOURCE |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
Source repository is at L<https://github.com/perlancar/perl-DateTime-Format-ISO8601-Format>. |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=head1 BUGS |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=DateTime-Format-ISO8601-Format> |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
When submitting a bug or request, please include a test-file or a |
253
|
|
|
|
|
|
|
patch to an existing test-file that illustrates the bug or desired |
254
|
|
|
|
|
|
|
feature. |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=head1 SEE ALSO |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
L<DateTime::Format::ISO8601>. Before v0.12, DateTime::Format::ISO8601 does not |
259
|
|
|
|
|
|
|
feature a C<format_datetime()> method, so DateTime::Format::ISO8601::Format |
260
|
|
|
|
|
|
|
supplies that functionality. After v0.12, DateTime::Format::ISO8601 already has |
261
|
|
|
|
|
|
|
C<format_datetime()>, but currently DateTime::Format::ISO8601::Format's version |
262
|
|
|
|
|
|
|
is faster and there's C<format_date> and C<format_time> as well. So I'm keeping |
263
|
|
|
|
|
|
|
this module for now. |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
L<DateTime::Format::Duration::ISO8601> to parse and format ISO8601 durations. |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=head1 AUTHOR |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
perlancar <perlancar@cpan.org> |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
This software is copyright (c) 2020, 2018 by perlancar@cpan.org. |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
276
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=cut |