File Coverage

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


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