File Coverage

blib/lib/Types/DateTime.pm
Criterion Covered Total %
statement 32 32 100.0
branch n/a
condition n/a
subroutine 11 11 100.0
pod n/a
total 43 43 100.0


line stmt bran cond sub pod time code
1 4     4   1219177 use 5.008;
  4         17  
2 4     4   21 use strict;
  4         8  
  4         70  
3 4     4   17 use warnings;
  4         11  
  4         192  
4              
5             package Types::DateTime;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.002';
9              
10 4     4   2184 use DateTime;
  4         1210274  
  4         127  
11 4     4   26 use DateTime::Duration;
  4         8  
  4         73  
12 4     4   25 use DateTime::Locale;
  4         8  
  4         55  
13 4     4   25 use DateTime::TimeZone;
  4         7  
  4         74  
14              
15 4     4   15 use Module::Runtime qw( use_module );
  4         7  
  4         28  
16              
17 4         44 use Type::Library -base, -declare => qw(
18             DateTime Duration TimeZone Locale Now
19             DateTimeWithZone DateTimeUTC
20 4     4   1688 );
  4         41512  
21 4     4   6964 use Types::Standard qw( Num Str HashRef InstanceOf );
  4         115006  
  4         39  
22 4     4   5933 use Type::Utils;
  4         13927  
  4         31  
23              
24             # This stuff for compat with MooseX::Types::DateTime
25              
26             class_type(DateTime, { class => 'DateTime' });
27             class_type(Duration, { class => 'DateTime::Duration' });
28             class_type(TimeZone, { class => 'DateTime::TimeZone' });
29             declare Locale,
30             as InstanceOf['DateTime::Locale::root','DateTime::Locale::FromData'];
31             enum(Now, ['now']);
32              
33             coerce DateTime,
34             from Num, q{ 'DateTime'->from_epoch(epoch => $_) },
35             from HashRef, q{ exists($_->{epoch}) ? 'DateTime'->from_epoch(%$_) : 'DateTime'->new(%{$_}) },
36             from Now, q{ 'DateTime'->now },
37             from InstanceOf['DateTime::Tiny'], q{ $_->DateTime };
38              
39             coerce Duration,
40             from Num, q{ 'DateTime::Duration'->new(seconds => $_) },
41             from HashRef, q{ 'DateTime::Duration'->new(%{$_}) };
42              
43             coerce TimeZone,
44             from Str, q{ 'DateTime::TimeZone'->new(name => $_) };
45              
46             coerce Locale,
47             from InstanceOf['Locale::Maketext'], q{ 'DateTime::Locale'->load($_->language_tag) },
48             from Str, q{ 'DateTime::Locale'->load($_) };
49              
50             # Time zone stuff
51              
52             declare DateTimeWithZone,
53             as DateTime,
54             coercion => 1, # inherit coercions
55             where { not($_ ->time_zone->is_floating) },
56             inline_as { (undef, "not($_\->time_zone->is_floating)") },
57             constraint_generator => sub {
58             my $zone = TimeZone->assert_coerce(shift);
59             sub { $_[0]->time_zone eq $zone };
60             },
61             coercion_generator => sub {
62             my $parent = shift;
63             my $child = shift;
64             my $zone = TimeZone->assert_coerce(shift);
65            
66             my $c = 'Type::Coercion'->new(type_constraint => $child);
67             $c->add_type_coercions(
68             $parent->coercibles, sub {
69             my $dt = DateTime->coerce($_);
70             return $_ unless DateTime->check($dt);
71             $dt->set_time_zone($zone);
72             return $dt;
73             },
74             );
75             $c;
76             };
77              
78             declare DateTimeUTC, as DateTimeWithZone['UTC'], coercion => 1;
79              
80             # Stringy coercions. No sugar for this stuff ;-)
81              
82             __PACKAGE__->meta->add_coercion({
83             name => 'Format',
84             type_constraint => DateTime,
85             coercion_generator => sub {
86             my ($self, $target, $format) = @_;
87             $format = use_module("DateTime::Format::$format")->new
88             unless ref($format);
89            
90             my $timezone;
91             if ($target->is_a_type_of(DateTimeWithZone))
92             {
93             my ($paramd_type) = grep {
94             $_->is_parameterized and $_->parent==DateTimeWithZone
95             } ($target, $target->parents);
96             $timezone = TimeZone->assert_coerce($paramd_type->type_parameter)
97             if $paramd_type;
98             }
99            
100             return (
101             Str,
102             sub {
103             my $dt = eval { $format->parse_datetime($_) };
104             return $_ unless $dt;
105             $dt->set_time_zone($timezone) if $timezone;
106             $dt;
107             },
108             );
109             },
110             });
111              
112             __PACKAGE__->meta->add_coercion({
113             name => 'Strftime',
114             type_constraint => Str,
115             coercion_generator => sub {
116             my ($self, $target, $format) = @_;
117             my $format_quoted = B::perlstring($format);
118             return (
119             DateTime->coercibles,
120             qq{\$_->strftime($format_quoted)},
121             );
122             },
123             });
124              
125             __PACKAGE__->meta->add_coercion({
126             name => 'ToISO8601',
127             type_constraint => Str,
128             type_coercion_map => [
129             DateTime->coercibles,
130             q{$_->iso8601},
131             ],
132             });
133              
134             1;
135              
136             __END__
137              
138             =pod
139              
140             =encoding utf-8
141              
142             =for stopwords datetime timezone
143              
144             =head1 NAME
145              
146             Types::DateTime - type constraints and coercions for datetime objects
147              
148             =head1 SYNOPSIS
149              
150             package FroobleGala;
151            
152             use Moose;
153             use Types::DateTime -all;
154            
155             has start_date => (
156             is => 'ro',
157             isa => DateTimeUTC->plus_coercions( Format['ISO8601'] ),
158             coerce => 1,
159             );
160              
161             =head1 DESCRIPTION
162              
163             L<Types::DateTime> is a type constraint library suitable for use with
164             L<Moo>/L<Moose> attributes, L<Kavorka> sub signatures, and so forth.
165              
166             =head2 Types
167              
168             This module provides some type constraints broadly compatible with
169             those provided by L<MooseX::Types::DateTime>, plus a couple of extra
170             type constraints.
171              
172             =over
173              
174             =item C<DateTime>
175              
176             A class type for L<DateTime>. Coercions from:
177              
178             =over
179              
180             =item from C<Num>
181              
182             Uses L<DateTime/from_epoch>. Floating values will be used for sub-second
183             precision, see L<DateTime> for details.
184              
185             =item from C<HashRef>
186              
187             Calls L<DateTime/new> or L<DateTime/from_epoch> as appropriate, passing
188             the hash as arguments.
189              
190             =item from C<Now>
191              
192             Uses L<DateTime/now>.
193              
194             =item from C<< InstanceOf['DateTime::Tiny'] >>
195              
196             Inflated using L<DateTime::Tiny/DateTime>.
197              
198             =back
199              
200             =item C<Duration>
201              
202             A class type for L<DateTime::Duration>. Coercions from:
203              
204             =over
205              
206             =item from C<Num>
207              
208             Uses L<DateTime::Duration/new> and passes the number as the C<seconds>
209             argument.
210              
211             =item from C<HashRef>
212              
213             Calls L<DateTime::Duration/new> with the hash entries as arguments.
214              
215             =back
216              
217             =item C<Locale>
218              
219             A class type for L<DateTime::Locale>. Coercions from:
220              
221             =over
222              
223             =item from C<Str>
224              
225             The string is treated as a language tag (e.g. C<en> or C<he_IL>) and
226             given to L<DateTime::Locale/load>.
227              
228             =item from C<< InstanceOf['Locale::Maketext'] >>
229              
230             The C<Locale::Maketext/language_tag> attribute will be used with
231             L<DateTime::Locale/load>.
232              
233             =back
234              
235             =item C<TimeZone>
236              
237             A class type for L<DateTime::TimeZone>. Coercions from:
238              
239             =over
240              
241             =item from C<Str>
242              
243             Treated as a time zone name or offset. See L<DateTime::TimeZone/USAGE>
244             for more details on the allowed values.
245              
246             Delegates to L<DateTime::TimeZone/new> with the string as the C<name>
247             argument.
248              
249             =back
250              
251             =item C<Now>
252              
253             Type constraint with only one allowed value, the string "now".
254              
255             This is exported for compatibility with L<MooseX::Types::DateTime>, which
256             exports such a constraint, even though it is not documented.
257              
258             =item C<DateTimeWithZone>
259              
260             A subtype of C<DateTime> for objects with a defined (non-floating) time
261             zone.
262              
263             This type constraint inherits its coercions from C<DateTime>.
264              
265             =item C<< DateTimeWithZone[`a] >>
266              
267             The C<DateTimeWithZone> type constraint may be parameterized with a
268             L<DateTime::TimeZone> object, or a string that can be coerced into one.
269              
270             has start_date => (
271             is => 'ro',
272             isa => DateTimeWithZone['Europe/London'],
273             coerce => 1,
274             );
275              
276             This type constraint inherits its coercions from C<DateTime>, and will
277             additionally call L<DateTime/set_time_zone> to shift objects into the
278             correct timezone.
279              
280             =item C<DateTimeUTC>
281              
282             Shortcut for C<< DateTimeWithZone["UTC"] >>.
283              
284             =back
285              
286             =head2 Named Coercions
287              
288             It is hoped that Type::Tiny will help avoid the proliferation of
289             modules like L<MooseX::Types::DateTimeX>,
290             L<MooseX::Types::DateTime::ButMaintained>, and
291             L<MooseX::Types::DateTime::MoreCoercions>. It makes it very easy to add
292             coercions to a type constraint at the point of use:
293              
294             has start_date => (
295             is => 'ro',
296             isa => DateTime->plus_coercions(
297             InstanceOf['MyApp::DT'] => sub { $_->to_DateTime }
298             ),
299             coerce => 1,
300             );
301              
302             Even easier, this module exports some named coercions.
303              
304             =over
305              
306             =item C<< Format[`a] >>
307              
308             May be passed an object providing a C<parse_datetime> method, or a
309             class name from the C<< DateTime::Format:: >> namespace (upon which
310             C<new> will be called).
311              
312             For example:
313              
314             DateTime->plus_coercions( Format['ISO8601'] )
315              
316             Or:
317              
318             DateTimeUTC->plus_coercions(
319             Format[
320             DateTime::Format::Natural->new(lang => 'en')
321             ]
322             )
323              
324             =item C<< Strftime[`a] >>
325              
326             A pattern for serializing a DateTime object into a string using
327             L<DateTime/strftime>.
328              
329             Str->plus_coercions( Strftime['%a %e %b %Y'] );
330              
331             =item C<ToISO8601>
332              
333             A coercion for serializing a DateTime object into a string using
334             L<DateTime/iso8601>.
335              
336             Str->plus_coercions( ToISO8601 );
337              
338             =back
339              
340             =head1 BUGS
341              
342             Please report any bugs to
343             L<http://rt.cpan.org/Dist/Display.html?Queue=Types-DateTime>.
344              
345             =head1 SEE ALSO
346              
347             L<MooseX::Types::DateTime>,
348             L<Type::Tiny::Manual>,
349             L<DateTime>,
350             L<DateTime::Duration>,
351             L<DateTime::Locale>,
352             L<DateTime::TimeZone>.
353              
354             =head1 AUTHOR
355              
356             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
357              
358             =head1 COPYRIGHT AND LICENCE
359              
360             This software is copyright (c) 2014, 2017 by Toby Inkster.
361              
362             This is free software; you can redistribute it and/or modify it under
363             the same terms as the Perl 5 programming language system itself.
364              
365             =head1 DISCLAIMER OF WARRANTIES
366              
367             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
368             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
369             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
370