| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
package MooseX::TimestampTZ; |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
=head1 NAME |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
MooseX::Timestamp - simple timestamp type for Moose, with Time Zone |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
use MooseX::TimestampTZ qw(:all); |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
print zone 0; # +0000 |
|
13
|
|
|
|
|
|
|
print zone 0, 1; # Z |
|
14
|
|
|
|
|
|
|
print zone 12*3600; # +1200 |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
print offset_s "Z"; # 0 |
|
17
|
|
|
|
|
|
|
print offset_s "+1200"; # 43200 (= 12 * 3600) |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# local times |
|
20
|
|
|
|
|
|
|
print timestamptz; # 2007-12-06 23:23:22+1300 |
|
21
|
|
|
|
|
|
|
print timestamptz 0; # 1970-01-01 12:00:00+1200 |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# UTC times |
|
24
|
|
|
|
|
|
|
print gmtimestamptz; # 2007-12-06 10:23:22+0000 |
|
25
|
|
|
|
|
|
|
print gmtimestamptz 0; # 1970-01-01 00:00:00+0000 |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
# hires timestamps |
|
28
|
|
|
|
|
|
|
print tmtimestamptz 0.123; # 1970-01-01 00:00:00.123+0000 |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
use MooseX::TimestampTZ ":all" => { hires => 1 }; |
|
31
|
|
|
|
|
|
|
print tmtimestamptz; # 2010-07-20 14:13:23.73418+1200 |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# conversion the other way |
|
34
|
|
|
|
|
|
|
print epoch "1970-01-01 00:00:00+0000"; # 0 |
|
35
|
|
|
|
|
|
|
print epoch "1970-01-01 12:00:00+1200"; # 0 |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
print for epochtz "1970-01-01 12:00:00+1200"; # 0, 43200 |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# you can get these ISO forms if you want, too. functions |
|
40
|
|
|
|
|
|
|
# that take a timestamptz accept either |
|
41
|
|
|
|
|
|
|
package SomewhereElse; |
|
42
|
|
|
|
|
|
|
use MooseX::TimestampTZ gmtimestamptz => { use_z => 1 }; |
|
43
|
|
|
|
|
|
|
print gmtimestamptz 0; # 1970-01-01 00:00:00Z |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
package MyClass; |
|
46
|
|
|
|
|
|
|
use Moose; |
|
47
|
|
|
|
|
|
|
has 'stamp' => |
|
48
|
|
|
|
|
|
|
isa => "Timestamp", |
|
49
|
|
|
|
|
|
|
is => "rw", |
|
50
|
|
|
|
|
|
|
coerce => 1; |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
package main; |
|
53
|
|
|
|
|
|
|
my $obj = MyClass->new(stamp => "2007-01-02 12:00:12"); # ok |
|
54
|
|
|
|
|
|
|
$obj->stamp("2007-01-02 12:01"); |
|
55
|
|
|
|
|
|
|
$obj->stamp("2007-01-02 12"); |
|
56
|
|
|
|
|
|
|
$obj->stamp("2007-01-02 12:00:00Gibbons"); #fail |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
This module provides floating dates on the Gregorian calendar without |
|
61
|
|
|
|
|
|
|
much code. It operates in (one particular variant of) ISO-8601 date |
|
62
|
|
|
|
|
|
|
format with time zone, and epoch times. Sub-second resolution is not |
|
63
|
|
|
|
|
|
|
yet supported. |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=cut |
|
66
|
|
|
|
|
|
|
|
|
67
|
3
|
|
|
3
|
|
44250
|
use strict; |
|
|
3
|
|
|
|
|
9
|
|
|
|
3
|
|
|
|
|
130
|
|
|
68
|
3
|
|
|
3
|
|
19
|
use warnings; |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
114
|
|
|
69
|
3
|
|
|
3
|
|
16
|
use Carp; |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
530
|
|
|
70
|
3
|
|
|
3
|
|
842
|
use MooseX::Timestamp qw(:all); |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
use Moose::Util::TypeConstraints; |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub _curry { |
|
74
|
|
|
|
|
|
|
my $class = shift; |
|
75
|
|
|
|
|
|
|
my $name = shift; |
|
76
|
|
|
|
|
|
|
my $arg_h = shift; |
|
77
|
|
|
|
|
|
|
my $col_h = shift; |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
my $chain = \&$name; |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
if ( defined $arg_h->{use_z} or defined $col_h->{defaults}{use_z} ) { |
|
82
|
|
|
|
|
|
|
my $use_z = defined $arg_h->{use_z} ? |
|
83
|
|
|
|
|
|
|
$arg_h->{use_z} : $col_h->{defaults}{use_z}; |
|
84
|
|
|
|
|
|
|
my $old_chain = $chain; |
|
85
|
|
|
|
|
|
|
$chain = sub { $old_chain->($_[0], $use_z) }; |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
if ( defined $arg_h->{hires} or defined $col_h->{defaults}{hires} ) { |
|
89
|
|
|
|
|
|
|
my $hires = defined $arg_h->{hires} ? |
|
90
|
|
|
|
|
|
|
$arg_h->{hires} : $col_h->{defaults}{hires}; |
|
91
|
|
|
|
|
|
|
if ( $hires ) { |
|
92
|
|
|
|
|
|
|
require Time::HiRes; |
|
93
|
|
|
|
|
|
|
my $old_chain = $chain; |
|
94
|
|
|
|
|
|
|
$chain = sub { |
|
95
|
|
|
|
|
|
|
$old_chain->( |
|
96
|
|
|
|
|
|
|
defined($_[0])?$_[0]:&Time::HiRes::time, |
|
97
|
|
|
|
|
|
|
@_[1..$#_], |
|
98
|
|
|
|
|
|
|
); |
|
99
|
|
|
|
|
|
|
}; |
|
100
|
|
|
|
|
|
|
} |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
$chain; |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub _curry_epoch { |
|
107
|
|
|
|
|
|
|
my $class = shift; |
|
108
|
|
|
|
|
|
|
my $name = shift; |
|
109
|
|
|
|
|
|
|
my $arg_h = shift; |
|
110
|
|
|
|
|
|
|
my $col_h = shift; |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
my $chain = \&$name; |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
if ( defined $arg_h->{hires} or defined $col_h->{defaults}{hires} ) { |
|
115
|
|
|
|
|
|
|
my $hires = defined $arg_h->{hires} ? |
|
116
|
|
|
|
|
|
|
$arg_h->{hires} : $col_h->{defaults}{hires}; |
|
117
|
|
|
|
|
|
|
if ( $hires ) { |
|
118
|
|
|
|
|
|
|
require Time::HiRes; |
|
119
|
|
|
|
|
|
|
my $old_chain = $chain; |
|
120
|
|
|
|
|
|
|
$chain = sub { |
|
121
|
|
|
|
|
|
|
if ( @_ ) { |
|
122
|
|
|
|
|
|
|
$old_chain->(@_); |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
else { |
|
125
|
|
|
|
|
|
|
return &Time::HiRes::time; |
|
126
|
|
|
|
|
|
|
} |
|
127
|
|
|
|
|
|
|
}; |
|
128
|
|
|
|
|
|
|
} |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
$chain; |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
use Sub::Exporter -setup => |
|
135
|
|
|
|
|
|
|
{ exports => |
|
136
|
|
|
|
|
|
|
[ qw(offset_s timestamp posixtime epochtz), |
|
137
|
|
|
|
|
|
|
epoch => \&_curry_epoch, |
|
138
|
|
|
|
|
|
|
map { ($_ => \&_curry) } qw(zone timestamptz gmtimestamptz), |
|
139
|
|
|
|
|
|
|
], |
|
140
|
|
|
|
|
|
|
groups => |
|
141
|
|
|
|
|
|
|
{ default => [ qw(timestamptz gmtimestamptz epoch) ] }, |
|
142
|
|
|
|
|
|
|
collectors => { defaults => sub { |
|
143
|
|
|
|
|
|
|
1; |
|
144
|
|
|
|
|
|
|
} }, |
|
145
|
|
|
|
|
|
|
}; |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
subtype "TimestampTZ" |
|
148
|
|
|
|
|
|
|
=> as "Str" |
|
149
|
|
|
|
|
|
|
=> where { |
|
150
|
|
|
|
|
|
|
m{^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[\-+]\d{4}|Z)$} |
|
151
|
|
|
|
|
|
|
and do { |
|
152
|
|
|
|
|
|
|
my $x; |
|
153
|
|
|
|
|
|
|
eval { $x = epoch($_) }; |
|
154
|
|
|
|
|
|
|
warn "Error: $@ on $_" if $@; |
|
155
|
|
|
|
|
|
|
!$@ |
|
156
|
|
|
|
|
|
|
}; |
|
157
|
|
|
|
|
|
|
}; |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
use Time::Local; |
|
160
|
|
|
|
|
|
|
use Memoize; |
|
161
|
|
|
|
|
|
|
memoize qw(zone); |
|
162
|
|
|
|
|
|
|
sub zone { |
|
163
|
|
|
|
|
|
|
my $offset_s = shift; |
|
164
|
|
|
|
|
|
|
my $use_z = shift; |
|
165
|
|
|
|
|
|
|
if ( $use_z and $offset_s == 0 ) { |
|
166
|
|
|
|
|
|
|
"Z"; |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
else { |
|
169
|
|
|
|
|
|
|
my $hh = sprintf("%.2d", int(abs($offset_s)/3600)); |
|
170
|
|
|
|
|
|
|
my $mm = sprintf("%.2d", int((abs($offset_s)-$hh*3600)/60)); |
|
171
|
|
|
|
|
|
|
my $s = ( $offset_s >= 0 ? "+" : "-" ); |
|
172
|
|
|
|
|
|
|
"$s$hh$mm"; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
} |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
sub offset_s { |
|
177
|
|
|
|
|
|
|
my $zone = shift or croak "no zone passed to offset_s!"; |
|
178
|
|
|
|
|
|
|
if ( $zone eq "Z" ) { |
|
179
|
|
|
|
|
|
|
return 0; |
|
180
|
|
|
|
|
|
|
} |
|
181
|
|
|
|
|
|
|
elsif ( $zone =~ m{^([\-+])(\d{2}):?(\d{2})?$}) { |
|
182
|
|
|
|
|
|
|
return ( ($1 eq "-" ? -1 : 1) * |
|
183
|
|
|
|
|
|
|
(($2 * 60) + ($3||0)) * 60 ); |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
else { |
|
186
|
|
|
|
|
|
|
croak "no timezone on '$zone'"; |
|
187
|
|
|
|
|
|
|
} |
|
188
|
|
|
|
|
|
|
} |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub timestamptz { |
|
191
|
|
|
|
|
|
|
my $time = shift; |
|
192
|
|
|
|
|
|
|
defined($time)||($time = time); |
|
193
|
|
|
|
|
|
|
my $use_z = shift; |
|
194
|
|
|
|
|
|
|
my @lt = localtime(int($time)); |
|
195
|
|
|
|
|
|
|
my $offset_s = timegm(@lt) - int($time); |
|
196
|
|
|
|
|
|
|
if ( int($time) != $time ) { |
|
197
|
|
|
|
|
|
|
$lt[0] += $time - int($time); |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
timestamp(@lt).zone($offset_s, $use_z); |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
sub gmtimestamptz { |
|
203
|
|
|
|
|
|
|
my $time = shift; |
|
204
|
|
|
|
|
|
|
defined($time)||($time = time); |
|
205
|
|
|
|
|
|
|
my $use_z = shift; |
|
206
|
|
|
|
|
|
|
my @gt = gmtime($time); |
|
207
|
|
|
|
|
|
|
if ( int($time) != $time ) { |
|
208
|
|
|
|
|
|
|
$gt[0] += $time - int($time); |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
timestamp(@gt).zone(0, $use_z); |
|
211
|
|
|
|
|
|
|
} |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub epochtz { |
|
214
|
|
|
|
|
|
|
my $timestamptz = shift || timestamptz; |
|
215
|
|
|
|
|
|
|
my ($timestamp, $zone) = |
|
216
|
|
|
|
|
|
|
($timestamptz =~ m{^(.*)([\-+]\d{2}(?::?\d{2})?|Z)$}x) |
|
217
|
|
|
|
|
|
|
or die "bad TimestampTZ passed to epoch: '$timestamptz'"; |
|
218
|
|
|
|
|
|
|
my @wct = posixtime($timestamp); |
|
219
|
|
|
|
|
|
|
my $frac = $wct[0] - int($wct[0]); |
|
220
|
|
|
|
|
|
|
$wct[0] = int($wct[0]); |
|
221
|
|
|
|
|
|
|
my $offset_s = offset_s($zone); |
|
222
|
|
|
|
|
|
|
(timegm(@wct) - $offset_s + $frac, $offset_s); |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub epoch { |
|
226
|
|
|
|
|
|
|
return time unless @_; |
|
227
|
|
|
|
|
|
|
return (epochtz(@_))[0]; |
|
228
|
|
|
|
|
|
|
} |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
subtype 'time_t' |
|
231
|
|
|
|
|
|
|
=> as "Int"; |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub _looks_like_timestamp { |
|
234
|
|
|
|
|
|
|
my ($epoch, $off) = eval { epochtz $_ }; |
|
235
|
|
|
|
|
|
|
if ( defined $epoch ) { |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
elsif ( eval { valid_posixtime(posixtime($_)) } and !$@ ) { |
|
238
|
|
|
|
|
|
|
my @gt = posixtime($_); |
|
239
|
|
|
|
|
|
|
my $frac = $gt[0] - int($gt[0]); |
|
240
|
|
|
|
|
|
|
$gt[0] = int($gt[0]); |
|
241
|
|
|
|
|
|
|
my $gmtime = timegm(@gt); |
|
242
|
|
|
|
|
|
|
my $localtime = timelocal(@gt); |
|
243
|
|
|
|
|
|
|
$epoch = $localtime + $frac; |
|
244
|
|
|
|
|
|
|
$off = ($localtime - $gmtime); |
|
245
|
|
|
|
|
|
|
} |
|
246
|
|
|
|
|
|
|
else { |
|
247
|
|
|
|
|
|
|
croak "bad TimestampTZ $_"; |
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
if ( wantarray ) { |
|
250
|
|
|
|
|
|
|
return ($epoch, $off); |
|
251
|
|
|
|
|
|
|
} |
|
252
|
|
|
|
|
|
|
else { |
|
253
|
|
|
|
|
|
|
return $epoch; |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
coerce 'time_t' |
|
258
|
|
|
|
|
|
|
=> from "Num" |
|
259
|
|
|
|
|
|
|
=> via { $_ }, |
|
260
|
|
|
|
|
|
|
=> from "TimestampTZ" |
|
261
|
|
|
|
|
|
|
=> via { epoch($_) } |
|
262
|
|
|
|
|
|
|
=> from "Str" |
|
263
|
|
|
|
|
|
|
=> via \&_looks_like_timestamp; |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
coerce 'Timestamp' |
|
266
|
|
|
|
|
|
|
=> from "TimestampTZ" |
|
267
|
|
|
|
|
|
|
=> via { |
|
268
|
|
|
|
|
|
|
my $epoch = epoch($_); |
|
269
|
|
|
|
|
|
|
my $frac = $epoch - int($epoch); |
|
270
|
|
|
|
|
|
|
my @lt = localtime(int($epoch)); |
|
271
|
|
|
|
|
|
|
$lt[0] += $frac; |
|
272
|
|
|
|
|
|
|
timestamp(@lt); |
|
273
|
|
|
|
|
|
|
}; |
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
# traditionally, coercing a timestamp to one with time zone and back |
|
276
|
|
|
|
|
|
|
# uses the local time, with the resultant ambiguities |
|
277
|
|
|
|
|
|
|
coerce 'TimestampTZ' |
|
278
|
|
|
|
|
|
|
=> from "TimestampTZ" |
|
279
|
|
|
|
|
|
|
=> via { $_ }, |
|
280
|
|
|
|
|
|
|
=> from "time_t" |
|
281
|
|
|
|
|
|
|
=> via { timestamptz($_) } |
|
282
|
|
|
|
|
|
|
=> from "Timestamp" |
|
283
|
|
|
|
|
|
|
=> via { |
|
284
|
|
|
|
|
|
|
my @lt = posixtime($_); |
|
285
|
|
|
|
|
|
|
my $frac = $lt[0] - int($lt[0]); |
|
286
|
|
|
|
|
|
|
$lt[0] = int($lt[0]); |
|
287
|
|
|
|
|
|
|
timestamptz(timelocal(@lt)+$frac); |
|
288
|
|
|
|
|
|
|
}, |
|
289
|
|
|
|
|
|
|
=> from "Str" |
|
290
|
|
|
|
|
|
|
=> via { |
|
291
|
|
|
|
|
|
|
my ($epoch, $off) = _looks_like_timestamp; |
|
292
|
|
|
|
|
|
|
my $frac = $epoch - int($epoch); |
|
293
|
|
|
|
|
|
|
my @gt = gmtime(int($epoch)+$off); |
|
294
|
|
|
|
|
|
|
$gt[0] += $frac; |
|
295
|
|
|
|
|
|
|
timestamp(@gt).zone($off); |
|
296
|
|
|
|
|
|
|
}; |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=head1 FUNCTIONS |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
The following functions are available for import. If you want to |
|
301
|
|
|
|
|
|
|
import them all, use the C<:all> import group, as below: |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
use MooseX::TimestampTZ qw(:all); |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=head2 zone(Int $offset, Bool $use_z = false) |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
Returns the timezone of the given offset. Pass $use_z to select |
|
308
|
|
|
|
|
|
|
returning "Z" as a timezone if the offset is 0. |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=head2 offset_s(Str) |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
Returns the offset corresponding to the given timezone. Does NOT |
|
313
|
|
|
|
|
|
|
accept nicknames like "EST", etc (which EST did you mean, US or |
|
314
|
|
|
|
|
|
|
Australian Eastern Standard Time?). |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head2 timestamptz(time_t $time_t = time(), Bool $use_z = false) |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
Returns the passed epoch time as a valid TimestampTZ, according to the |
|
319
|
|
|
|
|
|
|
local time zone rules in effect. C<$use_z> functions as with C<zone>. |
|
320
|
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
=head2 gmtimestamptz(time_t $time_t = time(), Bool $use_z = false) |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
Returns the passed epoch time as a valid TimestampTZ, corresponding to |
|
324
|
|
|
|
|
|
|
the time in UTC. C<$use_z> functions as with C<zone>, and if passed |
|
325
|
|
|
|
|
|
|
this function will always return TimestampTZs ending with C<Z>. |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
=head2 epoch() |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
Synonym for the built-in C<time()>. |
|
330
|
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
=head2 epoch(TimestampTZ) |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
Converts the passed TimestampTZ value to an epoch time. Does B<not> |
|
334
|
|
|
|
|
|
|
perform any coercion - the passed value must already have a time zone |
|
335
|
|
|
|
|
|
|
on it. You may omit any part of the time, specify the time zone in |
|
336
|
|
|
|
|
|
|
hours or with a C<Z>, and optionally separate your time from your date |
|
337
|
|
|
|
|
|
|
with a C<T>. Single digit values for fields are accepted. |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
Example valid forms: |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
2007-12-07 16:34:02+1200 |
|
342
|
|
|
|
|
|
|
2007-12-07 16:34+12 |
|
343
|
|
|
|
|
|
|
2007-12-07 04Z |
|
344
|
|
|
|
|
|
|
2007-12-7T4Z |
|
345
|
|
|
|
|
|
|
2007-12-7+12 |
|
346
|
|
|
|
|
|
|
2007120704:12:32 # Date::Manip format |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
Examples of ISO-8601 valid forms which are not currently accepted: |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
07-12-07Z |
|
351
|
|
|
|
|
|
|
071207Z |
|
352
|
|
|
|
|
|
|
20071207Z # seperators required |
|
353
|
|
|
|
|
|
|
2007120704Z |
|
354
|
|
|
|
|
|
|
-12-07Z # no year specified |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
No locale-specific date forms, such as C</> delimited dates, are |
|
357
|
|
|
|
|
|
|
accepted. |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=head2 epochtz(...) |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
Just like C<epoch()>, except returns the timezone as well. |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=head1 TYPES AND COERCIONS |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
The following subtypes are defined by this module: |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=head2 TimestampTZ |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
This is a subtype of C<Str> which conforms to one of the two |
|
370
|
|
|
|
|
|
|
normalized forms of a TimestampTZ (either with a Z, or without). |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
Rules exist to coerce C<Str>, C<Timestamp> and C<time_t> to this type, |
|
373
|
|
|
|
|
|
|
and are available by using the C<coerce =E<gt> 1> flag on a Moose |
|
374
|
|
|
|
|
|
|
attribute declaration: |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
package Widget; |
|
377
|
|
|
|
|
|
|
use MooseX::TimestampTZ; |
|
378
|
|
|
|
|
|
|
has 'created' => |
|
379
|
|
|
|
|
|
|
isa => TimestampTZ, |
|
380
|
|
|
|
|
|
|
is => "rw", |
|
381
|
|
|
|
|
|
|
coerce => 1; |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
With the above, if you set C<created> to a time_t value, it will |
|
384
|
|
|
|
|
|
|
automatically get converted into a TimestampTZ in the current time |
|
385
|
|
|
|
|
|
|
zone. |
|
386
|
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
A TimestampTZ value with a fractional second part is considered valid, |
|
388
|
|
|
|
|
|
|
regardless of whether C<hires> is passed to the importer. |
|
389
|
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
B<New in 0.07>: Timestamp to TimestampTZ conversion now happens in |
|
391
|
|
|
|
|
|
|
I<local time>, not UTC. |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=head2 time_t |
|
394
|
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
C<time_t> is a nicer way of writing an epoch time. If you set |
|
396
|
|
|
|
|
|
|
C<coerce =E<gt> 1> on your accessors, then you can happily pass in |
|
397
|
|
|
|
|
|
|
timestamps. As of MooseX::Timestamp 0.07, B<time_t> is a C<Num>, not |
|
398
|
|
|
|
|
|
|
merely an C<Int>. |
|
399
|
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
=head1 EXPORTS |
|
401
|
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
The default exporting action of this module is to export the |
|
403
|
|
|
|
|
|
|
C<timestamptz>, C<gmtimestamptz> and C<epoch> methods. To avoid this, |
|
404
|
|
|
|
|
|
|
pass an empty argument list to the use statement: |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
use MooseX::TimestampTZ (); |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
=head2 ISO-8601 "Z" TIMEZONE |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
Several of the functions which return a timezone may be told to return |
|
411
|
|
|
|
|
|
|
"Z" if the offset is 0, that is, the time is in UTC. To select this, |
|
412
|
|
|
|
|
|
|
pass a true second argument to any of the three functions (C<zone>, |
|
413
|
|
|
|
|
|
|
C<timestamptz> and C<gmtimestamptz>), or curry them on import; |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
use MooseX::TimestampTZ qw(:default), defaults => { use_z => 1 }; |
|
416
|
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
You can also curry individual functions like this: |
|
418
|
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
use MooseX::TimestampTZ zone => { use_z => 1 }; |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
=cut |
|
422
|
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
=head1 BUGS |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
This module is relatively slow, as conversions and calls to C<timegm> |
|
426
|
|
|
|
|
|
|
and friends happen far too often, really - especially with coercion. |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=head1 AUTHOR AND LICENSE |
|
429
|
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
Sam Vilain, <samv@cpan.org> |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
Copyright 2007, Sam Vilain. All Rights Reserved. This program is |
|
433
|
|
|
|
|
|
|
Free Software; you may use it and/or redistribute it under the terms |
|
434
|
|
|
|
|
|
|
of Perl itself. |
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=cut |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
1; |