Server IP : 103.119.228.120 / Your IP : 18.218.75.58 Web Server : Apache System : Linux v8.techscape8.com 3.10.0-1160.119.1.el7.tuxcare.els2.x86_64 #1 SMP Mon Jul 15 12:09:18 UTC 2024 x86_64 User : nobody ( 99) PHP Version : 5.6.40 Disable Function : shell_exec,symlink,system,exec,proc_get_status,proc_nice,proc_terminate,define_syslog_variables,syslog,openlog,closelog,escapeshellcmd,passthru,ocinum cols,ini_alter,leak,listen,chgrp,apache_note,apache_setenv,debugger_on,debugger_off,ftp_exec,dl,dll,myshellexec,proc_open,socket_bind,proc_close,escapeshellarg,parse_ini_filepopen,fpassthru,exec,passthru,escapeshellarg,escapeshellcmd,proc_close,proc_open,ini_alter,popen,show_source,proc_nice,proc_terminate,proc_get_status,proc_close,pfsockopen,leak,apache_child_terminate,posix_kill,posix_mkfifo,posix_setpgid,posix_setsid,posix_setuid,dl,symlink,shell_exec,system,dl,passthru,escapeshellarg,escapeshellcmd,myshellexec,c99_buff_prepare,c99_sess_put,fpassthru,getdisfunc,fx29exec,fx29exec2,is_windows,disp_freespace,fx29sh_getupdate,fx29_buff_prepare,fx29_sess_put,fx29shexit,fx29fsearch,fx29ftpbrutecheck,fx29sh_tools,fx29sh_about,milw0rm,imagez,sh_name,myshellexec,checkproxyhost,dosyayicek,c99_buff_prepare,c99_sess_put,c99getsource,c99sh_getupdate,c99fsearch,c99shexit,view_perms,posix_getpwuid,posix_getgrgid,posix_kill,parse_perms,parsesort,view_perms_color,set_encoder_input,ls_setcheckboxall,ls_reverse_all,rsg_read,rsg_glob,selfURL,dispsecinfo,unix2DosTime,addFile,system,get_users,view_size,DirFiles,DirFilesWide,DirPrintHTMLHeaders,GetFilesTotal,GetTitles,GetTimeTotal,GetMatchesCount,GetFileMatchesCount,GetResultFiles,fs_copy_dir,fs_copy_obj,fs_move_dir,fs_move_obj,fs_rmdir,SearchText,getmicrotime MySQL : ON | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /usr/local/share/perl5/DateTime/TimeZone/OlsonDB/ |
Upload File : |
package DateTime::TimeZone::OlsonDB::Observance; $DateTime::TimeZone::OlsonDB::Observance::VERSION = '2.01'; use strict; use warnings; use DateTime::Duration; use DateTime::TimeZone::OlsonDB; use DateTime::TimeZone::OlsonDB::Change; use List::Util 1.33 qw( any first ); use Params::Validate qw( validate SCALAR ARRAYREF UNDEF OBJECT ); sub new { my $class = shift; my %p = validate( @_, { gmtoff => { type => SCALAR }, rules => { type => ARRAYREF }, format => { type => SCALAR }, until => { type => SCALAR, default => q{} }, utc_start_datetime => { type => OBJECT | UNDEF }, offset_from_std => { type => SCALAR, default => 0 }, last_offset_from_utc => { type => SCALAR, default => 0 }, last_offset_from_std => { type => SCALAR, default => 0 }, } ); my $offset_from_utc = $p{gmtoff} =~ m/^[+-]?\d?\d$/ # only hours? need to handle specially ? 3600 * $p{gmtoff} : DateTime::TimeZone::offset_as_seconds( $p{gmtoff} ); my $offset_from_std = DateTime::TimeZone::offset_as_seconds( $p{offset_from_std} ); my $last_offset_from_utc = delete $p{last_offset_from_utc}; my $last_offset_from_std = delete $p{last_offset_from_std}; my $self = bless { %p, offset_from_utc => $offset_from_utc, offset_from_std => $offset_from_std, until => [ split /\s+/, $p{until} ], }, $class; $self->{first_rule} = $self->_first_rule( $last_offset_from_utc, $last_offset_from_std ); if ( $p{utc_start_datetime} ) { $offset_from_std += $self->{first_rule}->offset_from_std if $self->{first_rule}; my $local_start_datetime = $p{utc_start_datetime}->clone; $local_start_datetime += DateTime::Duration->new( seconds => $offset_from_utc + $offset_from_std ); $self->{local_start_datetime} = $local_start_datetime; } return $self; } sub offset_from_utc { $_[0]->{offset_from_utc} || 0 } sub offset_from_std { $_[0]->{offset_from_std} || 0 } sub total_offset { $_[0]->offset_from_utc + $_[0]->offset_from_std } sub rules { @{ $_[0]->{rules} } } sub first_rule { $_[0]->{first_rule} } ## no critic (Subroutines::ProhibitBuiltinHomonyms) sub format { $_[0]->{format} } ## use critic sub utc_start_datetime { $_[0]->{utc_start_datetime} } sub local_start_datetime { $_[0]->{local_start_datetime} } sub formatted_short_name { my $self = shift; my $letter = shift; my $format = $self->format; return $format unless $format =~ /%/; return sprintf( $format, $letter ); } sub expand_from_rules { my $self = shift; my $zone = shift; # real max is year + 1 so we include max year my $max_year = (shift) + 1; my $min_year; if ( $self->utc_start_datetime ) { $min_year = $self->utc_start_datetime->year; } else { # There is at least one time zone that has an infinite # observance, but that observance has rules that only start at # a certain point - Pacific/Chatham # In this case we just find the earliest rule and start there $min_year = ( sort { $a <=> $b } map { $_->min_year } $self->rules )[0]; } my $until = $self->until( $zone->last_change->offset_from_std ); if ($until) { $max_year = $until->year; } else { # Some zones, like Asia/Tehran, have a predefined fixed set of # rules that go well into the future (2037 for Asia/Tehran) my $max_rule_year = 0; foreach my $rule ( $self->rules ) { $max_rule_year = $rule->max_year if $rule->max_year && $rule->max_year > $max_rule_year; } $max_year = $max_rule_year if $max_rule_year > $max_year; } foreach my $year ( $min_year .. $max_year ) { my @rules = $self->_sorted_rules_for_year($year); for my $rule (@rules) { my $dt = $rule->utc_start_datetime_for_year( $year, $self->offset_from_utc, $zone->last_change->offset_from_std ); next if $self->utc_start_datetime && $dt <= $self->utc_start_datetime; ## no critic (Variables::ProhibitReusedNames) my $until = $self->until( $zone->last_change->offset_from_std ); next if $until && $dt >= $until; my $change = DateTime::TimeZone::OlsonDB::Change->new( type => 'rule', utc_start_datetime => $dt, local_start_datetime => $dt + DateTime::Duration->new( seconds => $self->total_offset + $rule->offset_from_std ), short_name => $self->formatted_short_name( $rule->letter ), observance => $self, rule => $rule, ); if ($DateTime::TimeZone::OlsonDB::DEBUG) { ## no critic (InputOutput::RequireCheckedSyscalls) print "Adding rule change ...\n"; $change->_debug_output; } $zone->add_change($change); } } } sub _sorted_rules_for_year { my $self = shift; my $year = shift; ## no critic (BuiltinFunctions::ProhibitComplexMappings) my @rules = ( map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { my $dt = $_->utc_start_datetime_for_year( $year, $self->offset_from_utc, 0 ); [ $_, $dt ] } grep { $_->min_year <= $year && ( ( !$_->max_year ) || $_->max_year >= $year ) } $self->rules ); my %rules_by_month; for my $rule (@rules) { push @{ $rules_by_month{ $rule->month() } }, $rule; } # In some cases we have both a "max year" rule and a "this year" rule for # a given month's change. In that case, we want to pick the more specific # ("this year") rule, not apply both. This only matters for zones that # have a winter transition that follows the Islamic calendar to deal with # Ramadan. So far this has happened with Cairo, El_Aaiun, and other zones # in northern Africa. my @final_rules; for my $month ( sort { $a <=> $b } keys %rules_by_month ) { my @r = @{ $rules_by_month{$month} }; if ( @r == 2 ) { my ($repeating) = grep { !defined $_->max_year() } @r; my ($this_year) = grep { $_->max_year() && $_->max_year() == $year } @r; if ( $repeating && $this_year ) { # We used to pick the repeating rule for year 2037 only # because it seemed like that's what zic did in the past. Now # it seems to pick the "this year" rule instead. if ($DateTime::TimeZone::OlsonDB::DEBUG) { ## no critic (InputOutput::RequireCheckedSyscalls) print "Found two rules for the same month, picking the one for this year\n"; } push @final_rules, $this_year; next; } push @final_rules, @r; } else { push @final_rules, @r; } } return @final_rules; } ## no critic (Subroutines::ProhibitBuiltinHomonyms) sub until { my $self = shift; my $offset_from_std = shift || $self->offset_from_std; return unless defined $self->until_year; my $utc = DateTime::TimeZone::OlsonDB::utc_datetime_for_time_spec( spec => $self->until_time_spec, year => $self->until_year, month => $self->until_month, day => $self->until_day, offset_from_utc => $self->offset_from_utc, offset_from_std => $offset_from_std, ); return $utc; } ## use critic sub until_year { $_[0]->{until}[0] } sub until_month { ( defined $_[0]->{until}[1] ? $DateTime::TimeZone::OlsonDB::MONTHS{ $_[0]->{until}[1] } : 1 ); } sub until_day { ( defined $_[0]->{until}[2] ? DateTime::TimeZone::OlsonDB::parse_day_spec( $_[0]->{until}[2], $_[0]->until_month, $_[0]->until_year ) : 1 ); } sub until_time_spec { defined $_[0]->{until}[3] ? $_[0]->{until}[3] : '00:00:00'; } ## no critic (Subroutines::ProhibitExcessComplexity) sub _first_rule { my $self = shift; my $last_offset_from_utc = shift; my $last_offset_from_std = shift; return unless $self->rules; my $date = $self->utc_start_datetime or return $self->_first_no_dst_rule; my @rules = $self->rules; my %possible_rules; my $year = $date->year; foreach my $rule (@rules) { # We need to look at what the year _would_ be if we added the # rule's offset to the UTC date. Otherwise we can end up with # a UTC date in year X, and a rule that starts in _local_ year # X + 1, where that rule really does apply to that UTC date. my $temp_year = $date->clone->add( seconds => $self->offset_from_utc + $rule->offset_from_std ) ->year; # Save the highest value $year = $temp_year if $temp_year > $year; next if $rule->min_year > $temp_year; $possible_rules{$rule} = $rule; } my $earliest_year = $year - 1; foreach my $rule (@rules) { $earliest_year = $rule->min_year if $rule->min_year < $earliest_year; } # figure out what date each rule would start on _if_ that rule # were applied to this current observance. this could be a rule # that started much earlier, but is only now active because of an # observance switch. An obnoxious example of this is # America/Phoenix in 1944, which applies the US rule in April, # thus (re-)instating the "war time" rule from 1942. Can you say # ridiculous crack-smoking stupidity? my @rule_dates; foreach my $y ( $earliest_year .. $year ) { RULE: foreach my $rule ( values %possible_rules ) { # skip rules that can't have applied the year before the # observance started. if ( $rule->min_year > $y ) { ## no critic (InputOutput::RequireCheckedSyscalls) print 'Skipping rule beginning in ', $rule->min_year, ". Year is $y.\n" if $DateTime::TimeZone::OlsonDB::DEBUG; next RULE; } if ( $rule->max_year && $rule->max_year < $y ) { ## no critic (InputOutput::RequireCheckedSyscalls) print 'Skipping rule ending in ', $rule->max_year, ". Year is $y.\n" if $DateTime::TimeZone::OlsonDB::DEBUG; next RULE; } my $rule_start = $rule->utc_start_datetime_for_year( $y, $last_offset_from_utc, $last_offset_from_std ); push @rule_dates, [ $rule_start, $rule ]; } } @rule_dates = sort { $a->[0] <=> $b->[0] } @rule_dates; ## no critic (InputOutput::RequireCheckedSyscalls) print "Looking for first rule ...\n" if $DateTime::TimeZone::OlsonDB::DEBUG; print ' Observance starts: ', $date->datetime, "\n\n" if $DateTime::TimeZone::OlsonDB::DEBUG; ## use critic # ... look through the rules to see if any are still in # effect at the beginning of the observance ## no critic (ControlStructures::ProhibitCStyleForLoops) for ( my $x = 0; $x < @rule_dates; $x++ ) { my ( $dt, $rule ) = @{ $rule_dates[$x] }; my ( $next_dt, $next_rule ) = $x < @rule_dates - 1 ? @{ $rule_dates[ $x + 1 ] } : undef; next if $next_dt && $next_dt < $date; ## no critic (InputOutput::RequireCheckedSyscalls) print ' This rule starts: ', $dt->datetime, "\n" if $DateTime::TimeZone::OlsonDB::DEBUG; print ' Next rule starts: ', $next_dt->datetime, "\n" if $next_dt && $DateTime::TimeZone::OlsonDB::DEBUG; print ' No next rule\n\n' if !$next_dt && $DateTime::TimeZone::OlsonDB::DEBUG; ## use critic if ( $dt <= $date ) { if ($next_dt) { return $rule if $date < $next_dt; return $next_rule if $date == $next_dt; } else { return $rule; } } } # If this observance has rules, but the rules don't have any # defined changes until after the observance starts, we get the # earliest standard time rule and use it. If there is none, shit # blows up (but this is not the case for any time zones as of # 2009a). I really, really hate the Olson database a lot of the # time! Could this be more arbitrary? my $std_time_rule = $self->_first_no_dst_rule; die q{Cannot find a rule that applies to the observance's date range and cannot find a rule without DST to apply} unless $std_time_rule; return $std_time_rule; } ## use critic sub _first_no_dst_rule { my $self = shift; return first { !$_->offset_from_std } sort { $a->min_year <=> $b->min_year } $self->rules; } 1;