File Coverage

blib/lib/Rose/DB/Object/MakeMethods/Date.pm
Criterion Covered Total %
statement 69 676 10.2
branch 33 694 4.7
condition 19 569 3.3
subroutine 8 23 34.7
pod 6 6 100.0
total 135 1968 6.8


line stmt bran cond sub pod time code
1             package Rose::DB::Object::MakeMethods::Date;
2              
3 4     4   29 use strict;
  4         8  
  4         131  
4              
5 4     4   23 use Carp();
  4         8  
  4         90  
6              
7 4     4   21 use Rose::Object::MakeMethods;
  4         8  
  4         28  
8             our @ISA = qw(Rose::Object::MakeMethods);
9              
10             use Rose::DB::Object::Constants
11 4         323 qw(PRIVATE_PREFIX FLAG_DB_IS_PRIVATE STATE_IN_DB STATE_LOADING
12 4     4   219 STATE_SAVING MODIFIED_COLUMNS MODIFIED_NP_COLUMNS SET_COLUMNS);
  4         8  
13              
14 4     4   25 use Rose::DB::Object::Util qw(column_value_formatted_key);
  4         9  
  4         34935  
15              
16             our $VERSION = '0.787';
17              
18             sub date
19             {
20 7     7 1 545 my($class, $name, $args) = @_;
21              
22 7   66     24 my $key = $args->{'hash_key'} || $name;
23 7   100     20 my $interface = $args->{'interface'} || 'get_set';
24 7   50     23 my $tz = $args->{'time_zone'} || 0;
25              
26 7 100       19 my $column_name = $args->{'column'} ? $args->{'column'}->name : $name;
27              
28 7   50     33 my $undef_overrides_default = $args->{'undef_overrides_default'} || 0;
29              
30 7         20 my $formatted_key = column_value_formatted_key($key);
31 7         17 my $default = $args->{'default'};
32              
33 7 100       16 my $mod_columns_key = ($args->{'column'} ? $args->{'column'}->nonpersistent : 0) ?
    50          
34             MODIFIED_NP_COLUMNS : MODIFIED_COLUMNS;
35              
36 7         30 my %methods;
37              
38 7 100       36 if($interface eq 'get_set')
    100          
    50          
39             {
40             $methods{$name} = sub
41             {
42 0     0   0 my $self = shift;
43              
44 0 0       0 my $db = $self->db or die "Missing Rose::DB object attribute";
45 0   0     0 my $driver = $db->driver || 'unknown';
46              
47 0 0       0 if(@_)
48             {
49 0 0       0 if(@_ == 2)
50             {
51 0   0     0 my $dt = $self->{$key} || $self->{$formatted_key,$driver};
52              
53 0 0 0     0 if(defined $dt && !ref $dt)
54             {
55 0         0 my $dt2 = $db->parse_date($dt);
56              
57 0 0       0 unless($dt2)
58             {
59 0 0 0     0 $dt2 = Rose::DateTime::Util::parse_date($dt, $tz || $db->server_time_zone) or
60             Carp::croak "Could not parse date '$dt'";
61             }
62              
63 0         0 $dt = $dt2;
64             }
65              
66 0 0       0 if($_[0] eq 'format')
    0          
67             {
68 0 0       0 return $dt unless(ref $dt);
69 0 0       0 return Rose::DateTime::Util::format_date($dt, (ref $_[1] ? @{$_[1]} : $_[1]));
  0         0  
70             }
71             elsif($_[0] eq 'truncate')
72             {
73 0 0       0 return undef unless($self->{$key});
74 0 0       0 return $dt unless(ref $dt);
75 0         0 return $dt->clone->truncate(to => $_[1]);
76             }
77             else
78             {
79 0         0 Carp::croak "Invalid argument(s) to $name: @_";
80             }
81             }
82              
83 0 0       0 if(defined $_[0])
84             {
85 0 0       0 if($self->{STATE_LOADING()})
86             {
87 0         0 $self->{$key} = undef;
88 0         0 $self->{$formatted_key,$driver} = $_[0];
89             }
90             else
91             {
92 0         0 my $dt = $db->parse_date($_[0]);
93              
94 0 0       0 unless($dt)
95             {
96 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($_[0], $tz || $db->server_time_zone) or
97             Carp::croak "Invalid date: '$_[0]'";
98             }
99              
100 0 0       0 if(ref $dt)
101             {
102 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
103 0         0 $self->{$key} = $dt;
104 0         0 $self->{$formatted_key,$driver} = undef;
105             }
106             else
107             {
108 0         0 $self->{$key} = undef;
109 0         0 $self->{$formatted_key,$driver} = $dt;
110             }
111              
112 0         0 $self->{$mod_columns_key}{$column_name} = 1;
113             }
114             }
115             else
116             {
117 0         0 $self->{$key} = undef;
118 0         0 $self->{$formatted_key,$driver} = undef;
119             $self->{$mod_columns_key}{$column_name} = 1
120 0 0       0 unless($self->{STATE_LOADING()});
121             }
122             }
123              
124 0 0       0 return unless(defined wantarray);
125              
126 0 0 0     0 unless(!defined $default || defined $self->{$key} || defined $self->{$formatted_key,$driver} ||
      0        
      0        
      0        
      0        
127             ($undef_overrides_default && ($self->{$mod_columns_key}{$column_name} ||
128             ($self->{STATE_IN_DB()} && !($self->{SET_COLUMNS()}{$column_name} || $self->{$mod_columns_key}{$column_name})))))
129             {
130 0         0 my $dt = $db->parse_date($default);
131              
132 0 0       0 unless($dt)
133             {
134 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($default, $tz || $db->server_time_zone) or
135             Carp::croak "Invalid default date: '$default'";
136             }
137              
138 0 0       0 if(ref $dt)
139             {
140 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
141 0         0 $self->{$key} = $dt;
142 0         0 $self->{$formatted_key,$driver} = undef;
143             }
144             else
145             {
146 0         0 $self->{$key} = undef;
147 0         0 $self->{$formatted_key,$driver} = $dt;
148             }
149              
150             $self->{$mod_columns_key}{$column_name} = 1
151 0 0       0 unless($self->{STATE_IN_DB()});
152             }
153              
154 0 0       0 if($self->{STATE_SAVING()})
155             {
156             return ($self->{$key} || $self->{$formatted_key,$driver}) ?
157 0 0 0     0 ($self->{$formatted_key,$driver} ||= $db->format_date($self->{$key})) : undef;
      0        
158             }
159              
160 0 0       0 return $self->{$key} if($self->{$key});
161              
162 0 0       0 if(my $value = $self->{$formatted_key,$driver})
163             {
164 0         0 my $dt = $db->parse_date($value);
165              
166 0 0       0 unless($dt)
167             {
168 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($value, $tz || $db->server_time_zone) or
169             Carp::croak "Invalid date: '$value'";
170             }
171              
172 0 0       0 if(ref $dt)
173             {
174 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
175             }
176              
177 0         0 return $self->{$key} = $dt;
178             }
179              
180 0         0 return undef;
181 5         56 };
182             }
183             elsif($interface eq 'get')
184             {
185             $methods{$name} = sub
186             {
187 0     0   0 my $self = shift;
188              
189 0 0       0 my $db = $self->db or die "Missing Rose::DB object attribute";
190 0   0     0 my $driver = $db->driver || 'unknown';
191              
192 0 0       0 if(@_ == 2)
193             {
194 0   0     0 my $dt = $self->{$key} || $self->{$formatted_key,$driver};
195              
196 0 0 0     0 if(defined $dt && !ref $dt)
197             {
198 0         0 my $dt2 = $db->parse_date($dt);
199              
200 0 0       0 unless($dt2)
201             {
202 0 0 0     0 $dt2 = Rose::DateTime::Util::parse_date($dt, $tz || $db->server_time_zone) or
203             Carp::croak "Could not parse date '$dt'";
204             }
205              
206 0         0 $dt = $dt2;
207             }
208              
209 0 0       0 if($_[0] eq 'format')
    0          
210             {
211 0 0       0 return $dt unless(ref $dt);
212 0 0       0 return Rose::DateTime::Util::format_date($dt, (ref $_[1] ? @{$_[1]} : $_[1]));
  0         0  
213             }
214             elsif($_[0] eq 'truncate')
215             {
216 0 0       0 return undef unless($self->{$key});
217 0 0       0 return $dt unless(ref $dt);
218 0         0 return $dt->clone->truncate(to => $_[1]);
219             }
220             else
221             {
222 0         0 Carp::croak "Invalid argument(s) to $name: @_";
223             }
224             }
225              
226 0 0 0     0 unless(!defined $default || defined $self->{$key} || defined $self->{$formatted_key,$driver} ||
      0        
      0        
      0        
      0        
227             ($undef_overrides_default && ($self->{$mod_columns_key}{$column_name} ||
228             ($self->{STATE_IN_DB()} && !($self->{SET_COLUMNS()}{$column_name} || $self->{$mod_columns_key}{$column_name})))))
229             {
230 0         0 my $dt = $db->parse_date($default);
231              
232 0 0       0 unless($dt)
233             {
234 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($default, $tz || $db->server_time_zone) or
235             Carp::croak "Invalid default date: '$default'";
236             }
237              
238 0 0       0 if(ref $dt)
239             {
240 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
241 0         0 $self->{$key} = $dt;
242 0         0 $self->{$formatted_key,$driver} = undef;
243             }
244             else
245             {
246 0         0 $self->{$key} = undef;
247 0         0 $self->{$formatted_key,$driver} = $dt;
248             }
249              
250             $self->{$mod_columns_key}{$column_name} = 1
251 0 0       0 unless($self->{STATE_IN_DB()});
252             }
253              
254 0 0       0 if($self->{STATE_SAVING()})
255             {
256             return ($self->{$key} || $self->{$formatted_key,$driver}) ?
257 0 0 0     0 ($self->{$formatted_key,$driver} ||= $db->format_date($self->{$key})) : undef;
      0        
258             }
259              
260 0 0       0 return $self->{$key} if($self->{$key});
261              
262 0 0       0 if(my $value = $self->{$formatted_key,$driver})
263             {
264 0         0 my $dt = $db->parse_date($value);
265              
266 0 0       0 unless($dt)
267             {
268 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($value, $tz || $db->server_time_zone) or
269             Carp::croak "Invalid date: '$value'";
270             }
271              
272 0 0       0 if(ref $dt)
273             {
274 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
275             }
276              
277 0         0 return $self->{$key} = $dt;
278             }
279              
280 0         0 return undef;
281 1         5 };
282             }
283             elsif($interface eq 'set')
284             {
285             $methods{$name} = sub
286             {
287 0     0   0 my $self = shift;
288              
289 0 0       0 my $db = $self->db or die "Missing Rose::DB object attribute";
290 0   0     0 my $driver = $db->driver || 'unknown';
291              
292 0 0       0 Carp::croak "Missing argument in call to $name" unless(@_);
293              
294 0 0       0 if(defined $_[0])
295             {
296 0 0       0 if($self->{STATE_LOADING()})
297             {
298 0         0 $self->{$key} = undef;
299 0         0 $self->{$formatted_key,$driver} = $_[0];
300             }
301             else
302             {
303 0         0 my $dt = $db->parse_date($_[0]);
304              
305 0 0       0 unless($dt)
306             {
307 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($_[0], $tz || $db->server_time_zone) or
308             Carp::croak "Invalid date: '$_[0]'";
309             }
310              
311 0 0       0 if(ref $dt)
312             {
313 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
314 0         0 $self->{$key} = $dt;
315 0         0 $self->{$formatted_key,$driver} = undef;
316             }
317             else
318             {
319 0         0 $self->{$key} = undef;
320 0         0 $self->{$formatted_key,$driver} = $dt;
321             }
322              
323 0         0 $self->{$mod_columns_key}{$column_name} = 1;
324             }
325             }
326             else
327             {
328 0         0 $self->{$key} = undef;
329 0         0 $self->{$formatted_key,$driver} = undef;
330             $self->{$mod_columns_key}{$column_name} = 1
331 0 0       0 unless($self->{STATE_LOADING()});
332             }
333              
334 0 0       0 return unless(defined wantarray);
335              
336 0 0 0     0 unless(!defined $default || defined $self->{$key} || defined $self->{$formatted_key,$driver} ||
      0        
      0        
      0        
      0        
337             ($undef_overrides_default && ($self->{$mod_columns_key}{$column_name} ||
338             ($self->{STATE_IN_DB()} && !($self->{SET_COLUMNS()}{$column_name} || $self->{$mod_columns_key}{$column_name})))))
339             {
340 0         0 my $dt = $db->parse_date($default);
341              
342 0 0       0 unless($dt)
343             {
344 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($default, $tz || $db->server_time_zone) or
345             Carp::croak "Invalid default date: '$default'";
346             }
347              
348 0 0       0 if(ref $dt)
349             {
350 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
351 0         0 $self->{$key} = $dt;
352 0         0 $self->{$formatted_key,$driver} = undef;
353             }
354             else
355             {
356 0         0 $self->{$key} = undef;
357 0         0 $self->{$formatted_key,$driver} = $dt;
358             }
359              
360             $self->{$mod_columns_key}{$column_name} = 1
361 0 0       0 unless($self->{STATE_IN_DB()});
362             }
363              
364 0 0       0 if($self->{STATE_SAVING()})
365             {
366             return ($self->{$key} || $self->{$formatted_key,$driver}) ?
367 0 0 0     0 ($self->{$formatted_key,$driver} ||= $db->format_date($self->{$key})) : undef;
      0        
368             }
369              
370 0 0       0 return $self->{$key} if($self->{$key});
371              
372 0 0       0 if(my $value = $self->{$formatted_key,$driver})
373             {
374 0         0 my $dt = $db->parse_date($value);
375              
376 0 0       0 unless($dt)
377             {
378 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($value, $tz || $db->server_time_zone) or
379             Carp::croak "Invalid date: '$value'";
380             }
381              
382 0 0       0 if(ref $dt)
383             {
384 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
385             }
386              
387 0         0 return $self->{$key} = $dt;
388             }
389              
390 0         0 return undef;
391 1         6 };
392             }
393 0         0 else { Carp::croak "Unknown interface: $interface" }
394              
395 7         33 return \%methods;
396             }
397              
398             sub datetime
399             {
400 5     5 1 137 my($class, $name, $args) = @_;
401              
402 5   66     13 my $key = $args->{'hash_key'} || $name;
403 5   100     13 my $interface = $args->{'interface'} || 'get_set';
404 5   50     12 my $type = $args->{'type'} || 'datetime';
405 5   50     11 my $tz = $args->{'time_zone'} || 0;
406              
407 5 100       19 my $column_name = $args->{'column'} ? $args->{'column'}->name : $name;
408              
409 5   50     13 my $undef_overrides_default = $args->{'undef_overrides_default'} || 0;
410              
411 5         9 for($type)
412             {
413             # "datetime year to fraction(5)" -> datetime_year_to_fraction_5
414 5         10 tr/ /_/;
415 5         9 s/\(([1-5])\)$/_$1/;
416             }
417              
418 5         17 my $format_method = "format_$type";
419 5         9 my $parse_method = "parse_$type";
420              
421 5         12 my $formatted_key = column_value_formatted_key($key);
422 5         10 my $default = $args->{'default'};
423              
424 5 100       11 my $mod_columns_key = ($args->{'column'} ? $args->{'column'}->nonpersistent : 0) ?
    50          
425             MODIFIED_NP_COLUMNS : MODIFIED_COLUMNS;
426              
427 5         21 my %methods;
428              
429 5 100       20 if($interface eq 'get_set')
    100          
    50          
430             {
431             $methods{$name} = sub
432             {
433 0     0   0 my $self = shift;
434              
435 0 0       0 my $db = $self->db or die "Missing Rose::DB object attribute";
436 0   0     0 my $driver = $db->driver || 'unknown';
437              
438 0 0       0 if(@_)
439             {
440 0 0       0 if(@_ == 2)
441             {
442 0   0     0 my $dt = $self->{$key} || $self->{$formatted_key,$driver};
443              
444 0 0 0     0 if(defined $dt && !ref $dt)
445             {
446 0         0 my $dt2 = $db->$parse_method($dt);
447              
448 0 0       0 unless($dt2)
449             {
450 0   0     0 $dt2 = Rose::DateTime::Util::parse_date($dt, $tz || $db->server_time_zone);
451 0         0 Carp::croak "Could not parse datetime '$dt'";
452             }
453              
454 0         0 $dt = $dt2;
455             }
456              
457 0 0       0 if($_[0] eq 'format')
    0          
458             {
459 0 0       0 return $dt unless(ref $dt);
460 0 0       0 return Rose::DateTime::Util::format_date($dt, (ref $_[1] ? @{$_[1]} : $_[1]));
  0         0  
461             }
462             elsif($_[0] eq 'truncate')
463             {
464 0 0       0 return undef unless($self->{$key});
465 0 0       0 return $db->$format_method($dt) unless(ref $dt);
466 0         0 return $dt->clone->truncate(to => $_[1]);
467             }
468             else
469             {
470 0         0 Carp::croak "Invalid argument(s) to $name: @_";
471             }
472             }
473              
474 0 0       0 if(defined $_[0])
475             {
476 0 0       0 if($self->{STATE_LOADING()})
477             {
478 0         0 $self->{$key} = undef;
479 0         0 $self->{$formatted_key,$driver} = $_[0];
480             }
481             else
482             {
483 0         0 my $dt = $db->$parse_method($_[0]);
484              
485 0 0       0 unless($dt)
486             {
487 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($_[0], $tz || $db->server_time_zone) or
488             Carp::croak "Invalid datetime: '$_[0]'";
489             }
490              
491 0 0 0     0 $dt->set_time_zone($tz || $db->server_time_zone) if(ref $dt);
492 0         0 $self->{$key} = $dt;
493 0         0 $self->{$formatted_key,$driver} = undef;
494              
495 0         0 $self->{$mod_columns_key}{$column_name} = 1;
496             }
497             }
498             else
499             {
500 0         0 $self->{$key} = undef;
501 0         0 $self->{$formatted_key,$driver} = undef;
502             $self->{$mod_columns_key}{$column_name} = 1
503 0 0       0 unless($self->{STATE_LOADING()});
504             }
505             }
506              
507 0 0       0 return unless(defined wantarray);
508              
509 0 0 0     0 unless(!defined $default || defined $self->{$key} || defined $self->{$formatted_key,$driver} ||
      0        
      0        
      0        
      0        
510             ($undef_overrides_default && ($self->{$mod_columns_key}{$column_name} ||
511             ($self->{STATE_IN_DB()} && !($self->{SET_COLUMNS()}{$column_name} || $self->{$mod_columns_key}{$column_name})))))
512             {
513 0         0 my $dt = $db->$parse_method($default);
514              
515 0 0       0 unless($dt)
516             {
517 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($default, $tz || $db->server_time_zone) or
518             Carp::croak "Invalid default datetime: '$default'";
519             }
520              
521 0 0       0 if(ref $dt)
522             {
523 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
524 0         0 $self->{$key} = $dt;
525 0         0 $self->{$formatted_key,$driver} = undef;
526             }
527             else
528             {
529 0         0 $self->{$key} = undef;
530 0         0 $self->{$formatted_key,$driver} = $dt;
531             }
532              
533             $self->{$mod_columns_key}{$column_name} = 1
534 0 0       0 unless($self->{STATE_IN_DB()});
535             }
536              
537 0 0       0 if($self->{STATE_SAVING()})
538             {
539             return ($self->{$key} || $self->{$formatted_key,$driver}) ?
540 0 0 0     0 ($self->{$formatted_key,$driver} ||= $db->$format_method($self->{$key})) : undef;
      0        
541             }
542              
543 0 0       0 return $self->{$key} if($self->{$key});
544              
545 0 0       0 if(my $value = $self->{$formatted_key,$driver})
546             {
547 0         0 my $dt = $db->$parse_method($value);
548              
549 0 0       0 unless($dt)
550             {
551 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($value, $tz || $db->server_time_zone) or
552             Carp::croak "Invalid datetime: '$value'";
553             }
554              
555 0 0       0 if(ref $dt)
556             {
557 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
558             }
559              
560 0         0 return $self->{$key} = $dt;
561             }
562              
563 0         0 return undef;
564 3         32 };
565             }
566             elsif($interface eq 'get')
567             {
568             $methods{$name} = sub
569             {
570 0     0   0 my $self = shift;
571              
572 0 0       0 my $db = $self->db or die "Missing Rose::DB object attribute";
573 0   0     0 my $driver = $db->driver || 'unknown';
574              
575 0 0       0 if(@_ == 2)
576             {
577 0   0     0 my $dt = $self->{$key} || $self->{$formatted_key,$driver};
578              
579 0 0 0     0 if(defined $dt && !ref $dt)
580             {
581 0         0 my $dt2 = $db->parse_timestamp($dt);
582              
583 0 0       0 unless($dt2)
584             {
585 0 0 0     0 $dt2 = Rose::DateTime::Util::parse_date($dt, $tz || $db->server_time_zone, 1) or
586             Carp::croak "Could not parse datetime '$dt'";
587             }
588              
589 0         0 $dt = $dt2;
590             }
591              
592 0 0       0 if($_[0] eq 'format')
    0          
593             {
594 0 0       0 return $dt unless(ref $dt);
595 0 0       0 return Rose::DateTime::Util::format_date($dt, (ref $_[1] ? @{$_[1]} : $_[1]), 1);
  0         0  
596             }
597             elsif($_[0] eq 'truncate')
598             {
599 0 0       0 return undef unless($self->{$key});
600 0 0       0 return $db->format_timestamp($dt) unless(ref $dt);
601 0         0 return $dt->clone->truncate(to => $_[1]);
602             }
603             else
604             {
605 0         0 Carp::croak "Invalid argument(s) to $name: @_";
606             }
607             }
608              
609 0 0 0     0 unless(!defined $default || defined $self->{$key} || defined $self->{$formatted_key,$driver} ||
      0        
      0        
      0        
      0        
610             ($undef_overrides_default && ($self->{$mod_columns_key}{$column_name} ||
611             ($self->{STATE_IN_DB()} && !($self->{SET_COLUMNS()}{$column_name} || $self->{$mod_columns_key}{$column_name})))))
612             {
613 0         0 my $dt = $db->$parse_method($default);
614              
615 0 0       0 unless($dt)
616             {
617 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($default, $tz || $db->server_time_zone) or
618             Carp::croak "Invalid default datetime: '$default'";
619             }
620              
621 0 0       0 if(ref $dt)
622             {
623 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
624 0         0 $self->{$key} = $dt;
625 0         0 $self->{$formatted_key,$driver} = undef;
626             }
627             else
628             {
629 0         0 $self->{$key} = undef;
630 0         0 $self->{$formatted_key,$driver} = $dt;
631             }
632              
633             $self->{$mod_columns_key}{$column_name} = 1
634 0 0       0 unless($self->{STATE_IN_DB()});
635             }
636              
637 0 0       0 if($self->{STATE_SAVING()})
638             {
639             return ($self->{$key} || $self->{$formatted_key,$driver}) ?
640 0 0 0     0 ($self->{$formatted_key,$driver} ||= $db->$format_method($self->{$key})) : undef;
      0        
641             }
642              
643 0 0       0 return $self->{$key} if($self->{$key});
644              
645 0 0       0 if(my $value = $self->{$formatted_key,$driver})
646             {
647 0         0 my $dt = $db->$parse_method($value);
648              
649 0 0       0 unless($dt)
650             {
651 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($value, $tz || $db->server_time_zone) or
652             Carp::croak "Invalid datetime: '$value'";
653             }
654              
655 0 0       0 if(ref $dt)
656             {
657 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
658             }
659              
660 0         0 return $self->{$key} = $dt;
661             }
662              
663 0         0 return undef;
664 1         6 };
665             }
666             elsif($interface eq 'set')
667             {
668             $methods{$name} = sub
669             {
670 0     0   0 my $self = shift;
671              
672 0 0       0 my $db = $self->db or die "Missing Rose::DB object attribute";
673 0   0     0 my $driver = $db->driver || 'unknown';
674              
675 0 0       0 Carp::croak "Missing argument in call to $name" unless(@_);
676              
677 0 0       0 if(defined $_[0])
678             {
679 0 0       0 if($self->{STATE_LOADING()})
680             {
681 0         0 $self->{$key} = undef;
682 0         0 $self->{$formatted_key,$driver} = $_[0];
683             }
684             else
685             {
686 0         0 my $dt = $db->$parse_method($_[0]);
687              
688 0 0       0 unless($dt)
689             {
690 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($_[0], $tz || $db->server_time_zone) or
691             Carp::croak "Invalid datetime: '$_[0]'";
692             }
693              
694 0 0 0     0 $dt->set_time_zone($tz || $db->server_time_zone) if(ref $dt);
695 0         0 $self->{$key} = $dt;
696 0         0 $self->{$formatted_key,$driver} = undef;
697              
698 0         0 $self->{$mod_columns_key}{$column_name} = 1;
699             }
700             }
701             else
702             {
703 0         0 $self->{$key} = undef;
704 0         0 $self->{$formatted_key,$driver} = undef;
705             $self->{$mod_columns_key}{$column_name} = 1
706 0 0       0 unless($self->{STATE_LOADING()});
707             }
708              
709 0 0       0 return unless(defined wantarray);
710              
711 0 0 0     0 unless(!defined $default || defined $self->{$key} || defined $self->{$formatted_key,$driver} ||
      0        
      0        
      0        
      0        
712             ($undef_overrides_default && ($self->{$mod_columns_key}{$column_name} ||
713             ($self->{STATE_IN_DB()} && !($self->{SET_COLUMNS()}{$column_name} || $self->{$mod_columns_key}{$column_name})))))
714             {
715 0         0 my $dt = $db->$parse_method($default);
716              
717 0 0       0 unless($dt)
718             {
719 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($default, $tz || $db->server_time_zone) or
720             Carp::croak "Invalid default datetime: '$default'";
721             }
722              
723 0 0       0 if(ref $dt)
724             {
725 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
726 0         0 $self->{$key} = $dt;
727 0         0 $self->{$formatted_key,$driver} = undef;
728             }
729             else
730             {
731 0         0 $self->{$key} = undef;
732 0         0 $self->{$formatted_key,$driver} = $dt;
733             }
734              
735             $self->{$mod_columns_key}{$column_name} = 1
736 0 0       0 unless($self->{STATE_IN_DB()});
737             }
738              
739 0 0       0 if($self->{STATE_SAVING()})
740             {
741             return ($self->{$key} || $self->{$formatted_key,$driver}) ?
742 0 0 0     0 ($self->{$formatted_key,$driver} ||= $db->$format_method($self->{$key})) : undef;
      0        
743             }
744              
745 0 0       0 return $self->{$key} if($self->{$key});
746              
747 0 0       0 if(my $value = $self->{$formatted_key,$driver})
748             {
749 0         0 my $dt = $db->$parse_method($value);
750              
751 0 0       0 unless($dt)
752             {
753 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($value, $tz || $db->server_time_zone) or
754             Carp::croak "Invalid datetime: '$value'";
755             }
756              
757 0 0       0 if(ref $dt)
758             {
759 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
760             }
761              
762 0         0 return $self->{$key} = $dt;
763             }
764              
765 0         0 return undef;
766 1         16 };
767             }
768 0         0 else { Carp::croak "Unknown interface: $interface" }
769              
770 5         16 return \%methods;
771             }
772              
773             sub timestamp_without_time_zone
774             {
775 0     0 1 0 my($class, $name, $args) = @_;
776              
777 0 0       0 if(exists $args->{'time_zone'})
778             {
779 0         0 Carp::croak "time_zone parameter is invalid for timestamp_without_time_zone methods";
780             }
781              
782 0         0 $args->{'time_zone'} = 'floating';
783              
784 0         0 return $class->timestamp($name, $args);
785             }
786              
787             sub timestamp
788             {
789 7     7 1 305 my($class, $name, $args) = @_;
790              
791 7   66     22 my $key = $args->{'hash_key'} || $name;
792 7   100     29 my $interface = $args->{'interface'} || 'get_set';
793 7   50     47 my $tz = $args->{'time_zone'} || 0;
794              
795 7 100       22 my $column_name = $args->{'column'} ? $args->{'column'}->name : $name;
796              
797 7   50     23 my $undef_overrides_default = $args->{'undef_overrides_default'} || 0;
798              
799 7         18 my $formatted_key = column_value_formatted_key($key);
800 7         13 my $default = $args->{'default'};
801              
802 7 100       14 my $mod_columns_key = ($args->{'column'} ? $args->{'column'}->nonpersistent : 0) ?
    50          
803             MODIFIED_NP_COLUMNS : MODIFIED_COLUMNS;
804              
805 7 50       43 my $with_time_zone = $args->{'_with_time_zone'} ? 1 : 0;
806              
807 7 50       19 my $parse_method = 'parse_timestamp' . ($with_time_zone ? '_with_time_zone' : '');
808 7 50       18 my $format_method = 'format_timestamp' . ($with_time_zone ? '_with_time_zone' : '');
809              
810 7         11 my %methods;
811              
812 7 100       18 if($interface eq 'get_set')
    100          
    50          
813             {
814             $methods{$name} = sub
815             {
816 0     0   0 my $self = shift;
817              
818 0 0       0 my $db = $self->db or die "Missing Rose::DB object attribute";
819 0   0     0 my $driver = $db->driver || 'unknown';
820              
821 0 0       0 if(@_)
822             {
823 0 0       0 if(@_ == 2)
824             {
825 0   0     0 my $dt = $self->{$key} || $self->{$formatted_key,$driver};
826              
827 0 0 0     0 if(defined $dt && !ref $dt)
828             {
829 0         0 my $dt2 = $db->$parse_method($dt);
830              
831 0 0       0 unless($dt2)
832             {
833 0 0 0     0 $dt2 = Rose::DateTime::Util::parse_date($dt, $tz || $db->server_time_zone, 1) or
834             Carp::croak "Could not parse timestamp '$dt'";
835             }
836              
837 0         0 $dt = $dt2;
838             }
839              
840 0 0       0 if($_[0] eq 'format')
    0          
841             {
842 0 0       0 return $dt unless(ref $dt);
843 0 0       0 return Rose::DateTime::Util::format_date($dt, (ref $_[1] ? @{$_[1]} : $_[1]), 1);
  0         0  
844             }
845             elsif($_[0] eq 'truncate')
846             {
847 0 0       0 return undef unless($self->{$key});
848 0 0       0 return $db->$format_method($dt) unless(ref $dt);
849 0         0 return $dt->clone->truncate(to => $_[1]);
850             }
851             else
852             {
853 0         0 Carp::croak "Invalid argument(s) to $name: @_";
854             }
855             }
856              
857 0 0       0 if(defined $_[0])
858             {
859 0 0       0 if($self->{STATE_LOADING()})
860             {
861 0         0 $self->{$key} = undef;
862 0         0 $self->{$formatted_key,$driver} = $_[0];
863             }
864             else
865             {
866 0         0 my $dt = $db->$parse_method($_[0]);
867              
868 0 0       0 unless($dt)
869             {
870 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($_[0], $tz || $db->server_time_zone, 1) or
871             Carp::croak "Invalid timestamp: '$_[0]'";
872             }
873              
874 0 0       0 if(ref $dt)
875             {
876 0 0       0 if($with_time_zone)
877             {
878 0 0       0 $dt->set_time_zone($tz) if($tz);
879             }
880             else
881             {
882 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
883             }
884             }
885              
886 0         0 $self->{$key} = $dt;
887 0         0 $self->{$formatted_key,$driver} = undef;
888              
889 0         0 $self->{$mod_columns_key}{$column_name} = 1;
890             }
891             }
892             else
893             {
894 0         0 $self->{$key} = undef;
895 0         0 $self->{$formatted_key,$driver} = undef;
896             $self->{$mod_columns_key}{$column_name} = 1
897 0 0       0 unless($self->{STATE_LOADING()});
898             }
899             }
900              
901 0 0       0 return unless(defined wantarray);
902              
903 0 0 0     0 unless(!defined $default || defined $self->{$key} || defined $self->{$formatted_key,$driver} ||
      0        
      0        
      0        
      0        
904             ($undef_overrides_default && ($self->{$mod_columns_key}{$column_name} ||
905             ($self->{STATE_IN_DB()} && !($self->{SET_COLUMNS()}{$column_name} || $self->{$mod_columns_key}{$column_name})))))
906             {
907 0         0 my $dt = $db->$parse_method($default);
908              
909 0 0       0 unless($dt)
910             {
911 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($default, $tz || $db->server_time_zone, 1) or
912             Carp::croak "Invalid default timestamp: '$default'";
913             }
914              
915 0 0       0 if(ref $dt)
916             {
917 0 0       0 if($with_time_zone)
918             {
919 0 0       0 $dt->set_time_zone($tz) if($tz);
920             }
921             else
922             {
923 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
924             }
925              
926 0         0 $self->{$key} = $dt;
927 0         0 $self->{$formatted_key,$driver} = undef;
928             }
929             else
930             {
931 0         0 $self->{$key} = undef;
932 0         0 $self->{$formatted_key,$driver} = $dt;
933             }
934              
935             $self->{$mod_columns_key}{$column_name} = 1
936 0 0       0 unless($self->{STATE_IN_DB()});
937             }
938              
939 0 0       0 if($self->{STATE_SAVING()})
940             {
941             return ($self->{$key} || $self->{$formatted_key,$driver}) ?
942 0 0 0     0 ($self->{$formatted_key,$driver} ||= $db->$format_method($self->{$key})) : undef;
      0        
943             }
944              
945 0 0       0 return $self->{$key} if($self->{$key});
946              
947 0 0       0 if(my $value = $self->{$formatted_key,$driver})
948             {
949 0         0 my $dt = $db->$parse_method($value);
950              
951 0 0       0 unless($dt)
952             {
953 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($value, $tz || $db->server_time_zone) or
954             Carp::croak "Invalid timestamp: '$value'";
955             }
956              
957 0 0       0 if(ref $dt)
958             {
959 0 0       0 if($with_time_zone)
960             {
961 0 0       0 $dt->set_time_zone($tz) if($tz);
962             }
963             else
964             {
965 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
966             }
967             }
968              
969 0         0 return $self->{$key} = $dt;
970             }
971              
972 0         0 return undef;
973 5         59 };
974             }
975             elsif($interface eq 'get')
976             {
977             $methods{$name} = sub
978             {
979 0     0   0 my $self = shift;
980              
981 0 0       0 my $db = $self->db or die "Missing Rose::DB object attribute";
982 0   0     0 my $driver = $db->driver || 'unknown';
983              
984 0 0       0 if(@_ == 2)
985             {
986 0   0     0 my $dt = $self->{$key} || $self->{$formatted_key,$driver};
987              
988 0 0 0     0 if(defined $dt && !ref $dt)
989             {
990 0         0 my $dt2 = $db->$parse_method($dt);
991              
992 0 0       0 unless($dt2)
993             {
994 0 0 0     0 $dt2 = Rose::DateTime::Util::parse_date($dt, $tz || $db->server_time_zone, 1) or
995             Carp::croak "Could not parse timestamp '$dt'";
996             }
997              
998 0         0 $dt = $dt2;
999             }
1000              
1001 0 0       0 if($_[0] eq 'format')
    0          
1002             {
1003 0 0       0 return $dt unless(ref $dt);
1004 0 0       0 return Rose::DateTime::Util::format_date($dt, (ref $_[1] ? @{$_[1]} : $_[1]), 1);
  0         0  
1005             }
1006             elsif($_[0] eq 'truncate')
1007             {
1008 0 0       0 return undef unless($self->{$key});
1009 0 0       0 return $db->$format_method($dt) unless(ref $dt);
1010 0         0 return $dt->clone->truncate(to => $_[1]);
1011             }
1012             else
1013             {
1014 0         0 Carp::croak "Invalid argument(s) to $name: @_";
1015             }
1016             }
1017              
1018 0 0       0 return unless(defined wantarray);
1019              
1020 0 0 0     0 unless(!defined $default || defined $self->{$key} || defined $self->{$formatted_key,$driver} ||
      0        
      0        
      0        
      0        
1021             ($undef_overrides_default && ($self->{$mod_columns_key}{$column_name} ||
1022             ($self->{STATE_IN_DB()} && !($self->{SET_COLUMNS()}{$column_name} || $self->{$mod_columns_key}{$column_name})))))
1023             {
1024 0         0 my $dt = $db->$parse_method($default);
1025              
1026 0 0       0 unless($dt)
1027             {
1028 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($default, $tz || $db->server_time_zone, 1) or
1029             Carp::croak "Invalid default timestamp: '$default'";
1030             }
1031              
1032 0 0       0 if(ref $dt)
1033             {
1034 0 0       0 if($with_time_zone)
1035             {
1036 0 0       0 $dt->set_time_zone($tz) if($tz);
1037             }
1038             else
1039             {
1040 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
1041             }
1042              
1043 0         0 $self->{$key} = $dt;
1044 0         0 $self->{$formatted_key,$driver} = undef;
1045             }
1046             else
1047             {
1048 0         0 $self->{$key} = undef;
1049 0         0 $self->{$formatted_key,$driver} = $dt;
1050             }
1051              
1052             $self->{$mod_columns_key}{$column_name} = 1
1053 0 0       0 unless($self->{STATE_IN_DB()});
1054             }
1055              
1056 0 0       0 if($self->{STATE_SAVING()})
1057             {
1058             return ($self->{$key} || $self->{$formatted_key,$driver}) ?
1059 0 0 0     0 ($self->{$formatted_key,$driver} ||= $db->$format_method($self->{$key})) : undef;
      0        
1060             }
1061              
1062 0 0       0 return $self->{$key} if($self->{$key});
1063              
1064 0 0       0 if(my $value = $self->{$formatted_key,$driver})
1065             {
1066 0         0 my $dt = $db->$parse_method($value);
1067              
1068 0 0       0 unless($dt)
1069             {
1070 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($value, $tz || $db->server_time_zone) or
1071             Carp::croak "Invalid timestamp: '$value'";
1072             }
1073              
1074 0 0       0 if(ref $dt)
1075             {
1076 0 0       0 if($with_time_zone)
1077             {
1078 0 0       0 $dt->set_time_zone($tz) if($tz);
1079             }
1080             else
1081             {
1082 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
1083             }
1084             }
1085              
1086 0         0 return $self->{$key} = $dt;
1087             }
1088              
1089 0         0 return undef;
1090 1         13 };
1091             }
1092             elsif($interface eq 'set')
1093             {
1094             $methods{$name} = sub
1095             {
1096 0     0   0 my $self = shift;
1097              
1098 0 0       0 my $db = $self->db or die "Missing Rose::DB object attribute";
1099 0   0     0 my $driver = $db->driver || 'unknown';
1100              
1101 0 0       0 Carp::croak "Missing argument in call to $name" unless(@_);
1102              
1103 0 0       0 if(defined $_[0])
1104             {
1105 0 0       0 if($self->{STATE_LOADING()})
1106             {
1107 0         0 $self->{$key} = undef;
1108 0         0 $self->{$formatted_key,$driver} = $_[0];
1109             }
1110             else
1111             {
1112 0         0 my $dt = $db->$parse_method($_[0]);
1113              
1114 0 0       0 unless($dt)
1115             {
1116 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($_[0], $tz || $db->server_time_zone, 1) or
1117             Carp::croak "Invalid timestamp: '$_[0]'";
1118             }
1119              
1120 0 0       0 if(ref $dt)
1121             {
1122 0 0       0 if($with_time_zone)
1123             {
1124 0 0       0 $dt->set_time_zone($tz) if($tz);
1125             }
1126             else
1127             {
1128 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
1129             }
1130             }
1131              
1132 0         0 $self->{$key} = $dt;
1133 0         0 $self->{$formatted_key,$driver} = undef;
1134              
1135 0         0 $self->{$mod_columns_key}{$column_name} = 1;
1136             }
1137             }
1138             else
1139             {
1140 0         0 $self->{$key} = undef;
1141 0         0 $self->{$formatted_key,$driver} = undef;
1142             $self->{$mod_columns_key}{$column_name} = 1
1143 0 0       0 unless($self->{STATE_LOADING()});
1144             }
1145              
1146 0 0       0 return unless(defined wantarray);
1147              
1148 0 0 0     0 unless(!defined $default || defined $self->{$key} || defined $self->{$formatted_key,$driver} ||
      0        
      0        
      0        
      0        
1149             ($undef_overrides_default && ($self->{$mod_columns_key}{$column_name} ||
1150             ($self->{STATE_IN_DB()} && !($self->{SET_COLUMNS()}{$column_name} || $self->{$mod_columns_key}{$column_name})))))
1151             {
1152 0         0 my $dt = $db->$parse_method($default);
1153              
1154 0 0       0 unless($dt)
1155             {
1156 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($default, $tz || $db->server_time_zone, 1) or
1157             Carp::croak "Invalid default timestamp: '$default'";
1158             }
1159              
1160 0 0       0 if(ref $dt)
1161             {
1162 0 0       0 if($with_time_zone)
1163             {
1164 0 0       0 $dt->set_time_zone($tz) if($tz);
1165             }
1166             else
1167             {
1168 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
1169             }
1170              
1171 0         0 $self->{$key} = $dt;
1172 0         0 $self->{$formatted_key,$driver} = undef;
1173             }
1174             else
1175             {
1176 0         0 $self->{$key} = undef;
1177 0         0 $self->{$formatted_key,$driver} = $dt;
1178             }
1179              
1180             $self->{$mod_columns_key}{$column_name} = 1
1181 0 0       0 unless($self->{STATE_IN_DB()});
1182             }
1183              
1184 0 0       0 if($self->{STATE_SAVING()})
1185             {
1186             return ($self->{$key} || $self->{$formatted_key,$driver}) ?
1187 0 0 0     0 ($self->{$formatted_key,$driver} ||= $db->$format_method($self->{$key})) : undef;
      0        
1188             }
1189              
1190 0 0       0 return $self->{$key} if($self->{$key});
1191              
1192 0 0       0 if(my $value = $self->{$formatted_key,$driver})
1193             {
1194 0         0 my $dt = $db->$parse_method($value);
1195              
1196 0 0       0 unless($dt)
1197             {
1198 0 0 0     0 $dt = Rose::DateTime::Util::parse_date($value, $tz || $db->server_time_zone) or
1199             Carp::croak "Invalid timestamp: '$value'";
1200             }
1201              
1202 0 0       0 if(ref $dt)
1203             {
1204 0 0       0 if($with_time_zone)
1205             {
1206 0 0       0 $dt->set_time_zone($tz) if($tz);
1207             }
1208             else
1209             {
1210 0   0     0 $dt->set_time_zone($tz || $db->server_time_zone);
1211             }
1212             }
1213              
1214 0         0 return $self->{$key} = $dt;
1215             }
1216              
1217 0         0 return undef;
1218 1         5 };
1219             }
1220 0         0 else { Carp::croak "Unknown interface: $interface" }
1221              
1222 7         26 return \%methods;
1223             }
1224              
1225             sub timestamp_with_time_zone
1226             {
1227 0     0 1   my($class, $name, $args) = @_;
1228 0           $args->{'_with_time_zone'} = 1;
1229 0           return shift->timestamp(@_);
1230             }
1231              
1232             sub epoch
1233             {
1234 0     0 1   my($class, $name, $args) = @_;
1235              
1236 0   0       my $key = $args->{'hash_key'} || $name;
1237 0   0       my $interface = $args->{'interface'} || 'get_set';
1238 0   0       my $tz = $args->{'time_zone'} || 0;
1239 0 0         my $epoch_method = $args->{'hires'} ? 'hires_epoch' : 'epoch';
1240              
1241 0 0         my $column_name = $args->{'column'} ? $args->{'column'}->name : $name;
1242              
1243 0   0       my $undef_overrides_default = $args->{'undef_overrides_default'} || 0;
1244              
1245 0           my $formatted_key = column_value_formatted_key($key);
1246 0           my $default = $args->{'default'};
1247              
1248 0 0         my $mod_columns_key = ($args->{'column'} ? $args->{'column'}->nonpersistent : 0) ?
    0          
1249             MODIFIED_NP_COLUMNS : MODIFIED_COLUMNS;
1250              
1251 0           my %methods;
1252              
1253 0 0         if($interface eq 'get_set')
    0          
    0          
1254             {
1255             $methods{$name} = sub
1256             {
1257 0     0     my $self = shift;
1258              
1259 0 0         my $db = $self->db or die "Missing Rose::DB object attribute";
1260 0   0       my $driver = $db->driver || 'unknown';
1261              
1262 0 0         if(@_)
1263             {
1264 0 0         if(@_ == 2)
1265             {
1266 0   0       my $dt = $self->{$key} || $self->{$formatted_key,$driver};
1267              
1268 0 0 0       if(defined $dt && !ref $dt)
1269             {
1270 0           my $dt2 = $db->parse_date($dt);
1271              
1272 0 0         unless($dt2)
1273             {
1274 0 0 0       $dt2 = Rose::DateTime::Util::parse_epoch($dt, $tz || $db->server_time_zone) or
1275             Carp::croak "Could not parse date '$dt'";
1276             }
1277              
1278 0           $dt = $dt2;
1279             }
1280              
1281 0 0         if($_[0] eq 'format')
    0          
1282             {
1283 0 0         return $dt unless(ref $dt);
1284 0 0         return Rose::DateTime::Util::format_date($dt, (ref $_[1] ? @{$_[1]} : $_[1]));
  0            
1285             }
1286             elsif($_[0] eq 'truncate')
1287             {
1288 0 0         return undef unless($self->{$key});
1289 0 0         return $dt unless(ref $dt);
1290 0           return $dt->clone->truncate(to => $_[1]);
1291             }
1292             else
1293             {
1294 0           Carp::croak "Invalid argument(s) to $name: @_";
1295             }
1296             }
1297              
1298 0 0         if(defined $_[0])
1299             {
1300 0 0         if($self->{STATE_LOADING()})
1301             {
1302 0           $self->{$key} = undef;
1303 0           $self->{$formatted_key,$driver} = $_[0];
1304             }
1305             else
1306             {
1307 0           my $dt = $db->parse_date($_[0]);
1308              
1309 0 0         unless($dt)
1310             {
1311 0 0 0       $dt = Rose::DateTime::Util::parse_epoch($_[0], $tz || $db->server_time_zone) or
1312             Carp::croak "Invalid date: '$_[0]'";
1313             }
1314              
1315 0 0         if(ref $dt)
1316             {
1317 0   0       $dt->set_time_zone($tz || $db->server_time_zone);
1318 0           $self->{$key} = $dt;
1319 0           $self->{$formatted_key,$driver} = undef;
1320             }
1321             else
1322             {
1323 0           $self->{$key} = undef;
1324 0           $self->{$formatted_key,$driver} = $dt;
1325             }
1326              
1327 0           $self->{$mod_columns_key}{$column_name} = 1;
1328             }
1329             }
1330             else
1331             {
1332 0           $self->{$key} = undef;
1333 0           $self->{$formatted_key,$driver} = undef;
1334             $self->{$mod_columns_key}{$column_name} = 1
1335 0 0         unless($self->{STATE_LOADING()});
1336             }
1337             }
1338              
1339 0 0         return unless(defined wantarray);
1340              
1341 0 0 0       unless(!defined $default || defined $self->{$key} || defined $self->{$formatted_key,$driver} ||
      0        
      0        
      0        
      0        
1342             ($undef_overrides_default && ($self->{$mod_columns_key}{$column_name} ||
1343             ($self->{STATE_IN_DB()} && !($self->{SET_COLUMNS()}{$column_name} || $self->{$mod_columns_key}{$column_name})))))
1344             {
1345 0           my $dt = $db->parse_date($default);
1346              
1347 0 0         unless($dt)
1348             {
1349 0 0 0       $dt = Rose::DateTime::Util::parse_epoch($default, $tz || $db->server_time_zone) or
1350             Carp::croak "Invalid default epoch: '$default'";
1351             }
1352              
1353 0 0         if(ref $dt)
1354             {
1355 0   0       $dt->set_time_zone($tz || $db->server_time_zone);
1356 0           $self->{$key} = $dt;
1357 0           $self->{$formatted_key,$driver} = undef;
1358             }
1359             else
1360             {
1361 0           $self->{$key} = undef;
1362 0           $self->{$formatted_key,$driver} = $dt;
1363             }
1364              
1365             $self->{$mod_columns_key}{$column_name} = 1
1366 0 0         unless($self->{STATE_IN_DB()});
1367             }
1368              
1369 0 0         if($self->{STATE_SAVING()})
1370             {
1371             return ($self->{$key} || defined $self->{$formatted_key,$driver}) ?
1372             (defined $self->{$formatted_key,$driver} ?
1373             $self->{$formatted_key,$driver} :
1374 0 0 0       ($self->{$formatted_key,$driver} = $self->{$key}->$epoch_method())) : undef;
    0          
1375             }
1376              
1377 0 0         return $self->{$key} if($self->{$key});
1378              
1379 0 0         if(defined(my $value = $self->{$formatted_key,$driver}))
1380             {
1381 0           my $dt = $db->parse_date($value);
1382              
1383 0 0         unless($dt)
1384             {
1385 0 0 0       $dt = Rose::DateTime::Util::parse_epoch($value, $tz || $db->server_time_zone) or
1386             Carp::croak "Invalid epoch: '$value'";
1387             }
1388              
1389 0 0         if(ref $dt)
1390             {
1391 0   0       $dt->set_time_zone($tz || $db->server_time_zone);
1392             }
1393              
1394 0           return $self->{$key} = $dt;
1395             }
1396              
1397 0           return undef;
1398 0           };
1399             }
1400             elsif($interface eq 'get')
1401             {
1402             $methods{$name} = sub
1403             {
1404 0     0     my $self = shift;
1405              
1406 0 0         my $db = $self->db or die "Missing Rose::DB object attribute";
1407 0   0       my $driver = $db->driver || 'unknown';
1408              
1409 0 0         if(@_ == 2)
1410             {
1411 0   0       my $dt = $self->{$key} || $self->{$formatted_key,$driver};
1412              
1413 0 0 0       if(defined $dt && !ref $dt)
1414             {
1415 0           my $dt2 = $db->parse_date($dt);
1416              
1417 0 0         unless($dt2)
1418             {
1419 0 0 0       $dt2 = Rose::DateTime::Util::parse_epoch($dt, $tz || $db->server_time_zone) or
1420             Carp::croak "Could not parse date '$dt'";
1421             }
1422              
1423 0           $dt = $dt2;
1424             }
1425              
1426 0 0         if($_[0] eq 'format')
    0          
1427             {
1428 0 0         return $dt unless(ref $dt);
1429 0 0         return Rose::DateTime::Util::format_date($dt, (ref $_[1] ? @{$_[1]} : $_[1]));
  0            
1430             }
1431             elsif($_[0] eq 'truncate')
1432             {
1433 0 0         return undef unless($self->{$key});
1434 0 0         return $dt unless(ref $dt);
1435 0           return $dt->clone->truncate(to => $_[1]);
1436             }
1437             else
1438             {
1439 0           Carp::croak "Invalid argument(s) to $name: @_";
1440             }
1441             }
1442              
1443 0 0         return unless(defined wantarray);
1444              
1445 0 0 0       unless(!defined $default || defined $self->{$key} || defined $self->{$formatted_key,$driver} ||
      0        
      0        
      0        
      0        
1446             ($undef_overrides_default && ($self->{$mod_columns_key}{$column_name} ||
1447             ($self->{STATE_IN_DB()} && !($self->{SET_COLUMNS()}{$column_name} || $self->{$mod_columns_key}{$column_name})))))
1448             {
1449 0           my $dt = $db->parse_date($default);
1450              
1451 0 0         unless($dt)
1452             {
1453 0 0 0       $dt = Rose::DateTime::Util::parse_epoch($default, $tz || $db->server_time_zone) or
1454             Carp::croak "Invalid default epoch: '$default'";
1455             }
1456              
1457 0 0         if(ref $dt)
1458             {
1459 0   0       $dt->set_time_zone($tz || $db->server_time_zone);
1460 0           $self->{$key} = $dt;
1461 0           $self->{$formatted_key,$driver} = undef;
1462             }
1463             else
1464             {
1465 0           $self->{$key} = undef;
1466 0           $self->{$formatted_key,$driver} = $dt;
1467             }
1468              
1469             $self->{$mod_columns_key}{$column_name} = 1
1470 0 0         unless($self->{STATE_IN_DB()});
1471             }
1472              
1473 0 0         if($self->{STATE_SAVING()})
1474             {
1475             return ($self->{$key} || defined $self->{$formatted_key,$driver}) ?
1476             (defined $self->{$formatted_key,$driver} ?
1477             $self->{$formatted_key,$driver} :
1478 0 0 0       ($self->{$formatted_key,$driver} = $self->{$key}->$epoch_method())) : undef;
    0          
1479             }
1480              
1481 0 0         return $self->{$key} if($self->{$key});
1482              
1483 0 0         if(defined(my $value = $self->{$formatted_key,$driver}))
1484             {
1485 0           my $dt = $db->parse_date($value);
1486              
1487 0 0         unless($dt)
1488             {
1489 0 0 0       $dt = Rose::DateTime::Util::parse_epoch($value, $tz || $db->server_time_zone) or
1490             Carp::croak "Invalid epoch: '$value'";
1491             }
1492              
1493 0 0         if(ref $dt)
1494             {
1495 0   0       $dt->set_time_zone($tz || $db->server_time_zone);
1496             }
1497              
1498 0           return $self->{$key} = $dt;
1499             }
1500              
1501 0           return undef;
1502 0           };
1503             }
1504             elsif($interface eq 'set')
1505             {
1506             $methods{$name} = sub
1507             {
1508 0     0     my $self = shift;
1509              
1510 0 0         my $db = $self->db or die "Missing Rose::DB object attribute";
1511 0   0       my $driver = $db->driver || 'unknown';
1512              
1513 0 0         Carp::croak "Missing argument in call to $name" unless(@_);
1514              
1515 0 0         if(defined $_[0])
1516             {
1517 0 0         if($self->{STATE_LOADING()})
1518             {
1519 0           $self->{$key} = undef;
1520 0           $self->{$formatted_key,$driver} = $_[0];
1521             }
1522             else
1523             {
1524 0           my $dt = $db->parse_date($_[0]);
1525              
1526 0 0         unless($dt)
1527             {
1528 0 0 0       $dt = Rose::DateTime::Util::parse_epoch($_[0], $tz || $db->server_time_zone) or
1529             Carp::croak "Invalid date: '$_[0]'";
1530             }
1531              
1532 0 0         if(ref $dt)
1533             {
1534 0   0       $dt->set_time_zone($tz || $db->server_time_zone);
1535 0           $self->{$key} = $dt;
1536 0           $self->{$formatted_key,$driver} = undef;
1537             }
1538             else
1539             {
1540 0           $self->{$key} = undef;
1541 0           $self->{$formatted_key,$driver} = $dt;
1542             }
1543             }
1544             }
1545             else
1546             {
1547 0           $self->{$key} = undef;
1548 0           $self->{$formatted_key,$driver} = undef;
1549             }
1550              
1551 0           $self->{$mod_columns_key}{$column_name} = 1;
1552              
1553 0 0         return unless(defined wantarray);
1554              
1555 0 0 0       unless(!defined $default || defined $self->{$key} || defined $self->{$formatted_key,$driver} ||
      0        
      0        
      0        
      0        
1556             ($undef_overrides_default && ($self->{$mod_columns_key}{$column_name} ||
1557             ($self->{STATE_IN_DB()} && !($self->{SET_COLUMNS()}{$column_name} || $self->{$mod_columns_key}{$column_name})))))
1558             {
1559 0           my $dt = $db->parse_date($default);
1560              
1561 0 0         unless($dt)
1562             {
1563 0 0 0       $dt = Rose::DateTime::Util::parse_epoch($default, $tz || $db->server_time_zone) or
1564             Carp::croak "Invalid default epoch: '$default'";
1565             }
1566              
1567 0 0         if(ref $dt)
1568             {
1569 0   0       $dt->set_time_zone($tz || $db->server_time_zone);
1570 0           $self->{$key} = $dt;
1571 0           $self->{$formatted_key,$driver} = undef;
1572             }
1573             else
1574             {
1575 0           $self->{$key} = undef;
1576 0           $self->{$formatted_key,$driver} = $dt;
1577             }
1578             }
1579              
1580 0 0         if($self->{STATE_SAVING()})
1581             {
1582             return ($self->{$key} || defined $self->{$formatted_key,$driver}) ?
1583             (defined $self->{$formatted_key,$driver} ?
1584             $self->{$formatted_key,$driver} :
1585 0 0 0       ($self->{$formatted_key,$driver} = $self->{$key}->$epoch_method())) : undef;
    0          
1586             }
1587              
1588 0 0         return $self->{$key} if($self->{$key});
1589              
1590 0 0         if(defined(my $value = $self->{$formatted_key,$driver}))
1591             {
1592 0           my $dt = $db->parse_date($value);
1593              
1594 0 0         unless($dt)
1595             {
1596 0 0 0       $dt = Rose::DateTime::Util::parse_epoch($value, $tz || $db->server_time_zone) or
1597             Carp::croak "Invalid epoch: '$value'";
1598             }
1599              
1600 0 0         if(ref $dt)
1601             {
1602 0   0       $dt->set_time_zone($tz || $db->server_time_zone);
1603             }
1604              
1605 0           return $self->{$key} = $dt;
1606             }
1607              
1608 0           return undef;
1609 0           };
1610             }
1611 0           else { Carp::croak "Unknown interface: $interface" }
1612              
1613 0           return \%methods;
1614             }
1615              
1616             1;
1617              
1618             __END__
1619              
1620             =head1 NAME
1621              
1622             Rose::DB::Object::MakeMethods::Date - Create date-related methods for Rose::DB::Object-derived objects.
1623              
1624             =head1 SYNOPSIS
1625              
1626             package MyDBObject;
1627              
1628             use base 'Rose::DB::Object';
1629              
1630             use Rose::DB::Object::MakeMethods::Date
1631             (
1632             date =>
1633             [
1634             'start_date',
1635             'end_date' => { default => '2005-01-30' }
1636             ],
1637              
1638             datetime =>
1639             [
1640             'date_created',
1641             'other_date' => { type => 'datetime year to minute' },
1642             ],
1643              
1644             timestamp =>
1645             [
1646             'last_modified' => { default => '2005-01-30 12:34:56.123' }
1647             ],
1648              
1649             epoch =>
1650             [
1651             due_date => { default => '2003-01-02 12:34:56' },
1652             event_start => { hires => 1 },
1653             ],
1654             );
1655              
1656             ...
1657              
1658             $o->start_date('2/3/2004 8am');
1659             $dt = $o->start_date(truncate => 'day');
1660              
1661             print $o->end_date(format => '%m/%d/%Y'); # 2005-01-30
1662              
1663             $o->date_created('now');
1664              
1665             $o->other_date('2001-02-20 12:34:56');
1666              
1667             # 02/20/2001 12:34:00
1668             print $o->other_date(format => '%m/%d/%Y %H:%M:%S');
1669              
1670             print $o->last_modified(format => '%S.%5N'); # 56.12300
1671              
1672             print $o->due_date(format => '%m/%d/%Y'); # 01/02/2003
1673              
1674             $o->event_start('1980-10-11 6:00.123456');
1675              
1676             =head1 DESCRIPTION
1677              
1678             C<Rose::DB::Object::MakeMethods::Date> creates methods that deal with dates, and inherits from L<Rose::Object::MakeMethods>. See the L<Rose::Object::MakeMethods> documentation to learn about the interface. The method types provided by this module are described below.
1679              
1680             All method types defined by this module are designed to work with objects that are subclasses of (or otherwise conform to the interface of) L<Rose::DB::Object>. In particular, the object is expected to have a L<db|Rose::DB::Object/db> method that returns a L<Rose::DB>-derived object. See the L<Rose::DB::Object> documentation for more details.
1681              
1682             =head1 METHODS TYPES
1683              
1684             =over 4
1685              
1686             =item B<date>
1687              
1688             Create get/set methods for date (year, month, day) attributes.
1689              
1690             =over 4
1691              
1692             =item Options
1693              
1694             =over 4
1695              
1696             =item C<default>
1697              
1698             Determines the default value of the attribute.
1699              
1700             =item C<hash_key>
1701              
1702             The key inside the hash-based object to use for the storage of this
1703             attribute. Defaults to the name of the method.
1704              
1705             =item C<interface>
1706              
1707             Choose the interface. The default is C<get_set>.
1708              
1709             =item C<time_zone>
1710              
1711             The time zone name, which must be in a format that is understood by L<DateTime::TimeZone>.
1712              
1713             =back
1714              
1715             =item Interfaces
1716              
1717             =over 4
1718              
1719             =item C<get_set>
1720              
1721             Creates a get/set method for a date (year, month, day) attribute. When setting the attribute, the value is passed through the L<parse_date|Rose::DB/parse_date> method of the object's L<db|Rose::DB::Object/db> attribute. If that fails, the value is passed to L<Rose::DateTime::Util>'s L<parse_date()|Rose::DateTime::Util/parse_date> function. If that fails, a fatal error will occur.
1722              
1723             The time zone of the L<DateTime> object that results from a successful parse is set to the value of the C<time_zone> option, if defined. Otherwise, it is set to the L<server_time_zone|Rose::DB/server_time_zone> value of the object's L<db|Rose::DB::Object/db> attribute using L<DateTime>'s L<set_time_zone|DateTime/set_time_zone> method.
1724              
1725             When saving to the database, the method will pass the attribute value through the L<format_date|Rose::DateTime::Util/format_date> method of the object's L<db|Rose::DB::Object/db> attribute before returning it. Otherwise, the value is returned as-is.
1726              
1727             This method is designed to allow date values to make a round trip from and back into the database without ever being "inflated" into L<DateTime> objects. Any use of the attribute (get or set) outside the context of loading from or saving to the database will cause the value to be "inflated" using the L<parse_date|Rose::DB/parse_date> method of the object's L<db|Rose::DB::Object/db> attribute. If that fails, L<Rose::DateTime::Util>'s L<parse_date()|Rose::DateTime::Util/parse_date> function is tried. If that fails, a fatal error will occur.
1728              
1729             If passed two arguments and the first argument is "format", then the second argument is taken as a format string and passed to L<Rose::DateTime::Util>'s L<format_date|Rose::DateTime::Util/format_date> function along with the current value of the date attribute. Example:
1730              
1731             $o->start_date('2004-05-22');
1732             print $o->start_date(format => '%A'); # "Saturday"
1733              
1734             If passed two arguments and the first argument is "truncate", then the second argument is taken as the value of the C<to> argument to L<DateTime>'s L<truncate|DateTime/truncate> method, which is applied to a clone of the current value of the date attribute, which is then returned. Example:
1735              
1736             $o->start_date('2004-05-22');
1737              
1738             # Equivalent to:
1739             # $d = $o->start_date->clone->truncate(to => 'month')
1740             $d = $o->start_date(truncate => 'month');
1741              
1742             If the date attribute is undefined, then undef is returned (i.e., no clone or call to L<truncate|DateTime/truncate> is made).
1743              
1744             If a valid date keyword is passed as an argument, the value will never be "inflated" but rather passed to the database I<and> returned to other code unmodified. That means that the "truncate" and "format" calls described above will also return the date keyword unmodified. See the L<Rose::DB> documentation for more information on date keywords.
1745              
1746             =item C<get>
1747              
1748             Creates an accessor method for a date (year, month, day) attribute. This method behaves like the C<get_set> method, except that the value cannot be set.
1749              
1750             =item C<set>
1751              
1752             Creates a mutator method for a date (year, month, day) attribute. This method behaves like the C<get_set> method, except that a fatal error will occur if no arguments are passed. It also does not support the C<truncate> and C<format> parameters.
1753              
1754             =back
1755              
1756             =back
1757              
1758             Example:
1759              
1760             package MyDBObject;
1761              
1762             use base 'Rose::DB::Object';
1763              
1764             use Rose::DB::Object::MakeMethods::Date
1765             (
1766             date =>
1767             [
1768             'start_date',
1769             'end_date' => { default => '2005-01-30' }
1770             ],
1771             );
1772              
1773             ...
1774              
1775             $o->start_date('2/3/2004');
1776             $dt = $o->start_date(truncate => 'week');
1777              
1778             print $o->end_date(format => '%m/%d/%Y'); # 01/30/2005
1779              
1780             =item B<datetime>
1781              
1782             Create get/set methods for "datetime" (year, month, day, hour, minute, second) attributes.
1783              
1784             =over 4
1785              
1786             =item Options
1787              
1788             =over 4
1789              
1790             =item C<default>
1791              
1792             Determines the default value of the attribute.
1793              
1794             =item C<hash_key>
1795              
1796             The key inside the hash-based object to use for the storage of this
1797             attribute. Defaults to the name of the method.
1798              
1799             =item C<interface>
1800              
1801             Choose the interface. The default is C<get_set>.
1802              
1803             =item C<time_zone>
1804              
1805             The time zone name, which must be in a format that is understood by L<DateTime::TimeZone>.
1806              
1807             =item C<type>
1808              
1809             The datetime variant as a string. Each space in the string is replaced with an underscore "_", then the string is appended to "format_" and "parse_" in order to form the names of the methods called on the object's L<db|Rose::DB::Object/db> attribute to format and parse datetime values. The default is "datetime", which means that the C<format_datetime()> and C<parse_datetime()> methods will be used.
1810              
1811             Any string that results in a set of method names that are supported by the object's L<db|Rose::DB::Object/db> attribute is acceptable. Check the documentation for the class of the object's L<db|Rose::DB::Object/db> attribute for a list of valid method names.
1812              
1813             =back
1814              
1815             =item Interfaces
1816              
1817             =over 4
1818              
1819             =item C<get_set>
1820              
1821             Creates a get/set method for a "datetime" attribute. The exact granularity of the "datetime" value is determined by the value of the C<type> option (see above).
1822              
1823             When setting the attribute, the value is passed through the C<parse_TYPE()> method of the object's L<db|Rose::DB::Object/db> attribute, where C<TYPE> is the value of the C<type> option. If that fails, the value is passed to L<Rose::DateTime::Util>'s L<parse_date()|Rose::DateTime::Util/parse_date> function. If that fails, a fatal error will occur.
1824              
1825             The time zone of the L<DateTime> object that results from a successful parse is set to the value of the C<time_zone> option, if defined. Otherwise, it is set to the L<server_time_zone|Rose::DB/server_time_zone> value of the object's L<db|Rose::DB::Object/db> attribute using L<DateTime>'s L<set_time_zone|DateTime/set_time_zone> method.
1826              
1827             When saving to the database, the method will pass the attribute value through the C<format_TYPE()> method of the object's L<db|Rose::DB::Object/db> attribute before returning it, where C<TYPE> is the value of the C<type> option. Otherwise, the value is returned as-is.
1828              
1829             This method is designed to allow datetime values to make a round trip from and back into the database without ever being "inflated" into L<DateTime> objects. Any use of the attribute (get or set) outside the context of loading from or saving to the database will cause the value to be "inflated" using the C<parse_TYPE()> method of the object's L<db|Rose::DB::Object/db> attribute, where C<TYPE> is the value of the C<type> option. If that fails, L<Rose::DateTime::Util>'s L<parse_date()|Rose::DateTime::Util/parse_date> function is tried. If that fails, a fatal error will occur.
1830              
1831             If passed two arguments and the first argument is "format", then the second argument is taken as a format string and passed to L<Rose::DateTime::Util>'s L<format_date|Rose::DateTime::Util/format_date> function along with the current value of the datetime attribute. Example:
1832              
1833             $o->start_date('2004-05-22 12:34:56');
1834             print $o->start_date(format => '%A'); # "Saturday"
1835              
1836             If passed two arguments and the first argument is "truncate", then the second argument is taken as the value of the C<to> argument to L<DateTime>'s L<truncate|DateTime/truncate> method, which is applied to a clone of the current value of the datetime attribute, which is then returned. Example:
1837              
1838             $o->start_date('2004-05-22 04:32:01');
1839              
1840             # Equivalent to:
1841             # $d = $o->start_date->clone->truncate(to => 'month')
1842             $d = $o->start_date(truncate => 'month');
1843              
1844             If the datetime attribute is undefined, then undef is returned (i.e., no clone or call to L<truncate|DateTime/truncate> is made).
1845              
1846             If a valid datetime keyword is passed as an argument, the value will never be "inflated" but rather passed to the database I<and> returned to other code unmodified. That means that the "truncate" and "format" calls described above will also return the datetime keyword unmodified. See the L<Rose::DB> documentation for more information on datetime keywords.
1847              
1848             =item C<get>
1849              
1850             Creates an accessor method for a "datetime" attribute. This method behaves like the C<get_set> method, except that the value cannot be set.
1851              
1852             =item C<set>
1853              
1854             Creates a mutator method for a "datetime" attribute. This method behaves like the C<get_set> method, except that a fatal error will occur if no arguments are passed. It also does not support the C<truncate> and C<format> parameters.
1855              
1856             =back
1857              
1858             =back
1859              
1860             Example:
1861              
1862             package MyDBObject;
1863              
1864             use base 'Rose::DB::Object';
1865              
1866             use Rose::DB::Object::MakeMethods::Date
1867             (
1868             datetime =>
1869             [
1870             'start_date',
1871             'end_date' => { default => '2005-01-30 12:34:56' }
1872             'other_date' => { type => 'datetime year to minute' },
1873             ],
1874             );
1875              
1876             ...
1877              
1878             $o->start_date('2/3/2004 8am');
1879             $dt = $o->start_date(truncate => 'day');
1880              
1881             # 01/30/2005 12:34:56
1882             print $o->end_date(format => '%m/%d/%Y %H:%M:%S');
1883              
1884             $o->other_date('2001-02-20 12:34:56');
1885              
1886             # 02/20/2001 12:34:00
1887             print $o->other_date(format => '%m/%d/%Y %H:%M:%S');
1888              
1889             =item B<epoch>
1890              
1891             Create get/set methods for an attribute that stores seconds since the Unix epoch.
1892              
1893             =over 4
1894              
1895             =item Options
1896              
1897             =over 4
1898              
1899             =item C<default>
1900              
1901             Determines the default value of the attribute.
1902              
1903             =item C<hash_key>
1904              
1905             The key inside the hash-based object to use for the storage of this
1906             attribute. Defaults to the name of the method.
1907              
1908             =item C<hires>
1909              
1910             A boolean flag that indicates whether or not epoch values should be stored with fractional seconds. If true, then up to six (6) digits past the decimal point are preserved. The default is false.
1911              
1912             =item C<interface>
1913              
1914             Choose the interface. The default is C<get_set>.
1915              
1916             =item C<time_zone>
1917              
1918             The time zone name, which must be in a format that is understood by L<DateTime::TimeZone>.
1919              
1920             =back
1921              
1922             =item Interfaces
1923              
1924             =over 4
1925              
1926             =item C<get_set>
1927              
1928             Creates a get/set method for an attribute that stores seconds since the Unix epoch. When setting the attribute, the value is passed through L<Rose::DateTime::Util>'s L<parse_date()|Rose::DateTime::Util/parse_date> function. If that fails, a fatal error will occur.
1929              
1930             The time zone of the L<DateTime> object that results from a successful parse is set to the value of the C<time_zone> option, if defined. Otherwise, it is set to the L<server_time_zone|Rose::DB/server_time_zone> value of the object's L<db|Rose::DB::Object/db> attribute using L<DateTime>'s L<set_time_zone|DateTime/set_time_zone> method.
1931              
1932             When saving to the database, the L<epoch|DateTime/epoch> or L<hires_epoch|DateTime/hires_epoch> method will be called on the L<DateTime> object, depending on the value of the C<hires> option. (See above.)
1933              
1934             This method is designed to allow values to make a round trip from and back into the database without ever being "inflated" into L<DateTime> objects. Any use of the attribute (get or set) outside the context of loading from or saving to the database will cause the value to be "inflated" using L<Rose::DateTime::Util>'s L<parse_date()|Rose::DateTime::Util/parse_date> function. If that fails, a fatal error will occur.
1935              
1936             If passed two arguments and the first argument is "format", then the second argument is taken as a format string and passed to L<Rose::DateTime::Util>'s L<format_date|Rose::DateTime::Util/format_date> function along with the current value of the attribute. Example:
1937              
1938             $o->due_date('2004-05-22');
1939             print $o->due_date(format => '%A'); # "Saturday"
1940              
1941             If passed two arguments and the first argument is "truncate", then the second argument is taken as the value of the C<to> argument to L<DateTime>'s L<truncate|DateTime/truncate> method, which is applied to a clone of the current value of the attribute, which is then returned. Example:
1942              
1943             $o->due_date('2004-05-22');
1944              
1945             # Equivalent to:
1946             # $d = $o->due_date->clone->truncate(to => 'month')
1947             $d = $o->due_date(truncate => 'month');
1948              
1949             If the attribute is undefined, then undef is returned (i.e., no clone or call to L<truncate|DateTime/truncate> is made).
1950              
1951             =item C<get>
1952              
1953             Creates an accessor method an attribute that stores seconds since the Unix epoch. This method behaves like the C<get_set> method, except that the value cannot be set.
1954              
1955             =item C<set>
1956              
1957             Creates a mutator method for an attribute that stores seconds since the Unix epoch. This method behaves like the C<get_set> method, except that a fatal error will occur if no arguments are passed. It also does not support the C<truncate> and C<format> parameters.
1958              
1959             =back
1960              
1961             =back
1962              
1963             Example:
1964              
1965             package MyDBObject;
1966              
1967             use base 'Rose::DB::Object';
1968              
1969             use Rose::DB::Object::MakeMethods::Date
1970             (
1971             epoch =>
1972             [
1973             due_date => { default => '2003-01-02 12:34:56' },
1974             event_start => { hires => 1 },
1975             ],
1976             );
1977              
1978             ...
1979              
1980             print $o->due_date(format => '%m/%d/%Y'); # 01/02/2003
1981             $dt = $o->due_date(truncate => 'week');
1982              
1983             $o->event_start('1980-10-11 6:00.123456');
1984             print $o->event_start(format => '%6N'); # 123456
1985              
1986             =item B<timestamp>
1987              
1988             Create get/set methods for "timestamp" (year, month, day, hour, minute, second, fractional seconds) attributes.
1989              
1990             =over 4
1991              
1992             =item Options
1993              
1994             =over 4
1995              
1996             =item C<default>
1997              
1998             Determines the default value of the attribute.
1999              
2000             =item C<hash_key>
2001              
2002             The key inside the hash-based object to use for the storage of this
2003             attribute. Defaults to the name of the method.
2004              
2005             =item C<interface>
2006              
2007             Choose the interface. The default interface is C<get_set>.
2008              
2009             =item C<time_zone>
2010              
2011             A time zone name, which must be in a format that is understood by L<DateTime::TimeZone>.
2012              
2013             =back
2014              
2015             =item Interfaces
2016              
2017             =over 4
2018              
2019             =item C<get_set>
2020              
2021             Creates a get/set method for a "timestamp" (year, month, day, hour, minute, second, fractional seconds) attribute. When setting the attribute, the value is passed through the C<parse_timestamp()> method of the object's L<db|Rose::DB::Object/db> attribute. If that fails, the value is passed to L<Rose::DateTime::Util>'s L<parse_date()|Rose::DateTime::Util/parse_date> function. If that fails, a fatal error will occur.
2022              
2023             The time zone of the L<DateTime> object that results from a successful parse is set to the value of the C<time_zone> option, if defined. Otherwise, it is set to the L<server_time_zone|Rose::DB/server_time_zone> value of the object's L<db|Rose::DB::Object/db> attribute using L<DateTime>'s L<set_time_zone|DateTime/set_time_zone> method.
2024              
2025             When saving to the database, the method will pass the attribute value through the L<format_timestamp|Rose::DB/format_timestamp> method of the object's L<db|Rose::DB::Object/db> attribute before returning it. Otherwise, the value is returned as-is.
2026              
2027             This method is designed to allow timestamp values to make a round trip from and back into the database without ever being "inflated" into L<DateTime> objects. Any use of the attribute (get or set) outside the context of loading from or saving to the database will cause the value to be "inflated" using the C<parse_timestamp()> method of the object's L<db|Rose::DB::Object/db> attribute. If that fails, L<Rose::DateTime::Util>'s L<parse_date()|Rose::DateTime::Util/parse_date> function is tried. If that fails, a fatal error will occur.
2028              
2029             If passed two arguments and the first argument is "format", then the second argument is taken as a format string and passed to L<Rose::DateTime::Util>'s L<format_date|Rose::DateTime::Util/format_date> function along with the current value of the timestamp attribute. Example:
2030              
2031             $o->start_date('2004-05-22 12:34:56.123');
2032             print $o->start_date(format => '%A'); # "Saturday"
2033              
2034             If passed two arguments and the first argument is "truncate", then the second argument is taken as the value of the C<to> argument to L<DateTime>'s L<truncate|DateTime/truncate> method, which is applied to a clone of the current value of the timestamp attribute, which is then returned. Example:
2035              
2036             $o->start_date('2004-05-22 04:32:01.456');
2037              
2038             # Equivalent to:
2039             # $d = $o->start_date->clone->truncate(to => 'month')
2040             $d = $o->start_date(truncate => 'month');
2041              
2042             If the timestamp attribute is undefined, then undef is returned (i.e., no clone or call to L<truncate|DateTime/truncate> is made).
2043              
2044             If a valid timestamp keyword is passed as an argument, the value will never be "inflated" but rather passed to the database I<and> returned to other code unmodified. That means that the "truncate" and "format" calls described above will also return the timestamp keyword unmodified. See the L<Rose::DB> documentation for more information on timestamp keywords.
2045              
2046             =item C<get>
2047              
2048             Creates an accessor method for a "timestamp" (year, month, day, hour, minute, second, fractional seconds) attribute. This method behaves like the C<get_set> method, except that the value cannot be set.
2049              
2050             =item C<set>
2051              
2052             Creates a mutator method for a "timestamp" (year, month, day, hour, minute, second, fractional seconds) attribute. This method behaves like the C<get_set> method, except that a fatal error will occur if no arguments are passed. It also does not support the C<truncate> and C<format> parameters.
2053              
2054             =back
2055              
2056             =back
2057              
2058             Example:
2059              
2060             package MyDBObject;
2061              
2062             use base 'Rose::DB::Object';
2063              
2064             use Rose::DB::Object::MakeMethods::Date
2065             (
2066             timestamp =>
2067             [
2068             'start_date',
2069             'end_date' => { default => '2005-01-30 12:34:56.123' }
2070             ],
2071             );
2072              
2073             ...
2074              
2075             $o->start_date('2/3/2004 8am');
2076             $dt = $o->start_date(truncate => 'day');
2077              
2078             # 01/30/2005 12:34:56.12300
2079             print $o->end_date(format => '%m/%d/%Y %H:%M:%S.%5N');
2080              
2081             =item B<timestamp_without_time_zone>
2082              
2083             This is identical to the L<timestamp|/timestamp> method described above, but with the C<time_zone> parameter always set to the value "floating". Any attempt to set the C<time_zone> parameter explicitly will cause a fatal error.
2084              
2085             =item B<timestamp_with_time_zone>
2086              
2087             Create get/set methods for "timestamp with time zone" (year, month, day, hour, minute, second, fractional seconds, time zone) attributes.
2088              
2089             =over 4
2090              
2091             =item Options
2092              
2093             =over 4
2094              
2095             =item C<default>
2096              
2097             Determines the default value of the attribute.
2098              
2099             =item C<hash_key>
2100              
2101             The key inside the hash-based object to use for the storage of this
2102             attribute. Defaults to the name of the method.
2103              
2104             =item C<interface>
2105              
2106             Choose the interface. The default interface is C<get_set>.
2107              
2108             =item C<time_zone>
2109              
2110             A time zone name, which must be in a format that is understood by L<DateTime::TimeZone>.
2111              
2112             =back
2113              
2114             =item Interfaces
2115              
2116             =over 4
2117              
2118             =item C<get_set>
2119              
2120             Creates a get/set method for a "timestamp with time zone" (year, month, day, hour, minute, second, fractional seconds, time zone) attribute. When setting the attribute, the value is passed through the C<parse_timestamp_with_timezone()> method of the object's L<db|Rose::DB::Object/db> attribute. If that fails, the value is passed to L<Rose::DateTime::Util>'s L<parse_date()|Rose::DateTime::Util/parse_date> function. If that fails, a fatal error will occur.
2121              
2122             The time zone of the L<DateTime> object will be set according to the successful parse of the "timestamp with time zone" value. If the C<time_zone> option is set, then the time zone of the L<DateTime> object is set to this value. Note that this happens I<after> the successful parse, which means that this operation may change the time and/or date according to the difference between the time zone of the value as originally parsed and the new time zone set according to the C<time_zone> option.
2123              
2124             When saving to the database, the method will pass the attribute value through the L<format_timestamp_with_timezone|Rose::DB/format_timestamp_with_timezone> method of the object's L<db|Rose::DB::Object/db> attribute before returning it. Otherwise, the value is returned as-is.
2125              
2126             This method is designed to allow timestamp values to make a round trip from and back into the database without ever being "inflated" into L<DateTime> objects. Any use of the attribute (get or set) outside the context of loading from or saving to the database will cause the value to be "inflated" using the C<parse_timestamp_with_time_zone()> method of the object's L<db|Rose::DB::Object/db> attribute. If that fails, L<Rose::DateTime::Util>'s L<parse_date()|Rose::DateTime::Util/parse_date> function is tried. If that fails, a fatal error will occur.
2127              
2128             If passed two arguments and the first argument is "format", then the second argument is taken as a format string and passed to L<Rose::DateTime::Util>'s L<format_date|Rose::DateTime::Util/format_date> function along with the current value of the timestamp attribute. Example:
2129              
2130             $o->start_date('2004-05-22 12:34:56.123');
2131             print $o->start_date(format => '%A'); # "Saturday"
2132              
2133             If passed two arguments and the first argument is "truncate", then the second argument is taken as the value of the C<to> argument to L<DateTime>'s L<truncate|DateTime/truncate> method, which is applied to a clone of the current value of the timestamp attribute, which is then returned. Example:
2134              
2135             $o->start_date('2004-05-22 04:32:01.456');
2136              
2137             # Equivalent to:
2138             # $d = $o->start_date->clone->truncate(to => 'month')
2139             $d = $o->start_date(truncate => 'month');
2140              
2141             If the timestamp attribute is undefined, then undef is returned (i.e., no clone or call to L<truncate|DateTime/truncate> is made).
2142              
2143             If a valid timestamp keyword is passed as an argument, the value will never be "inflated" but rather passed to the database I<and> returned to other code unmodified. That means that the "truncate" and "format" calls described above will also return the timestamp keyword unmodified. See the L<Rose::DB> documentation for more information on timestamp keywords.
2144              
2145             =item C<get>
2146              
2147             Creates an accessor method for a "timestamp with time zone" (year, month, day, hour, minute, second, fractional seconds, time zone) attribute. This method behaves like the C<get_set> method, except that the value cannot be set.
2148              
2149             =item C<set>
2150              
2151             Creates a mutator method for a "timestamp with time zone" (year, month, day, hour, minute, second, fractional seconds, time zone) attribute. This method behaves like the C<get_set> method, except that a fatal error will occur if no arguments are passed. It also does not support the C<truncate> and C<format> parameters.
2152              
2153             =back
2154              
2155             =back
2156              
2157             Example:
2158              
2159             package MyDBObject;
2160              
2161             use base 'Rose::DB::Object';
2162              
2163             use Rose::DB::Object::MakeMethods::Date
2164             (
2165             timestamp_with_timezone =>
2166             [
2167             'start_date',
2168             'end_date' => { default => '2005-01-30 12:34:56.123' }
2169             ],
2170             );
2171              
2172             ...
2173              
2174             $o->start_date('2/3/2004 8am');
2175             $dt = $o->start_date(truncate => 'day');
2176              
2177             # 01/30/2005 12:34:56.12300
2178             print $o->end_date(format => '%m/%d/%Y %H:%M:%S.%5N');
2179              
2180             =back
2181              
2182             =head1 AUTHOR
2183              
2184             John C. Siracusa (siracusa@gmail.com)
2185              
2186             =head1 LICENSE
2187              
2188             Copyright (c) 2010 by John C. Siracusa. All rights reserved. This program is
2189             free software; you can redistribute it and/or modify it under the same terms
2190             as Perl itself.