| | 24 | |
| | 25 | sub nanosecond { $_[0]->{rd_nanosecs} } |
| | 26 | |
| | 27 | sub utc_rd_values { @{ $_[0] }{ 'utc_rd_days', 'utc_rd_secs', 'rd_nanosecs' } } |
| | 28 | sub local_rd_values { @{ $_[0] }{ 'local_rd_days', 'local_rd_secs', 'rd_nanosecs' } } |
| | 29 | |
| | 30 | # XXX Prime candidate for SelfLoading |
| | 31 | sub ce_year { |
| | 32 | my $year = $_[0]->{local_c}{year}; |
| | 33 | return $year <= 0 ? $year - 1 : $year |
| | 34 | } |
| | 35 | |
| | 36 | sub set_time_zone { |
| | 37 | my ( $self, $tz ) = @_; |
| | 38 | |
| | 39 | # This is a bit of a hack but it works because time zone objects |
| | 40 | # are singletons, and if it doesn't work all we lose is a little |
| | 41 | # bit of speed. |
| | 42 | return $self if $self->{tz} eq $tz; |
| | 43 | |
| | 44 | my $was_floating = $self->{tz}->is_floating; |
| | 45 | |
| | 46 | $self->{tz} = ref $tz ? $tz : DateTime::Lite::TimeZone->load( name => $tz ); |
| | 47 | |
| | 48 | $self->_handle_offset_modifier( $self->second, 1 ); |
| | 49 | |
| | 50 | # if it either was or now is floating (but not both) |
| | 51 | if ( $self->{tz}->is_floating xor $was_floating ) |
| | 52 | { |
| | 53 | $self->_calc_utc_rd; |
| | 54 | } |
| | 55 | elsif ( ! $was_floating ) |
| | 56 | { |
| | 57 | $self->_calc_local_rd; |
| | 58 | } |
| | 59 | |
| | 60 | return $self; |
| | 61 | } |
| | 62 | |
| | 263 | sub from_object { |
| | 264 | my ($class, %p) = @_; |
| | 265 | my $object = delete $p{object}; |
| | 266 | |
| | 267 | my ( $rd_days, $rd_secs, $rd_nanosecs ) = $object->utc_rd_values; |
| | 268 | |
| | 269 | # A kludge because until all calendars are updated to return all |
| | 270 | # three values, $rd_nanosecs could be undef |
| | 271 | $rd_nanosecs ||= 0; |
| | 272 | |
| | 273 | # This is a big hack to let _seconds_as_components operate naively |
| | 274 | # on the given value. If the object _is_ on a leap second, we'll |
| | 275 | # add that to the generated seconds value later. |
| | 276 | my $leap_seconds = 0; |
| | 277 | if ( $object->can('time_zone') && ! $object->time_zone->is_floating |
| | 278 | && $rd_secs > 86399 && $rd_secs <= $class->_day_length($rd_days) ) |
| | 279 | { |
| | 280 | $leap_seconds = $rd_secs - 86399; |
| | 281 | $rd_secs -= $leap_seconds; |
| | 282 | } |
| | 283 | |
| | 284 | my %args; |
| | 285 | @args{ qw( year month day ) } = DateTime::Lite::Util::rd2ymd($rd_days); |
| | 286 | @args{ qw( hour minute second ) } = |
| | 287 | DateTime::Lite::Util::seconds_as_components($rd_secs); |
| | 288 | $args{nanosecond} = $rd_nanosecs; |
| | 289 | |
| | 290 | $args{second} += $leap_seconds; |
| | 291 | |
| | 292 | my $new = $class->new( %p, %args, time_zone => 'UTC' ); |
| | 293 | |
| | 294 | if ( $object->can('time_zone') ) |
| | 295 | { |
| | 296 | $new->set_time_zone( $object->time_zone ); |
| | 297 | } |
| | 298 | else |
| | 299 | { |
| | 300 | $new->set_time_zone( 'floating' ); |
| | 301 | } |
| | 302 | |
| | 303 | return $new; |
| | 304 | } |
| | 305 | |