| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package DateTime::Format::DateManip; |
|
2
|
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
15251
|
use strict; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
63
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
2
|
|
|
2
|
|
7
|
use vars qw ($VERSION); |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
131
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
$VERSION = '0.04'; |
|
8
|
|
|
|
|
|
|
|
|
9
|
2
|
|
|
2
|
|
15
|
use Carp; |
|
|
2
|
|
|
|
|
2
|
|
|
|
2
|
|
|
|
|
105
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
2
|
|
|
2
|
|
1133
|
use DateTime; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use DateTime::Duration; |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
use Date::Manip; |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# All formats are in the ASCII range so we can safely turn off UTF8 support |
|
18
|
|
|
|
|
|
|
use bytes; |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# This takes a Date::Manip string and converts it to a DateTime object |
|
21
|
|
|
|
|
|
|
# Note that the Date::Manip string just needs to be something that |
|
22
|
|
|
|
|
|
|
# Date::Manip::ParseDate() can format. |
|
23
|
|
|
|
|
|
|
# undef is returned if the string can not be converted. |
|
24
|
|
|
|
|
|
|
sub parse_datetime { |
|
25
|
|
|
|
|
|
|
my ($class, $dm_date) = @_; |
|
26
|
|
|
|
|
|
|
croak "Missing DateManip parseable string" unless defined $dm_date; |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# Get the timezone name and the date information and zome offset from |
|
29
|
|
|
|
|
|
|
# the Date::Manip string. |
|
30
|
|
|
|
|
|
|
my ($dm_tz, @bits) = UnixDate($dm_date, qw( %Z %Y %m %d %H %M %S %z )); |
|
31
|
|
|
|
|
|
|
return undef unless @bits; |
|
32
|
|
|
|
|
|
|
my @args = merge_lists([qw( year month day hour minute second time_zone )], |
|
33
|
|
|
|
|
|
|
\@bits); |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# Construct the DateTime object and use the offset timezone |
|
36
|
|
|
|
|
|
|
my $dt = DateTime->new(@args); |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# See if there is a better timezone to use |
|
39
|
|
|
|
|
|
|
my $dt_tz = $class->get_dt_timezone($dm_tz); |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# Apply the final time zone |
|
42
|
|
|
|
|
|
|
if (defined $dt_tz) { |
|
43
|
|
|
|
|
|
|
$dt->set_time_zone($dt_tz); |
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
return $dt; |
|
47
|
|
|
|
|
|
|
} |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# Takes a DateTime object and returns the corresponding Date::Manip string (in |
|
50
|
|
|
|
|
|
|
# the format returned by ParseDate) |
|
51
|
|
|
|
|
|
|
sub format_datetime { |
|
52
|
|
|
|
|
|
|
my ($class, $dt) = @_; |
|
53
|
|
|
|
|
|
|
croak "Missing DateTime object" unless defined $dt; |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# Note that we just use the TZ offset since Date::Manip doesn't |
|
56
|
|
|
|
|
|
|
# store time zone information with the dates but sets it system wide |
|
57
|
|
|
|
|
|
|
return ParseDate( $dt->strftime("%Y%m%dT%H%M%S %z") ); |
|
58
|
|
|
|
|
|
|
} |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# Takes a Date::Manip Delta string and returns the corresponding |
|
61
|
|
|
|
|
|
|
# DateTime::Duration object or undef |
|
62
|
|
|
|
|
|
|
sub parse_duration { |
|
63
|
|
|
|
|
|
|
my ($class, $dm_delta) = @_; |
|
64
|
|
|
|
|
|
|
croak "Missing DateManip parseable delta string" unless defined $dm_delta; |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
my @bits = Delta_Format($dm_delta, 0, qw( %yv %Mv %wv %dv %hv %mv %sv )); |
|
67
|
|
|
|
|
|
|
return undef unless @bits; |
|
68
|
|
|
|
|
|
|
my @args = merge_lists([qw( years months weeks days hours minutes seconds )], |
|
69
|
|
|
|
|
|
|
\@bits); |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# We have to do this in two phases since Date::Manip handles the sign |
|
72
|
|
|
|
|
|
|
# for years and months separately from the sign for the rest. |
|
73
|
|
|
|
|
|
|
# DateTime::Duration assumes that the sign is the same across all |
|
74
|
|
|
|
|
|
|
# items so we make the inital duration with years and months and add |
|
75
|
|
|
|
|
|
|
# the second duration (which may be negative) to finish the duration |
|
76
|
|
|
|
|
|
|
my $dt_dur = DateTime::Duration->new(@args[0..3]); # Year and month |
|
77
|
|
|
|
|
|
|
$dt_dur->add(@args[4..13]); # The rest |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
return $dt_dur; |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# Takes a DateTime::Duration object and returns the corresponding |
|
83
|
|
|
|
|
|
|
# Date::Manip Delta string (in the format returned by ParseDateDelta) |
|
84
|
|
|
|
|
|
|
sub format_duration { |
|
85
|
|
|
|
|
|
|
my ($class, $dt_dur) = @_; |
|
86
|
|
|
|
|
|
|
croak "Missing DateTime::Duration object" unless defined $dt_dur; |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# Not all elements are defined (if they can be derived from smaller elements) |
|
89
|
|
|
|
|
|
|
my %bits = $dt_dur->deltas(); |
|
90
|
|
|
|
|
|
|
my $str = join(":", |
|
91
|
|
|
|
|
|
|
0, # Years |
|
92
|
|
|
|
|
|
|
$bits{months}, |
|
93
|
|
|
|
|
|
|
0, # Weeks |
|
94
|
|
|
|
|
|
|
$bits{days}, |
|
95
|
|
|
|
|
|
|
0, # Hours |
|
96
|
|
|
|
|
|
|
$bits{minutes}, |
|
97
|
|
|
|
|
|
|
$bits{seconds}, |
|
98
|
|
|
|
|
|
|
); |
|
99
|
|
|
|
|
|
|
my $dm_dur = ParseDateDelta($str); |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
return $dm_dur; |
|
102
|
|
|
|
|
|
|
} |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
BEGIN { |
|
106
|
|
|
|
|
|
|
# Date::Manip to DateTime timezone mapping (where possible) |
|
107
|
|
|
|
|
|
|
my %TZ_MAP = |
|
108
|
|
|
|
|
|
|
( |
|
109
|
|
|
|
|
|
|
# Abbreviations (see http://www.worldtimezone.com/wtz-names/timezonenames.html) |
|
110
|
|
|
|
|
|
|
# [1] - YST matches worldtimezone.com but not Canada/Yukon |
|
111
|
|
|
|
|
|
|
# [2] - AT matches worldtimezone.com but not Atlantic/Azores |
|
112
|
|
|
|
|
|
|
# [3] - City chosen at random from similar matches |
|
113
|
|
|
|
|
|
|
idlw => "-1200", # International Date Line West (-1200) |
|
114
|
|
|
|
|
|
|
nt => "-1100", # Nome (-1100) (obs. -1967) |
|
115
|
|
|
|
|
|
|
hst => "US/Hawaii", # Hawaii Standard (-1000) |
|
116
|
|
|
|
|
|
|
cat => "-1000", # Central Alaska (-1000) (obs. -1967) |
|
117
|
|
|
|
|
|
|
ahst => "-1000", # Alaska-Hawaii Standard (-1000) (obs. 1967-1983) |
|
118
|
|
|
|
|
|
|
akst => "US/Alaska", # Alaska Standard (-0900) |
|
119
|
|
|
|
|
|
|
yst => "-0900", # Yukon Standard (-0900) [1] |
|
120
|
|
|
|
|
|
|
hdt => "-0900", # Hawaii Daylight (-0900) (until 1947?) |
|
121
|
|
|
|
|
|
|
akdt => "US/Alaska", # Alaska Daylight (-0800) |
|
122
|
|
|
|
|
|
|
ydt => "-0800", # Yukon Daylight (-0900) [1] |
|
123
|
|
|
|
|
|
|
pst => "US/Pacific", # Pacific Standard (-0800) |
|
124
|
|
|
|
|
|
|
pdt => "US/Pacific", # Pacific Daylight (-0700) |
|
125
|
|
|
|
|
|
|
mst => "US/Mountain", # Mountain Standard (-0700) |
|
126
|
|
|
|
|
|
|
mdt => "US/Mountain", # Mountain Daylight (-0600) |
|
127
|
|
|
|
|
|
|
cst => "US/Central", # Central Standard (-0600) |
|
128
|
|
|
|
|
|
|
cdt => "US/Central", # Central Daylight (-0500) |
|
129
|
|
|
|
|
|
|
est => "US/Eastern", # Eastern Standard (-0500) |
|
130
|
|
|
|
|
|
|
sat => "-0400", # Chile (-0400) |
|
131
|
|
|
|
|
|
|
edt => "US/Eastern", # Eastern Daylight (-0400) |
|
132
|
|
|
|
|
|
|
ast => "Canada/Atlantic", # Atlantic Standard (-0400) |
|
133
|
|
|
|
|
|
|
#nst => "Canada/Newfoundland", # Newfoundland Standard (-0300) nst=North Sumatra +0630 |
|
134
|
|
|
|
|
|
|
nft => "Canada/Newfoundland", # Newfoundland (-0330) |
|
135
|
|
|
|
|
|
|
#gst => "-0300", # Greenland Standard (-0300) gst=Guam Standard +1000 |
|
136
|
|
|
|
|
|
|
#bst => "Brazil/East", # Brazil Standard (-0300) bst=British Summer +0100 |
|
137
|
|
|
|
|
|
|
adt => "Canada/Atlantic", # Atlantic Daylight (-0300) |
|
138
|
|
|
|
|
|
|
ndt => "Canada/Newfoundland", # Newfoundland Daylight (-0230) |
|
139
|
|
|
|
|
|
|
at => "-0200", # Azores (-0200) [2] |
|
140
|
|
|
|
|
|
|
wat => "Africa/Bangui", # West Africa (-0100) [3] |
|
141
|
|
|
|
|
|
|
gmt => "Europe/London", # Greenwich Mean (+0000) |
|
142
|
|
|
|
|
|
|
ut => "Etc/Universal", # Universal (+0000) |
|
143
|
|
|
|
|
|
|
utc => "UTC", # Universal (Coordinated) (+0000) |
|
144
|
|
|
|
|
|
|
wet => "Europe/Lisbon", # Western European (+0000) [3] |
|
145
|
|
|
|
|
|
|
west => "Europe/Lisbon", # Alias for Western European (+0000) [3] |
|
146
|
|
|
|
|
|
|
cet => "Europe/Madrid", # Central European (+0100) |
|
147
|
|
|
|
|
|
|
fwt => "Europe/Paris", # French Winter (+0100) |
|
148
|
|
|
|
|
|
|
met => "Europe/Brussels", # Middle European (+0100) |
|
149
|
|
|
|
|
|
|
mez => "Europe/Berlin", # Middle European (+0100) |
|
150
|
|
|
|
|
|
|
mewt => "Europe/Brussels", # Middle European Winter (+0100) |
|
151
|
|
|
|
|
|
|
swt => "Europe/Stockholm", # Swedish Winter (+0100) |
|
152
|
|
|
|
|
|
|
bst => "Europe/London", # British Summer (+0100) bst=Brazil standard -0300 |
|
153
|
|
|
|
|
|
|
gb => "Europe/London", # GMT with daylight savings (+0100) |
|
154
|
|
|
|
|
|
|
eet => "Europe/Bucharest", # Eastern Europe, USSR Zone 1 (+0200) |
|
155
|
|
|
|
|
|
|
cest => "Europe/Madrid", # Central European Summer (+0200) |
|
156
|
|
|
|
|
|
|
fst => "Europe/Paris", # French Summer (+0200) |
|
157
|
|
|
|
|
|
|
# ist => "Asia/Jerusalem", # Israel standard (+0200) (duplicate of Indian) |
|
158
|
|
|
|
|
|
|
mest => "Europe/Brussels", # Middle European Summer (+0200) |
|
159
|
|
|
|
|
|
|
mesz => "Europe/Berlin", # Middle European Summer (+0200) |
|
160
|
|
|
|
|
|
|
metdst => "Europe/Brussels", # An alias for mest used by HP-UX (+0200) |
|
161
|
|
|
|
|
|
|
sast => "Africa/Johannesburg", # South African Standard (+0200) |
|
162
|
|
|
|
|
|
|
sst => "Europe/Stockholm", # Swedish Summer (+0200) sst=South Sumatra +0700 |
|
163
|
|
|
|
|
|
|
bt => "+0300", # Baghdad, USSR Zone 2 (+0300) |
|
164
|
|
|
|
|
|
|
eest => "Europe/Bucharest", # Eastern Europe Summer (+0300) |
|
165
|
|
|
|
|
|
|
eetedt => "Europe/Bucharest", # Eastern Europe, USSR Zone 1 (+0300) |
|
166
|
|
|
|
|
|
|
# idt => "Asia/Jerusalem", # Israel Daylight (+0300) [Jerusalem doesn't honor DST) |
|
167
|
|
|
|
|
|
|
msk => "Europe/Moscow", # Moscow (+0300) |
|
168
|
|
|
|
|
|
|
it => "Asia/Tehran", # Iran (+0330) |
|
169
|
|
|
|
|
|
|
zp4 => "+0400", # USSR Zone 3 (+0400) |
|
170
|
|
|
|
|
|
|
msd => "Europe/Moscow", # Moscow Daylight (+0400) |
|
171
|
|
|
|
|
|
|
zp5 => "+0500", # USSR Zone 4 (+0500) |
|
172
|
|
|
|
|
|
|
ist => "Asia/Calcutta", # Indian Standard (+0530) |
|
173
|
|
|
|
|
|
|
zp6 => "+0600", # USSR Zone 5 (+0600) |
|
174
|
|
|
|
|
|
|
nst => "+0630", # North Sumatra (+0630) nst=Newfoundland Std -0330 |
|
175
|
|
|
|
|
|
|
#sst => "+0700", # South Sumatra, USSR Zone 6 sst=Swedish Summer +0200 |
|
176
|
|
|
|
|
|
|
hkt => "Asia/Hong_Kong", # Hong Kong (+0800) |
|
177
|
|
|
|
|
|
|
sgt => "Asia/Singapore", # Singapore (+0800) |
|
178
|
|
|
|
|
|
|
cct => "Asia/Shanghai", # China Coast, USSR Zone 7 (+0800) |
|
179
|
|
|
|
|
|
|
awst => "Australia/West", # West Australian Standard (+0800) |
|
180
|
|
|
|
|
|
|
wst => "Australia/West", # West Australian Standard (+0800) |
|
181
|
|
|
|
|
|
|
pht => "Asia/Manila", # Asia Manila (+0800) |
|
182
|
|
|
|
|
|
|
kst => "Asia/Seoul", # Republic of Korea (+0900) |
|
183
|
|
|
|
|
|
|
jst => "Asia/Tokyo", # Japan Standard, USSR Zone 8 (+0900) |
|
184
|
|
|
|
|
|
|
rok => "ROK", # Republic of Korea (+0900) |
|
185
|
|
|
|
|
|
|
cast => "Australia/South", # Central Australian Standard (+0930) |
|
186
|
|
|
|
|
|
|
east => "Australia/Victoria", # Eastern Australian Standard (+1000) |
|
187
|
|
|
|
|
|
|
gst => "Pacific/Guam", # Guam Standard, USSR Zone 9 gst=Greenland Std -0300 |
|
188
|
|
|
|
|
|
|
cadt => "Australia/South", # Central Australian Daylight (+1030) |
|
189
|
|
|
|
|
|
|
eadt => "Australia/Victoria", # Eastern Australian Daylight (+1100) |
|
190
|
|
|
|
|
|
|
idle => "+1200", # International Date Line East |
|
191
|
|
|
|
|
|
|
nzst => "Pacific/Auckland", # New Zealand Standard |
|
192
|
|
|
|
|
|
|
nzt => "Pacific/Auckland", # New Zealand |
|
193
|
|
|
|
|
|
|
nzdt => "Pacific/Auckland", # New Zealand Daylight |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
# US Military Zones |
|
196
|
|
|
|
|
|
|
z => "+0000", |
|
197
|
|
|
|
|
|
|
a => "+0100", |
|
198
|
|
|
|
|
|
|
b => "+0200", |
|
199
|
|
|
|
|
|
|
c => "+0300", |
|
200
|
|
|
|
|
|
|
d => "+0400", |
|
201
|
|
|
|
|
|
|
e => "+0500", |
|
202
|
|
|
|
|
|
|
f => "+0600", |
|
203
|
|
|
|
|
|
|
g => "+0700", |
|
204
|
|
|
|
|
|
|
h => "+0800", |
|
205
|
|
|
|
|
|
|
i => "+0900", |
|
206
|
|
|
|
|
|
|
k => "+1000", |
|
207
|
|
|
|
|
|
|
l => "+1100", |
|
208
|
|
|
|
|
|
|
m => "+1200", |
|
209
|
|
|
|
|
|
|
n => "-0100", |
|
210
|
|
|
|
|
|
|
o => "-0200", |
|
211
|
|
|
|
|
|
|
p => "-0300", |
|
212
|
|
|
|
|
|
|
q => "-0400", |
|
213
|
|
|
|
|
|
|
r => "-0500", |
|
214
|
|
|
|
|
|
|
s => "-0600", |
|
215
|
|
|
|
|
|
|
t => "-0700", |
|
216
|
|
|
|
|
|
|
u => "-0800", |
|
217
|
|
|
|
|
|
|
v => "-0900", |
|
218
|
|
|
|
|
|
|
w => "-1000", |
|
219
|
|
|
|
|
|
|
x => "-1100", |
|
220
|
|
|
|
|
|
|
y => "-1200", |
|
221
|
|
|
|
|
|
|
); |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# Return the DateTime timezone corresponding to the given Date::Manip timezone or |
|
224
|
|
|
|
|
|
|
# return undef if there is no match. |
|
225
|
|
|
|
|
|
|
sub get_dt_timezone { |
|
226
|
|
|
|
|
|
|
my ($class, $dm_tz) = @_; |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# Work out the time zone that Date::Manip was using and try to reproduce it |
|
229
|
|
|
|
|
|
|
# in DateTime |
|
230
|
|
|
|
|
|
|
my $dt_tz = $dm_tz; |
|
231
|
|
|
|
|
|
|
if ($dm_tz =~ m{/}) { |
|
232
|
|
|
|
|
|
|
# Don't change it since it is in the complete form already |
|
233
|
|
|
|
|
|
|
# (e.g. America/New_York) |
|
234
|
|
|
|
|
|
|
} |
|
235
|
|
|
|
|
|
|
elsif ($dm_tz =~ m/^[-+]\d+$/) { |
|
236
|
|
|
|
|
|
|
# It is an offset, leave it alone (e.g. -0500) |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
else { |
|
239
|
|
|
|
|
|
|
# Look it up |
|
240
|
|
|
|
|
|
|
my $lc_tz = lc $dm_tz; |
|
241
|
|
|
|
|
|
|
$dt_tz = $TZ_MAP{$lc_tz}; |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
return $dt_tz; |
|
245
|
|
|
|
|
|
|
} |
|
246
|
|
|
|
|
|
|
} |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
# Take a list of keys and a list of values and insersperse them and |
|
249
|
|
|
|
|
|
|
# return the result |
|
250
|
|
|
|
|
|
|
sub merge_lists { |
|
251
|
|
|
|
|
|
|
my ($keys, $values) = @_; |
|
252
|
|
|
|
|
|
|
die "Length mismatch" unless @$keys == @$values; |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
# Add the argument names to the values |
|
255
|
|
|
|
|
|
|
my @result; |
|
256
|
|
|
|
|
|
|
for (my $i = 0; $i < @$keys; $i++) { |
|
257
|
|
|
|
|
|
|
push @result, $keys->[$i] => $values->[$i]; |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
return @result; |
|
261
|
|
|
|
|
|
|
} |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
1; |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
__END__ |