| 1 | # Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd. |
|---|
| 2 | # This program is distributed under the terms of the |
|---|
| 3 | # GNU General Public License, version 2. |
|---|
| 4 | # |
|---|
| 5 | # $Id$ |
|---|
| 6 | |
|---|
| 7 | # Adapted from DateTime package to avoid requirement of DateTime package. |
|---|
| 8 | |
|---|
| 9 | package MT::DateTime; |
|---|
| 10 | |
|---|
| 11 | use Exporter; |
|---|
| 12 | @MT::DateTime::ISA = qw( Exporter ); |
|---|
| 13 | use vars qw( @EXPORT_OK ); |
|---|
| 14 | @EXPORT_OK = qw( ymd2rd tz_offset_as_seconds ); |
|---|
| 15 | |
|---|
| 16 | sub new { |
|---|
| 17 | my $class = shift; |
|---|
| 18 | my (%param) = @_; |
|---|
| 19 | my $self = \%param; |
|---|
| 20 | bless $self, $class || __PACKAGE__; |
|---|
| 21 | } |
|---|
| 22 | |
|---|
| 23 | sub week_year { (shift->week)[0] } |
|---|
| 24 | sub week_number { (shift->week)[1] } |
|---|
| 25 | |
|---|
| 26 | sub year { shift->{year} } |
|---|
| 27 | sub month { shift->{month} } |
|---|
| 28 | sub day { shift->{day} } |
|---|
| 29 | sub hour { shift->{hour} } |
|---|
| 30 | sub minute { shift->{minute} } |
|---|
| 31 | sub second { shift->{second} } |
|---|
| 32 | sub time_zone { shift->{time_zone} } |
|---|
| 33 | |
|---|
| 34 | sub day_of_year { |
|---|
| 35 | my $self = shift; |
|---|
| 36 | return $self->{local_c}{day_of_year} if $self->{local_c}{day_of_year}; |
|---|
| 37 | |
|---|
| 38 | my $year = $self->year; |
|---|
| 39 | my $days = 0; |
|---|
| 40 | |
|---|
| 41 | require MT::Util; |
|---|
| 42 | for (my $i = 1; $i < $self->month; $i++) { |
|---|
| 43 | $days += MT::Util::days_in($i, $year); |
|---|
| 44 | } |
|---|
| 45 | $days += $self->day; |
|---|
| 46 | $self->{local_c}{day_of_year} = $days; |
|---|
| 47 | } |
|---|
| 48 | |
|---|
| 49 | sub week { |
|---|
| 50 | my $self = shift; |
|---|
| 51 | |
|---|
| 52 | unless ( defined $self->{local_c}{week_year} ) { |
|---|
| 53 | my $jan_one_dow_m1 = |
|---|
| 54 | ( ( $self->ymd2rd( $self->year, 1, 1 ) + 6 ) % 7 ); |
|---|
| 55 | |
|---|
| 56 | $self->{local_c}{week_number} = |
|---|
| 57 | int( ( ( $self->day_of_year) + $jan_one_dow_m1 ) / 7 ); |
|---|
| 58 | $self->{local_c}{week_number}++ if $jan_one_dow_m1 < 4; |
|---|
| 59 | |
|---|
| 60 | if ( $self->{local_c}{week_number} == 0 ) { |
|---|
| 61 | $self->{local_c}{week_year} = $self->year - 1; |
|---|
| 62 | $self->{local_c}{week_number} = |
|---|
| 63 | $self->weeks_in_year( $self->{local_c}{week_year} ); |
|---|
| 64 | } |
|---|
| 65 | elsif ( $self->{local_c}{week_number} == 53 && |
|---|
| 66 | $self->weeks_in_year( $self->year ) == 52 ) |
|---|
| 67 | { |
|---|
| 68 | $self->{local_c}{week_number} = 1; |
|---|
| 69 | $self->{local_c}{week_year} = $self->year + 1; |
|---|
| 70 | } |
|---|
| 71 | else |
|---|
| 72 | { |
|---|
| 73 | $self->{local_c}{week_year} = $self->year; |
|---|
| 74 | } |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | return @{ $self->{local_c} }{ 'week_year', 'week_number' } |
|---|
| 78 | } |
|---|
| 79 | |
|---|
| 80 | sub weeks_in_year { |
|---|
| 81 | my $self = shift; |
|---|
| 82 | my $year = shift; |
|---|
| 83 | |
|---|
| 84 | my $jan_one_dow = |
|---|
| 85 | ( ( $self->ymd2rd( $year, 1, 1 ) + 6 ) % 7 ) + 1; |
|---|
| 86 | my $dec_31_dow = |
|---|
| 87 | ( ( $self->ymd2rd( $year, 12, 31 ) + 6 ) % 7 ) + 1; |
|---|
| 88 | |
|---|
| 89 | return $jan_one_dow == 4 || $dec_31_dow == 4 ? 53 : 52; |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | sub ymd2rd { |
|---|
| 93 | my $self = shift; |
|---|
| 94 | |
|---|
| 95 | use integer; |
|---|
| 96 | my ( $y, $m, $d ); |
|---|
| 97 | if (@_) { |
|---|
| 98 | ( $y, $m, $d ) = @_; |
|---|
| 99 | } elsif (ref $self) { |
|---|
| 100 | ( $y, $m, $d ) = ( $self->{year}, $self->{month}, $self->{day} ); |
|---|
| 101 | } |
|---|
| 102 | |
|---|
| 103 | my $adj; |
|---|
| 104 | |
|---|
| 105 | # make month in range 3..14 (treat Jan & Feb as months 13..14 of |
|---|
| 106 | # prev year) |
|---|
| 107 | if ( $m <= 2 ) |
|---|
| 108 | { |
|---|
| 109 | $y -= ( $adj = ( 14 - $m ) / 12 ); |
|---|
| 110 | $m += 12 * $adj; |
|---|
| 111 | } |
|---|
| 112 | elsif ( $m > 14 ) |
|---|
| 113 | { |
|---|
| 114 | $y += ( $adj = ( $m - 3 ) / 12 ); |
|---|
| 115 | $m -= 12 * $adj; |
|---|
| 116 | } |
|---|
| 117 | |
|---|
| 118 | # make year positive (oh, for a use integer 'sane_div'!) |
|---|
| 119 | if ( $y < 0 ) |
|---|
| 120 | { |
|---|
| 121 | $d -= 146097 * ( $adj = ( 399 - $y ) / 400 ); |
|---|
| 122 | $y += 400 * $adj; |
|---|
| 123 | } |
|---|
| 124 | |
|---|
| 125 | # add: day of month, days of previous 0-11 month period that began |
|---|
| 126 | # w/March, days of previous 0-399 year period that began w/March |
|---|
| 127 | # of a 400-multiple year), days of any 400-year periods before |
|---|
| 128 | # that, and 306 days to adjust from Mar 1, year 0-relative to Jan |
|---|
| 129 | # 1, year 1-relative (whew) |
|---|
| 130 | |
|---|
| 131 | $d += ( $m * 367 - 1094 ) / 12 + $y % 100 * 1461 / 4 + |
|---|
| 132 | ( $y / 100 * 36524 + $y / 400 ) - 306; |
|---|
| 133 | } |
|---|
| 134 | |
|---|
| 135 | sub tz_offset_as_seconds { |
|---|
| 136 | my $self = shift; |
|---|
| 137 | my $offset = shift; |
|---|
| 138 | if (ref $self) { |
|---|
| 139 | $offset = $self->{time_zone}; |
|---|
| 140 | } |
|---|
| 141 | |
|---|
| 142 | return undef unless defined $offset; |
|---|
| 143 | |
|---|
| 144 | return 0 if $offset eq '0'; |
|---|
| 145 | |
|---|
| 146 | my ( $sign, $hours, $minutes, $seconds ); |
|---|
| 147 | if ( $offset =~ /^([\+\-])?(\d\d?):(\d\d)(?::(\d\d))?$/ ) |
|---|
| 148 | { |
|---|
| 149 | ( $sign, $hours, $minutes, $seconds ) = ( $1, $2, $3, $4 ); |
|---|
| 150 | } |
|---|
| 151 | elsif ( $offset =~ /^([\+\-])?(\d\d)(\d\d)(\d\d)?$/ ) |
|---|
| 152 | { |
|---|
| 153 | ( $sign, $hours, $minutes, $seconds ) = ( $1, $2, $3, $4 ); |
|---|
| 154 | } |
|---|
| 155 | else |
|---|
| 156 | { |
|---|
| 157 | return undef; |
|---|
| 158 | } |
|---|
| 159 | |
|---|
| 160 | $sign = '+' unless defined $sign; |
|---|
| 161 | return undef unless $hours >= 0 && $hours <= 99; |
|---|
| 162 | return undef unless $minutes >= 0 && $minutes <= 59; |
|---|
| 163 | return undef unless ! defined( $seconds ) || ( $seconds >= 0 && $seconds <= 59 ); |
|---|
| 164 | |
|---|
| 165 | my $total = $hours * 3600 + $minutes * 60; |
|---|
| 166 | $total += $seconds if $seconds; |
|---|
| 167 | $total *= -1 if $sign eq '-'; |
|---|
| 168 | |
|---|
| 169 | return $total; |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | 1; |
|---|
| 173 | __END__ |
|---|
| 174 | |
|---|
| 175 | =head1 NAME |
|---|
| 176 | |
|---|
| 177 | MT::DateTime |
|---|
| 178 | |
|---|
| 179 | =head1 AUTHOR & COPYRIGHT |
|---|
| 180 | |
|---|
| 181 | Please see L<MT/AUTHOR & COPYRIGHT>. |
|---|
| 182 | |
|---|
| 183 | =cut |
|---|