3 use Test::MockTime qw(set_fixed_time restore_time);
8 my $localized_datetime_tests;
11 $localized_datetime_tests =
12 eval { require DateTime; 1; } && eval { require DateTime::Locale; 1; } &&
13 DateTime->can('format_cldr') && DateTime::Locale::root->can('date_format_full');
15 if ($localized_datetime_tests) {
17 # Include RT::Date::LocalizedDateTime tests
22 use warnings; use strict;
23 use RT::Test tests => $tests;
29 my $date = RT::Date->new($RT::SystemUser);
30 isa_ok($date, 'RT::Date', "constructor returned RT::Date oject");
31 $date = $date->new($RT::SystemUser);
32 isa_ok($date, 'RT::Date', "constructor returned RT::Date oject");
36 # set timezone in all places to UTC
37 $RT::SystemUser->UserObj->__Set(Field => 'Timezone', Value => 'UTC')
38 if $RT::SystemUser->UserObj->Timezone;
39 RT->Config->Set( Timezone => 'UTC' );
44 my $user = RT::User->new($RT::SystemUser);
45 my($uid, $msg) = $user->Create(
46 Name => "date_api". rand(200),
50 ok($uid, "user was created") or diag("error: $msg");
51 $current_user = RT::CurrentUser->new($user);
55 my $date = RT::Date->new( $current_user );
56 is($date->Timezone, 'UTC', "dropped all timzones to UTC");
57 is($date->Timezone('user'), 'UTC', "dropped all timzones to UTC");
58 is($date->Timezone('server'), 'UTC', "dropped all timzones to UTC");
59 is($date->Timezone('unknown'), 'UTC', "with wrong context returns UTC");
61 $current_user->UserObj->__Set( Field => 'Timezone', Value => 'Europe/Moscow');
62 is($current_user->UserObj->Timezone,
64 "successfuly changed user's timezone");
65 is($date->Timezone('user'),
67 "in user context returns user's timezone");
68 is($date->Timezone, 'UTC', "the deafult value is always UTC");
69 is($date->Timezone('server'), 'UTC', "wasn't changed");
71 RT->Config->Set( Timezone => 'Africa/Ouagadougou' );
72 is($date->Timezone('server'),
74 "timezone of the RT server was changed");
75 is($date->Timezone('user'),
77 "in user context still returns user's timezone");
78 is($date->Timezone, 'UTC', "the deafult value is always UTC");
80 $current_user->UserObj->__Set( Field => 'Timezone', Value => '');
81 is_empty($current_user->UserObj->Timezone,
82 "successfuly changed user's timezone");
83 is($date->Timezone('user'),
85 "in user context returns timezone of the server if user's one is not defined");
86 is($date->Timezone, 'UTC', "the deafult value is always UTC");
88 RT->Config->Set( Timezone => 'GMT' );
89 is($date->Timezone('server'),
91 "timezone is GMT which one is alias for UTC");
93 RT->Config->Set( Timezone => '' );
94 is($date->Timezone, 'UTC', "dropped all timzones to UTC");
95 is($date->Timezone('user'),
97 "user's and server's timzones are not defined, so UTC");
98 is($date->Timezone('server'),
100 "timezone of the server is not defined so UTC");
102 RT->Config->Set( Timezone => 'UTC' );
106 my $date = RT::Date->new($RT::SystemUser);
107 is($date->Unix, 0, "new date returns 0 in Unix format");
108 is($date->Get, '1970-01-01 00:00:00', "default is ISO format");
109 is($date->Get(Format =>'SomeBadFormat'),
110 '1970-01-01 00:00:00',
111 "don't know format, return ISO format");
112 is($date->Get(Format =>'W3CDTF'),
113 '1970-01-01T00:00:00Z',
114 "W3CDTF format with defaults");
115 is($date->Get(Format =>'RFC2822'),
116 'Thu, 1 Jan 1970 00:00:00 +0000',
117 "RFC2822 format with defaults");
118 is($date->Get(Format =>'LocalizedDateTime'),
119 'Thu, Jan 1, 1970 12:00:00 AM',
120 "LocalizedDateTime format with defaults") if ( $localized_datetime_tests );
122 is($date->ISO(Time => 0),
124 "ISO format without time part");
125 is($date->W3CDTF(Time => 0),
127 "W3CDTF format without time part");
128 is($date->RFC2822(Time => 0),
130 "RFC2822 format without time part");
131 is($date->LocalizedDateTime(Time => 0),
133 "LocalizedDateTime format without time part") if ( $localized_datetime_tests );
135 is($date->ISO(Date => 0),
137 "ISO format without date part");
138 is($date->W3CDTF(Date => 0),
139 '1970-01-01T00:00:00Z',
140 "W3CDTF format is incorrect without date part");
141 is($date->RFC2822(Date => 0),
143 "RFC2822 format without date part");
144 is($date->LocalizedDateTime(Date => 0),
146 "LocalizedDateTime format without date part") if ( $localized_datetime_tests );
148 is($date->ISO(Date => 0, Seconds => 0),
150 "ISO format without date part and seconds");
151 is($date->W3CDTF(Date => 0, Seconds => 0),
153 "W3CDTF format without seconds, but we ship date part even if Date is false");
154 is($date->RFC2822(Date => 0, Seconds => 0),
156 "RFC2822 format without date part and seconds");
158 is($date->RFC2822(DayOfWeek => 0),
159 '1 Jan 1970 00:00:00 +0000',
160 "RFC2822 format without 'day of week' part");
161 is($date->RFC2822(DayOfWeek => 0, Date => 0),
163 "RFC2822 format without 'day of week' and date parts(corner case test)");
165 is($date->LocalizedDateTime(AbbrDay => 0),
166 'Thursday, Jan 1, 1970 12:00:00 AM',
167 "LocalizedDateTime format without abbreviation of day") if ( $localized_datetime_tests );
168 is($date->LocalizedDateTime(AbbrMonth => 0),
169 'Thu, January 1, 1970 12:00:00 AM',
170 "LocalizedDateTime format without abbreviation of month") if ( $localized_datetime_tests );
171 is($date->LocalizedDateTime(DateFormat => 'date_format_short'),
172 '1/1/70 12:00:00 AM',
173 "LocalizedDateTime format with non default DateFormat") if ( $localized_datetime_tests );
174 is($date->LocalizedDateTime(TimeFormat => 'time_format_short'),
175 'Thu, Jan 1, 1970 12:00 AM',
176 "LocalizedDateTime format with non default TimeFormat") if ( $localized_datetime_tests );
180 "the default format for the 'Date' method is ISO");
181 is($date->Date(Format => 'W3CDTF'),
183 "'Date' method, W3CDTF format");
184 is($date->Date(Format => 'RFC2822'),
186 "'Date' method, RFC2822 format");
187 is($date->Date(Time => 1),
189 "'Date' method doesn't pass through 'Time' argument");
190 is($date->Date(Date => 0),
192 "'Date' method overrides 'Date' argument");
196 "the default format for the 'Time' method is ISO");
197 is($date->Time(Format => 'W3CDTF'),
198 '1970-01-01T00:00:00Z',
199 "'Time' method, W3CDTF format, date part is required by w3c doc");
200 is($date->Time(Format => 'RFC2822'),
202 "'Time' method, RFC2822 format");
203 is($date->Time(Date => 1),
205 "'Time' method doesn't pass through 'Date' argument");
206 is($date->Time(Time => 0),
208 "'Time' method overrides 'Time' argument");
211 '1970-01-01 00:00:00',
212 "the default format for the 'DateTime' method is ISO");
213 is($date->DateTime(Format =>'W3CDTF'),
214 '1970-01-01T00:00:00Z',
215 "'DateTime' method, W3CDTF format");
216 is($date->DateTime(Format =>'RFC2822'),
217 'Thu, 1 Jan 1970 00:00:00 +0000',
218 "'DateTime' method, RFC2822 format");
219 is($date->DateTime(Date => 0, Time => 0),
220 '1970-01-01 00:00:00',
221 "the 'DateTime' method overrides both 'Date' and 'Time' arguments");
225 { # positive timezone
226 $current_user->UserObj->__Set( Field => 'Timezone', Value => 'Europe/Moscow');
227 my $date = RT::Date->new( $current_user );
228 $date->Set( Format => 'ISO', Timezone => 'utc', Value => '2005-01-01 15:10:00' );
229 is($date->ISO( Timezone => 'user' ), '2005-01-01 18:10:00', "ISO");
230 is($date->W3CDTF( Timezone => 'user' ), '2005-01-01T18:10:00+03:00', "W3C DTF");
231 is($date->RFC2822( Timezone => 'user' ), 'Sat, 1 Jan 2005 18:10:00 +0300', "RFC2822");
234 $date = RT::Date->new( $current_user );
235 $date->Set( Format => 'ISO', Timezone => 'utc', Value => '2005-07-01 15:10:00' );
236 is($date->ISO( Timezone => 'user' ), '2005-07-01 19:10:00', "ISO");
237 is($date->W3CDTF( Timezone => 'user' ), '2005-07-01T19:10:00+04:00', "W3C DTF");
238 is($date->RFC2822( Timezone => 'user' ), 'Fri, 1 Jul 2005 19:10:00 +0400', "RFC2822");
241 { # negative timezone
242 $current_user->UserObj->__Set( Field => 'Timezone', Value => 'America/New_York');
243 my $date = RT::Date->new( $current_user );
244 $date->Set( Format => 'ISO', Timezone => 'utc', Value => '2005-01-01 15:10:00' );
245 is($date->ISO( Timezone => 'user' ), '2005-01-01 10:10:00', "ISO");
246 is($date->W3CDTF( Timezone => 'user' ), '2005-01-01T10:10:00-05:00', "W3C DTF");
247 is($date->RFC2822( Timezone => 'user' ), 'Sat, 1 Jan 2005 10:10:00 -0500', "RFC2822");
250 $date = RT::Date->new( $current_user );
251 $date->Set( Format => 'ISO', Timezone => 'utc', Value => '2005-07-01 15:10:00' );
252 is($date->ISO( Timezone => 'user' ), '2005-07-01 11:10:00', "ISO");
253 is($date->W3CDTF( Timezone => 'user' ), '2005-07-01T11:10:00-04:00', "W3C DTF");
254 is($date->RFC2822( Timezone => 'user' ), 'Fri, 1 Jul 2005 11:10:00 -0400', "RFC2822");
259 my $date = RT::Date->new($RT::SystemUser);
260 $date->Set( Format => 'bad' );
261 is($date->Unix, 0, "bad format");
262 } qr'Unknown Date format: bad';
265 { # setting value via Unix method
266 my $date = RT::Date->new($RT::SystemUser);
268 is($date->ISO, '1970-01-01 00:00:01', "correct value");
270 foreach (undef, 0, ''){
272 is($date->ISO, '1970-01-01 00:00:01', "correct value");
274 $date->Set(Format => 'unix', Value => $_);
275 is($date->ISO, '1970-01-01 00:00:00', "Set a date to midnight 1/1/1970 GMT due to wrong call");
276 is($date->Unix, 0, "unix is 0 => unset");
280 my $year = (localtime(time))[5] + 1900;
283 my $date = RT::Date->new($RT::SystemUser);
285 $date->Set(Format => 'ISO', Value => 'weird date');
286 } qr/Couldn't parse date 'weird date' as a ISO format/;
287 is($date->Unix, 0, "date was wrong => unix == 0");
289 # XXX: ISO format has more feature than we suport
290 # http://www.cl.cam.ac.uk/~mgk25/iso-time.html
292 $date->Set(Format => 'ISO', Value => '2005-11-28 15:10:00');
293 is($date->ISO, '2005-11-28 15:10:00', "YYYY-DD-MM hh:mm:ss");
295 $date->Set(Format => 'ISO', Value => '2005-11-28 15:10:00+00');
296 is($date->ISO, '2005-11-28 15:10:00', "YYYY-DD-MM hh:mm:ss+00");
298 $date->Set(Format => 'ISO', Value => '11-28 15:10:00');
299 is($date->ISO, $year .'-11-28 15:10:00', "DD-MM hh:mm:ss");
301 $date->Set(Format => 'ISO', Value => '11-28 15:10:00+00');
302 is($date->ISO, $year .'-11-28 15:10:00', "DD-MM hh:mm:ss+00");
304 $date->Set(Format => 'ISO', Value => '20051128151000');
305 is($date->ISO, '2005-11-28 15:10:00', "YYYYDDMMhhmmss");
307 $date->Set(Format => 'ISO', Value => '1128151000');
308 is($date->ISO, $year .'-11-28 15:10:00', "DDMMhhmmss");
310 $date->Set(Format => 'ISO', Value => '2005112815:10:00');
311 is($date->ISO, '2005-11-28 15:10:00', "YYYYDDMMhh:mm:ss");
313 $date->Set(Format => 'ISO', Value => '112815:10:00');
314 is($date->ISO, $year .'-11-28 15:10:00', "DDMMhh:mm:ss");
316 $date->Set(Format => 'ISO', Value => '2005-13-28 15:10:00');
317 is($date->Unix, 0, "wrong month value");
319 $date->Set(Format => 'ISO', Value => '2005-00-28 15:10:00');
320 is($date->Unix, 0, "wrong month value");
322 $date->Set(Format => 'ISO', Value => '1960-01-28 15:10:00');
323 is($date->Unix, 0, "too old, we don't support");
326 { # set+datemanip format(Time::ParseDate)
327 my $date = RT::Date->new($RT::SystemUser);
328 $date->Set(Format => 'unknown', Value => 'weird date');
329 is($date->Unix, 0, "date was wrong");
331 RT->Config->Set( Timezone => 'Europe/Moscow' );
332 $date->Set(Format => 'datemanip', Value => '2005-11-28 15:10:00');
333 is($date->ISO, '2005-11-28 12:10:00', "YYYY-DD-MM hh:mm:ss");
335 RT->Config->Set( Timezone => 'UTC' );
336 $date->Set(Format => 'datemanip', Value => '2005-11-28 15:10:00');
337 is($date->ISO, '2005-11-28 15:10:00', "YYYY-DD-MM hh:mm:ss");
339 $current_user->UserObj->__Set( Field => 'Timezone', Value => 'Europe/Moscow');
340 $date = RT::Date->new( $current_user );
341 $date->Set(Format => 'datemanip', Value => '2005-11-28 15:10:00');
342 is($date->ISO, '2005-11-28 12:10:00', "YYYY-DD-MM hh:mm:ss");
345 { # set+unknown format(Time::ParseDate)
346 my $date = RT::Date->new($RT::SystemUser);
347 $date->Set(Format => 'unknown', Value => 'weird date');
348 is($date->Unix, 0, "date was wrong");
350 RT->Config->Set( Timezone => 'Europe/Moscow' );
351 $date->Set(Format => 'unknown', Value => '2005-11-28 15:10:00');
352 is($date->ISO, '2005-11-28 12:10:00', "YYYY-DD-MM hh:mm:ss");
354 $date->Set(Format => 'unknown', Value => '2005-11-28 15:10:00', Timezone => 'utc' );
355 is($date->ISO, '2005-11-28 15:10:00', "YYYY-DD-MM hh:mm:ss");
357 # test relative dates
359 set_fixed_time("2005-11-28T15:10:00Z");
360 $date->Set(Format => 'unknown', Value => 'now');
361 is($date->ISO, '2005-11-28 15:10:00', "YYYY-DD-MM hh:mm:ss");
363 $date->Set(Format => 'unknown', Value => '1 day ago');
364 is($date->ISO, '2005-11-27 15:10:00', "YYYY-DD-MM hh:mm:ss");
368 RT->Config->Set( Timezone => 'UTC' );
369 $date->Set(Format => 'unknown', Value => '2005-11-28 15:10:00');
370 is($date->ISO, '2005-11-28 15:10:00', "YYYY-DD-MM hh:mm:ss");
372 $current_user->UserObj->__Set( Field => 'Timezone', Value => 'Europe/Moscow');
373 $date = RT::Date->new( $current_user );
374 $date->Set(Format => 'unknown', Value => '2005-11-28 15:10:00');
375 is($date->ISO, '2005-11-28 12:10:00', "YYYY-DD-MM hh:mm:ss");
376 $date->Set(Format => 'unknown', Value => '2005-11-28 15:10:00', Timezone => 'server' );
377 is($date->ISO, '2005-11-28 15:10:00', "YYYY-DD-MM hh:mm:ss");
378 $date->Set(Format => 'unknown', Value => '2005-11-28 15:10:00', Timezone => 'utc' );
379 is($date->ISO, '2005-11-28 15:10:00', "YYYY-DD-MM hh:mm:ss");
383 my $date = RT::Date->new($RT::SystemUser);
385 RT->Config->Set( Timezone => 'Europe/Moscow' );
386 $date->Set(Format => 'ISO', Value => '2005-11-28 15:10:00');
387 $date->SetToMidnight;
388 is($date->ISO, '2005-11-28 00:00:00', "default is utc");
389 $date->Set(Format => 'ISO', Value => '2005-11-28 15:10:00');
390 $date->SetToMidnight(Timezone => 'utc');
391 is($date->ISO, '2005-11-28 00:00:00', "utc context");
392 $date->Set(Format => 'ISO', Value => '2005-11-28 15:10:00');
393 $date->SetToMidnight(Timezone => 'user');
394 is($date->ISO, '2005-11-27 21:00:00', "user context, user has no preference, fallback to server");
395 $date->Set(Format => 'ISO', Value => '2005-11-28 15:10:00');
396 $date->SetToMidnight(Timezone => 'server');
397 is($date->ISO, '2005-11-27 21:00:00', "server context");
399 $current_user->UserObj->__Set( Field => 'Timezone', Value => 'Europe/Moscow');
400 $date = RT::Date->new( $current_user );
401 $date->Set(Format => 'ISO', Value => '2005-11-28 15:10:00');
402 $date->SetToMidnight;
403 is($date->ISO, '2005-11-28 00:00:00', "default is utc");
404 $date->Set(Format => 'ISO', Value => '2005-11-28 15:10:00');
405 $date->SetToMidnight(Timezone => 'utc');
406 is($date->ISO, '2005-11-28 00:00:00', "utc context");
407 $date->Set(Format => 'ISO', Value => '2005-11-28 15:10:00');
408 $date->SetToMidnight(Timezone => 'user');
409 is($date->ISO, '2005-11-27 21:00:00', "user context");
410 $date->SetToMidnight(Timezone => 'server');
411 is($date->ISO, '2005-11-27 21:00:00', "server context");
413 RT->Config->Set( Timezone => 'UTC' );
417 my $date = RT::Date->new($RT::SystemUser);
420 ok($date->Unix >= $time, 'close enough');
421 ok($date->Unix < $time+5, 'difference is less than five seconds');
425 my $date = RT::Date->new($RT::SystemUser);
429 is($date->ISO, '1970-01-01 00:00:00', "nothing changed");
430 $date->AddSeconds(0);
431 is($date->ISO, '1970-01-01 00:00:00', "nothing changed");
434 $date->AddSeconds(5);
435 is($date->ISO, '1970-01-01 00:00:05', "added five seconds");
436 $date->AddSeconds(-2);
437 is($date->ISO, '1970-01-01 00:00:03', "substracted two seconds");
440 $date->AddSeconds(3661);
441 is($date->ISO, '1970-01-01 01:01:01', "added one hour, minute and a second");
443 # XXX: TODO, doesn't work with Test::Warn
445 # local $TODO = "BUG or subject to change Date handling to support unix time <= 0";
447 # $date->AddSeconds(-2);
448 # ok($date->Unix > 0);
453 is($date->ISO, '1970-01-02 00:00:00', "added one day");
455 is($date->ISO, '1970-01-04 00:00:00', "added two days");
457 is($date->ISO, '1970-01-03 00:00:00', "substructed one day");
461 is($date->ISO, '1970-02-01 00:00:00', "added one month");
465 $current_user->UserObj->__Set( Field => 'Timezone', Value => '');
466 my $date = RT::Date->new( $current_user );
467 is($date->AsString, "Not set", "AsString returns 'Not set'");
469 RT->Config->Set( DateTimeFormat => '');
471 is($date->AsString, 'Thu Jan 01 00:00:01 1970', "correct string");
472 is($date->AsString(Date => 0), '00:00:01', "correct string");
473 is($date->AsString(Time => 0), 'Thu Jan 01 1970', "correct string");
474 is($date->AsString(Date => 0, Time => 0), 'Thu Jan 01 00:00:01 1970', "invalid input");
476 RT->Config->Set( DateTimeFormat => 'RFC2822' );
478 is($date->AsString, 'Thu, 1 Jan 1970 00:00:01 +0000', "correct string");
480 RT->Config->Set( DateTimeFormat => { Format => 'RFC2822', Seconds => 0 } );
482 is($date->AsString, 'Thu, 1 Jan 1970 00:00 +0000', "correct string");
483 is($date->AsString(Seconds => 1), 'Thu, 1 Jan 1970 00:00:01 +0000', "correct string");
487 my $date = RT::Date->new($RT::SystemUser);
489 is($date->DurationAsString(1), '1 sec', '1 sec');
490 is($date->DurationAsString(59), '59 sec', '59 sec');
491 is($date->DurationAsString(60), '1 min', '1 min');
492 is($date->DurationAsString(60*119), '119 min', '119 min');
493 is($date->DurationAsString(60*60*2-1), '120 min', '120 min');
494 is($date->DurationAsString(60*60*2), '2 hours', '2 hours');
495 is($date->DurationAsString(60*60*48-1), '48 hours', '48 hours');
496 is($date->DurationAsString(60*60*48), '2 days', '2 days');
497 is($date->DurationAsString(60*60*24*14-1), '14 days', '14 days');
498 is($date->DurationAsString(60*60*24*14), '2 weeks', '2 weeks');
499 is($date->DurationAsString(60*60*24*7*8-1), '8 weeks', '8 weeks');
500 is($date->DurationAsString(60*60*24*61), '2 months', '2 months');
501 is($date->DurationAsString(60*60*24*365-1), '12 months', '12 months');
502 is($date->DurationAsString(60*60*24*366), '1 years', '1 years');
504 is($date->DurationAsString(-1), '1 sec ago', '1 sec ago');
508 my $date = RT::Date->new($RT::SystemUser);
509 is($date->DiffAsString(1), '', 'no diff, wrong input');
510 is($date->DiffAsString(-1), '', 'no diff, wrong input');
511 is($date->DiffAsString('qwe'), '', 'no diff, wrong input');
514 is($date->DiffAsString(-1), '', 'no diff, wrong input');
516 is($date->DiffAsString(3), '1 sec ago', 'diff: 1 sec ago');
517 is($date->DiffAsString(1), '1 sec', 'diff: 1 sec');
519 my $ndate = RT::Date->new($RT::SystemUser);
520 is($date->DiffAsString($ndate), '', 'no diff, wrong input');
522 is($date->DiffAsString($ndate), '1 sec ago', 'diff: 1 sec ago');
526 my $date = RT::Date->new($RT::SystemUser);
528 my $diff = $date->Diff;
529 ok($diff <= 0, 'close enought');
530 ok($diff > -5, 'close enought');
534 my $date = RT::Date->new($RT::SystemUser);
536 my $diff = $date->AgeAsString;
537 like($diff, qr/^(0 sec|[1-5] sec ago)$/, 'close enought');
541 my $date = RT::Date->new($RT::SystemUser);
542 is($date->GetWeekday(7), '', '7 and greater are invalid');
543 is($date->GetWeekday(6), 'Sat', '6 is Saturday');
544 is($date->GetWeekday(0), 'Sun', '0 is Sunday');
545 is($date->GetWeekday(-1), 'Sat', '-1 is Saturday');
546 is($date->GetWeekday(-7), 'Sun', '-7 is Sunday');
547 is($date->GetWeekday(-8), '', '-8 and lesser are invalid');
551 my $date = RT::Date->new($RT::SystemUser);
552 is($date->GetMonth(12), '', '12 and greater are invalid');
553 is($date->GetMonth(11), 'Dec', '11 is December');
554 is($date->GetMonth(0), 'Jan', '0 is January');
555 is($date->GetMonth(-1), 'Dec', '11 is December');
556 is($date->GetMonth(-12), 'Jan', '0 is January');
557 is($date->GetMonth(-13), '', '-13 and lesser are invalid');
561 #TODO: RFC2822, W3CDTF with Timezones