summaryrefslogtreecommitdiff
path: root/t/03-date-handling.t
blob: 5d414c20deea59550052f8876ae11ed664ea123d (plain)
  1. #!/usr/bin/perl
  2. #
  3. # Note: This file assumes good dates, SL behaviour with bad dates is undefined
  4. #
  5. use strict;
  6. use warnings;
  7. use Test::More 'no_plan';
  8. use Math::BigFloat;
  9. use LedgerSMB::Sysconfig;
  10. use LedgerSMB;
  11. use LedgerSMB::Form;
  12. use LedgerSMB::Locale;
  13. my $form = new Form;
  14. my $locale_en = LedgerSMB::Locale->get_handle('en_CA');
  15. my $locale_es = LedgerSMB::Locale->get_handle('es');
  16. my %myconfig;
  17. ok(defined $form);
  18. isa_ok($form, 'Form');
  19. my $lsmb = new LedgerSMB;
  20. ok(defined $lsmb);
  21. isa_ok($lsmb, 'LedgerSMB');
  22. $form->{dbh} = ${LedgerSMB::Sysconfig::GLOBALDBH};
  23. my @formats = ( ['mm-dd-yy', '-', 2, '02-29-00', '03-01-00'],
  24. ['mm/dd/yy', '/', 2, '02/29/00', '03/01/00'],
  25. ['dd-mm-yy', '-', 2, '29-02-00', '01-03-00'],
  26. ['dd/mm/yy', '/', 2, '29/02/00', '01/03/00'],
  27. ['dd.mm.yy', '.', 2, '29.02.00', '01.03.00'],
  28. # ['yyyymmdd', '', 4, '20000229', '20000301'],
  29. ['yyyy-mm-dd', '-', 4, '2000-02-29', '2000-03-01']);
  30. my @months = ('January', 'February', 'March', 'April', 'May ', 'June',
  31. 'July', 'August', 'September', 'October', 'November', 'December');
  32. my @mon = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
  33. 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
  34. my %month_num = ('01' => '31', '02' => '28', '03' => '31', '04' => '30',
  35. '05' => '31', '06' => '30', '07' => '31', '08' => '31',
  36. '09' => '30', '10' => '31', '11' => '30', '12' => '31');
  37. my $today = `date +\%F`;
  38. chomp $today;
  39. my %today_parts;
  40. $today_parts{'yyyy'} = `date +\%Y`;
  41. $today_parts{'yy'} = $today_parts{'yyyy'};
  42. $today_parts{'yy'} =~ s/^..//;
  43. $today_parts{'mm'} = `date +\%m`;
  44. $today_parts{'dd'} = `date +\%d`;
  45. chomp $today_parts{'yyyy'};
  46. chomp $today_parts{'yy'};
  47. chomp $today_parts{'mm'};
  48. chomp $today_parts{'dd'};
  49. # $locale->date checks
  50. # Note that $locale->date assumes the year range 2000-2099
  51. # Note that $locale->date does not perform language-specific long forms
  52. # Note that $locale->date also takes in yyyymmdd
  53. foreach my $format (0 .. $#formats) {
  54. %myconfig = (dateformat => $formats[$format][0]);
  55. my $fmt = $formats[$format][0];
  56. my $sep = $formats[$format][1];
  57. my $yearcount = $formats[$format][2];
  58. my $result = $formats[$format][3];
  59. $result =~ s/^(.*)(20)?00(.*)$/${1}2000${3}/ if $yearcount == 2;
  60. cmp_ok($locale_en->date(\%myconfig), 'eq',
  61. '', "date, $fmt: empty string");
  62. cmp_ok($locale_en->date(\%myconfig, $formats[$format][3]), 'eq',
  63. $result, "date, $fmt: short");
  64. cmp_ok($locale_en->date(\%myconfig, '20000229'), 'eq',
  65. $result, "date, $fmt: chopped");
  66. for my $mm (1 .. 12) {
  67. my $start = $fmt;
  68. my $temp = sprintf('%02d', $mm);
  69. my $month_en = $locale_en->text($months[$mm - 1]);
  70. my $month_en_2 = $locale_en->text($mon[$mm - 1]);
  71. my $month_es = $locale_es->text($months[$mm - 1]);
  72. $start =~ s/dd/29/;
  73. $start =~ s/yyyy/2000/;
  74. $start =~ s/yy/00/;
  75. $start =~ s/mm/$temp/;
  76. cmp_ok($locale_es->date(\%myconfig, $start, 1), 'eq',
  77. "$month_es 29 2000", "date, $start, $fmt: long, es");
  78. cmp_ok($locale_en->date(\%myconfig, $start, 1), 'eq',
  79. "$month_en 29 2000", "date, $start, $fmt: long, en");
  80. cmp_ok($locale_en->date(\%myconfig, $start, ''), 'eq',
  81. "$month_en_2 29 2000", "date, $start, $fmt: '', en") if
  82. $start !~ /^\d{4}\D/; # Ack... special case
  83. }
  84. cmp_ok($locale_en->date(\%myconfig, '2007-05-18', ''), 'eq',
  85. "2007-05-18", "date, 2007-05-18, $fmt: '', en");
  86. }
  87. # $form->current_date checks
  88. # Note that $form->current_date always uses the database
  89. # Note that $form->current_date can take four digit years with all formats
  90. # Note that $form->current_date will always accept a dateformat of 'yyyymmdd'
  91. foreach my $format (0 .. $#formats) {
  92. %myconfig = (dateformat => $formats[$format][0]);
  93. my $fmt = $formats[$format][0];
  94. my $sep = $formats[$format][1];
  95. my $yearcount = $formats[$format][2];
  96. my $tv = $fmt;
  97. $tv =~ s/(yy)?yy/$today_parts{'yyyy'}/;
  98. $tv =~ s/mm/$today_parts{'mm'}/;
  99. $tv =~ s/dd/$today_parts{'dd'}/;
  100. is($form->current_date(\%myconfig),
  101. $today, "current_date, $fmt: $today");
  102. is($form->current_date(\%myconfig, $formats[$format][3]),
  103. '2000-02-29', "current_date, $fmt: 2000-02-29");
  104. is($form->current_date(\%myconfig, $formats[$format][3], 1),
  105. '2000-03-01', "current_date, $fmt: 2000-03-01");
  106. is($form->current_date(\%myconfig, $tv),
  107. $today, "current_date, $fmt: $tv");
  108. $tv = "$today_parts{'yyyy'}$today_parts{'mm'}$today_parts{'dd'}";
  109. is($form->current_date(\%myconfig, $tv),
  110. $today, "current_date, $fmt: $tv");
  111. }
  112. # $form->datetonum checks
  113. # Note that $form->datetonum assumes the year range 2000-2099
  114. # Note that $form->datetonum is identity if there is no date or non-digit
  115. foreach my $format (0 .. $#formats) {
  116. %myconfig = (dateformat => $formats[$format][0]);
  117. my $fmt = $formats[$format][0];
  118. my $sep = $formats[$format][1];
  119. my $yearcount = $formats[$format][2];
  120. cmp_ok($form->datetonum(\%myconfig, $formats[$format][3]), 'eq',
  121. '20000229', "form: datetonum, $fmt");
  122. cmp_ok($lsmb->date_to_number('user' => \%myconfig,
  123. 'date' => $formats[$format][3]), 'eq',
  124. '20000229', "lsmb: date_to_number, $fmt");
  125. }
  126. cmp_ok($form->datetonum(\%myconfig), 'eq', '', "form: datetonum, empty string");
  127. cmp_ok($form->datetonum(\%myconfig, '1234'), 'eq', '1234',
  128. "form: datetonum, 1234");
  129. cmp_ok($lsmb->date_to_number('user' => \%myconfig), 'eq', '',
  130. "lsmb: date_to_number, empty date");
  131. cmp_ok($lsmb->date_to_number('user' => \%myconfig, 'date' => '1234'),
  132. 'eq', '1234', "lsmb: date_to_number, 1234");
  133. # $form->split_date checks
  134. # Note that $form->split_date assumes the year range 2000-2099
  135. # Note that $form->split_date only outputs two digit years
  136. # Note that $form->split_date if a date provided without non-digit, identity
  137. foreach my $format (0 .. $#formats) {
  138. %myconfig = (dateformat => $formats[$format][0]);
  139. my $fmt = $formats[$format][0];
  140. my $sep = $formats[$format][1];
  141. my $yearcount = $formats[$format][2];
  142. my @output = $form->split_date($fmt, $formats[$format][3]);
  143. my $rv = $fmt;
  144. $rv =~ s/\Q$sep\E//g;
  145. $rv =~ s/(yy)?yy/$output[1]/;
  146. $rv =~ s/mm/$output[2]/;
  147. $rv =~ s/dd/$output[3]/;
  148. cmp_ok($output[1], 'eq', '00', "split_date specified, year");
  149. cmp_ok($output[2], 'eq', '02', "split_date specified, month");
  150. cmp_ok($output[3], 'eq', '29', "split_date specified, day");
  151. cmp_ok($output[0], 'eq', $rv, "split_date specified, unit");
  152. @output = $form->split_date($fmt);
  153. $rv = $fmt;
  154. $rv =~ s/\Q$sep\E//g;
  155. $rv =~ s/(yy)?yy/$output[1]/;
  156. $rv =~ s/mm/$output[2]/;
  157. $rv =~ s/dd/$output[3]/;
  158. my $tv = $fmt;
  159. $tv =~ s/\Q$sep\E//g;
  160. $tv =~ s/(yy)?yy/$today_parts{'yy'}/;
  161. $tv =~ s/mm/$today_parts{'mm'}/;
  162. $tv =~ s/dd/$today_parts{'dd'}/;
  163. cmp_ok($output[1], 'eq', $today_parts{'yy'},
  164. "split_date unspecified, year");
  165. cmp_ok($output[2], 'eq', $today_parts{'mm'},
  166. "split_date unspecified, month");
  167. cmp_ok($output[3], 'eq', $today_parts{'dd'},
  168. "split_date unspecified, day");
  169. @output = $form->split_date($fmt, '12345');
  170. cmp_ok($output[0], 'eq', '12345',
  171. 'split_date, 12345');
  172. }
  173. # $form->format_date checks
  174. # Note that $form->format_date always outputs four digit years
  175. foreach my $format (0 .. $#formats) {
  176. $form->{db_dateformat} = $formats[$format][0];
  177. my $fmt = $formats[$format][0];
  178. my $sep = $formats[$format][1];
  179. my $yearcount = $formats[$format][2];
  180. my $results = $fmt;
  181. $results =~ s/(yy)?yy/2000/;
  182. $results =~ s/mm/02/;
  183. $results =~ s/dd/29/;
  184. cmp_ok($form->format_date('2000-02-29'), 'eq',
  185. $results, "format_date, $fmt, ISO");
  186. cmp_ok($form->format_date($formats[$format][3]), 'eq',
  187. $formats[$format][3], "format_date, $fmt, non-ISO");
  188. }
  189. # $form->from_to checks
  190. # Note that $form->from_to requires $form->format_date
  191. # Note that $form->from_to outputs four digit years
  192. # Note that $form->from_to outputs 1999-12-31 (formatted) if no input given
  193. # Note that $form->from_to outputs the last day of the previous year if only year given
  194. # Note that $form->from_to outputs the last day of the chosen month if month given
  195. # Note that $form->from_to $interval of 0 is current day
  196. # Note that $form->from_to $interval is an integral quantity of months
  197. # Note that $form->from_to will fail if ($interval + $month) > 22
  198. # (2 + 23), 25 - 12, 13 - 1, 12
  199. foreach my $format (0 .. $#formats) {
  200. $form->{db_dateformat} = $formats[$format][0];
  201. my $fmt = $formats[$format][0];
  202. my $sep = $formats[$format][1];
  203. my $yearcount = $formats[$format][2];
  204. my $results = $fmt;
  205. $results =~ s/(yy)?yy/1999/;
  206. $results =~ s/mm/12/;
  207. $results =~ s/dd/31/;
  208. cmp_ok($form->from_to(), 'eq',
  209. $results, "from_to, $fmt, unspecified");
  210. $results =~ s/1999/2006/;
  211. cmp_ok($form->from_to('07'), 'eq',
  212. $results, "from_to, $fmt, 07");
  213. cmp_ok($form->from_to('2007'), 'eq',
  214. $results, "from_to, $fmt, 2007");
  215. $results =~ s/2006/2007/;
  216. $results =~ s/12/05/;
  217. cmp_ok($form->from_to('07', '05'), 'eq',
  218. $results, "from_to, $fmt, 07-05");
  219. cmp_ok($form->from_to('2007', '05'), 'eq',
  220. $results, "from_to, $fmt, 2007-05");
  221. $results =~ s/05/02/;
  222. $results =~ s/31/28/;
  223. cmp_ok($form->from_to('07', '02'), 'eq',
  224. $results, "from_to, $fmt, 07-02");
  225. cmp_ok($form->from_to('2007', '02'), 'eq',
  226. $results, "from_to, $fmt, 2007-02");
  227. $results =~ s/2007/2000/;
  228. $results =~ s/28/29/;
  229. cmp_ok($form->from_to('00', '02'), 'eq',
  230. $results, "from_to, $fmt, 00-02 leap day");
  231. cmp_ok($form->from_to('2000', '02'), 'eq',
  232. $results, "from_to, $fmt, 2000-02 leap day");
  233. $results =~ s/29/31/;
  234. $results =~ s/02/01/;
  235. cmp_ok($form->from_to('00', '01'), 'eq',
  236. $results, "from_to, $fmt, 00-01 year edge");
  237. cmp_ok($form->from_to('2000', '01'), 'eq',
  238. $results, "from_to, $fmt, 2000-01 year edge");
  239. $results =~ s/01/12/;
  240. cmp_ok($form->from_to('00', '12'), 'eq',
  241. $results, "from_to, $fmt, 00-12 year edge");
  242. cmp_ok($form->from_to('2000', '12'), 'eq',
  243. $results, "from_to, $fmt, 2000-12 year edge");
  244. $results =~ s/12/02/;
  245. $results =~ s/31/29/;
  246. cmp_ok($form->from_to('00', '02', '1'), 'eq',
  247. $results, "from_to, $fmt, 00-02, 1 interval");
  248. cmp_ok($form->from_to('2000', '02', '1'), 'eq',
  249. $results, "from_to, $fmt, 2000-02, 1 interval");
  250. $results =~ s/29/28/;
  251. my $month;
  252. my $lastmonth;
  253. for (2 .. 11) {
  254. $month = sprintf '%02d', $_ + 1;
  255. $lastmonth = sprintf '%02d', $_;
  256. $results =~ s/$lastmonth/$month/;
  257. $results =~ s/$month_num{$lastmonth}/$month_num{$month}/;
  258. cmp_ok($form->from_to('00', '02', $_), 'eq',
  259. $results, "from_to, $fmt, 00-02, $_ interval");
  260. cmp_ok($form->from_to('2000', '02', $_), 'eq',
  261. $results, "from_to, $fmt, 2000-02, $_ interval");
  262. }
  263. $results =~ s/2000/2001/;
  264. for (0 .. 10) {
  265. $month = sprintf '%02d', $_ + 1;
  266. $lastmonth = sprintf '%02d', $_;
  267. $lastmonth = '12' if $lastmonth eq '00';
  268. $results =~ s/([^0])$lastmonth/${1}$month/;
  269. $results =~ s/^$lastmonth/$month/;
  270. $results =~ s/$month_num{$lastmonth}/$month_num{$month}/;
  271. cmp_ok($form->from_to('00', '02', $_ + 12), 'eq',
  272. $results, "from_to, $fmt, 00-02, $_ + 12 interval");
  273. cmp_ok($form->from_to('2000', '02', $_ + 12), 'eq',
  274. $results, "from_to, $fmt, 2000-02, $_ + 12 interval");
  275. }
  276. $results =~ s/2001/$today_parts{'yyyy'}/;
  277. $results =~ s/11/$today_parts{'mm'}/;
  278. $results =~ s/30/$today_parts{'dd'}/;
  279. cmp_ok($form->from_to('00', '02', '0'), 'eq',
  280. $results, "from_to, $fmt, 00-02, 0 interval (today)");
  281. cmp_ok($form->from_to('2000', '02', '0'), 'eq',
  282. $results, "from_to, $fmt, 2000-02, 0 interval (today)");
  283. }
  284. # $form->add_date checks
  285. # returns undef if no date passed
  286. # valid units: days, weeks, months, years
  287. # all uses in LSMB use days unit
  288. # has no error handling capabilities
  289. foreach my $format (0 .. $#formats) {
  290. $form->{db_dateformat} = $formats[$format][0];
  291. %myconfig = (dateformat => $formats[$format][0]);
  292. my $fmt = $formats[$format][0];
  293. my $sep = $formats[$format][1];
  294. my $yearcount = $formats[$format][2];
  295. my $start = $fmt;
  296. $start =~ s/(yy)?yy/2000/;
  297. $start =~ s/mm/01/;
  298. $start =~ s/dd/29/;
  299. my $results = $start;
  300. $results =~ s/29/30/;
  301. cmp_ok($form->add_date(\%myconfig, $start, 1, 'days'), 'eq',
  302. $results, "add_date, $fmt, 1 days, 2000-01-29");
  303. $results =~ s/30/31/;
  304. cmp_ok($form->add_date(\%myconfig, $start, 2, 'days'), 'eq',
  305. $results, "add_date, $fmt, 2 days, 2000-01-29");
  306. $results =~ s/31/05/;
  307. $results =~ s/01/02/;
  308. cmp_ok($form->add_date(\%myconfig, $start, 1, 'weeks'), 'eq',
  309. $results, "add_date, $fmt, 1 weeks, 2000-01-29");
  310. $results =~ s/05/12/;
  311. cmp_ok($form->add_date(\%myconfig, $start, 2, 'weeks'), 'eq',
  312. $results, "add_date, $fmt, 2 weeks, 2000-01-29");
  313. $results =~ s/12/29/;
  314. cmp_ok($form->add_date(\%myconfig, $start, 1, 'months'), 'eq',
  315. $results, "add_date, $fmt, 1 months, 2000-01-29");
  316. $results =~ s/02/03/;
  317. cmp_ok($form->add_date(\%myconfig, $start, 2, 'months'), 'eq',
  318. $results, "add_date, $fmt, 2 months, 2000-01-29");
  319. $results = $start;
  320. $results =~ s/01/11/;
  321. cmp_ok($form->add_date(\%myconfig, $start, 10, 'months'), 'eq',
  322. $results, "add_date, $fmt, 10 months, 2000-01-29");
  323. $results = $start;
  324. $results =~ s/01/12/;
  325. cmp_ok($form->add_date(\%myconfig, $start, 11, 'months'), 'eq',
  326. $results, "add_date, $fmt, 11 months, 2000-01-29");
  327. $results = $start;
  328. $results =~ s/2000/2001/;
  329. cmp_ok($form->add_date(\%myconfig, $start, 12, 'months'), 'eq',
  330. $results, "add_date, $fmt, 12 months, 2000-01-29");
  331. cmp_ok($form->add_date(\%myconfig, $start, 1, 'years'), 'eq',
  332. $results, "add_date, $fmt, 1 years, 2000-01-29");
  333. $results =~ s/2001/2002/;
  334. cmp_ok($form->add_date(\%myconfig, $start, 2, 'years'), 'eq',
  335. $results, "add_date, $fmt, 2 years, 2000-01-29");
  336. }
  337. cmp_ok($form->add_date(\%myconfig, '20000129', 2, 'years'), 'eq',
  338. '20020129', 'add_date, yyyymmdd, 2 years, 20000129');
  339. ok(!defined $form->add_date(\%myconfig),
  340. 'add_date, undef if no date');