@@ -82,9 +82,8 @@ sub _TZ_DEFINITION_KEYS {
8282 qw( std_name std_sign std_hours std_minutes std_seconds dst_name dst_sign dst_hours dst_minutes dst_seconds start_julian_without_feb29 end_julian_without_feb29 start_julian_with_feb29 end_julian_with_feb29 start_month end_month start_week end_week start_day end_day start_hour end_hour start_minute end_minute start_second end_second) ;
8383}
8484
85- my $_modern_regexs_work = 1;
86- my $_timezone_full_name_regex =
87- eval # # no critic (ProhibitStringyEval) required to allow old perl (pre 5.10) to compile
85+ my $_modern_regexs_work = 1;
86+ my $_timezone_full_name_regex = eval # # no critic (ProhibitStringyEval) required to allow old perl (pre 5.10) to compile
8887 ' qr/(?<tz>(?<area>\w+)(?:\/(?<location>[\w\-\/+]+))?)/smx'
8988 or do { $_modern_regexs_work = undef };
9089if ( !$_modern_regexs_work ) {
@@ -2161,7 +2160,10 @@ sub _get_isdst_gmtoff_abbr_calculating_for_time_local {
21612160 my $first_standard_time_type = $self -> _get_first_standard_time_type($tz );
21622161 my $transition_index = 0;
21632162 my $transition_time_found ;
2164- my $previous_offset = $first_standard_time_type -> {gmtoff };
2163+ my $previous_offset =
2164+ $OSNAME eq ' MSWin32'
2165+ ? $self -> {_tzdata }-> {$tz }-> {tz_definition }-> {std_offset_in_seconds }
2166+ : $first_standard_time_type -> {gmtoff };
21652167 my $first_transition_time ;
21662168 TRANSITION_TIME:
21672169
@@ -2686,7 +2688,7 @@ sub _cleanup_bracketed_names {
26862688
26872689sub _compile_modern_tz_regex {
26882690 my $modern_tz_regex ;
2689- eval # # no critic (ProhibitStringyEval) required to allow old perl (pre 5.10) to compile
2691+ eval # # no critic (ProhibitStringyEval) required to allow old perl (pre 5.10) to compile
26902692 <<'_REGEX_' or ( !$_modern_regexs_work ) or Carp::croak(" Failed to compile TZ regular expression:$EVAL_ERROR " );
26912693 my $timezone_abbr_name_regex =
26922694 qr/(?:[^:\d,+-][^\d,+-]{2,}|[<]\w*[+-]?\d+[>])/smx;
@@ -3042,16 +3044,24 @@ sub _read_win32_tzfile {
30423044
30433045 $self -> {_comments }-> {$tz } = $comment ;
30443046
3045- my $tz_definition = $self -> _unpack_win32_tzi_structure($binary );
3047+ my $tz_definition =
3048+ $self -> _unpack_win32_tzi_structure( $binary , $standard_name ,
3049+ $daylight_name );
30463050
30473051 $tz_definition -> {std_name } = $standard_name ;
30483052 $tz_definition -> {dst_name } = $daylight_name ;
30493053
30503054 $self -> _initialise_undefined_tz_definition_values($tz_definition );
30513055 $self -> {_tzdata }-> {$tz }-> {tz_definition } = $tz_definition ;
3052- $self -> {_tzdata }-> {$tz }-> {transition_times } =
3053- $self -> _read_win32_transition_times( $timezone_specific_subkey ,
3054- $timezone_specific_registry_path );
3056+ my %win32_dynamic_dst =
3057+ $self -> _extract_win32_dynamic_dst( $timezone_specific_subkey ,
3058+ $timezone_specific_registry_path ,
3059+ $tz_definition );
3060+ foreach my $key (qw( local_time_indexes local_time_types transition_times) ) {
3061+ if ( defined $win32_dynamic_dst {$key } ) {
3062+ $self -> {_tzdata }-> {$tz }-> {$key } = $win32_dynamic_dst {$key };
3063+ }
3064+ }
30553065
30563066 Win32API::Registry::RegCloseKey($timezone_specific_subkey )
30573067 or Carp::croak(
@@ -3107,13 +3117,13 @@ sub _read_tzfile {
31073117}
31083118
31093119sub _unpack_win32_tzi_structure {
3110- my ( $self , $binary ) = @_ ;
3120+ my ( $self , $binary , $standard_name , $daylight_name ) = @_ ;
31113121 my (
31123122 $bias , $standard_bias , $daylight_bias ,
31133123 $standard_year , $standard_month , $standard_day_of_week ,
3114- $standard_day , $standard_hour , $standard_minute ,
3124+ $standard_week , $standard_hour , $standard_minute ,
31153125 $standard_second , $standard_millisecond , $daylight_year ,
3116- $daylight_month , $daylight_day_of_week , $daylight_day ,
3126+ $daylight_month , $daylight_day_of_week , $daylight_week ,
31173127 $daylight_hour , $daylight_minute , $daylight_second ,
31183128 $daylight_millisecond
31193129 ) = unpack ' lllSSSSSSSSSSSSSS' , $binary ;
@@ -3174,8 +3184,8 @@ sub _unpack_win32_tzi_structure {
31743184 ),
31753185 start_month => $daylight_month ,
31763186 end_month => $standard_month ,
3177- start_week => $daylight_day ,
3178- end_week => $standard_day ,
3187+ start_week => $daylight_week ,
3188+ end_week => $standard_week ,
31793189 start_day => $daylight_day_of_week ,
31803190 end_day => $standard_day_of_week ,
31813191 start_hour => $daylight_hour ,
@@ -3188,13 +3198,31 @@ sub _unpack_win32_tzi_structure {
31883198 : ()
31893199 ),
31903200 };
3201+ $tz_definition -> {tz } = " $standard_name "
3202+ . (
3203+ $tz_definition -> {std_hours }
3204+ ? ( $tz_definition -> {std_sign } ? $tz_definition -> {std_sign } : q[ ] )
3205+ . " $tz_definition ->{std_hours}"
3206+ : q[ ]
3207+ )
3208+ . (
3209+ defined $tz_definition -> {dst_hours }
3210+ ? " ,$daylight_name ,"
3211+ . " M$tz_definition ->{start_month}\. $tz_definition ->{start_week}\. $tz_definition ->{start_day},"
3212+ . " M$tz_definition ->{end_month}\. $tz_definition ->{end_week}\. $tz_definition ->{end_day}/$tz_definition ->{end_hour}"
3213+ : q[ ]
3214+ );
3215+
3216+ # tz => "$standard_name-10$daylight_name,M$daylight_month\.$daylight_week\.$daylight_day_of_week,M$standard_month\.$standard_week\.$standard_day_of_week/$standard_hour",
3217+ # $tz_definition->{tz} =~ s/[ ]//smxg;
31913218 return $tz_definition ;
31923219}
31933220
3194- sub _read_win32_transition_times {
3195- my ( $self , $timezone_specific_subkey , $timezone_specific_registry_path ) =
3196- @_ ;
3197- my @transition_times ;
3221+ sub _extract_win32_dynamic_dst {
3222+ my ( $self , $timezone_specific_subkey , $timezone_specific_registry_path ,
3223+ $parent_tz_definition )
3224+ = @_ ;
3225+ my ( @transition_times , @local_time_types , @local_time_indexes );
31983226 if (
31993227 Win32API::Registry::RegOpenKeyExW(
32003228 $timezone_specific_subkey ,
@@ -3226,7 +3254,109 @@ sub _read_win32_transition_times {
32263254 or Carp::croak(
32273255" Failed to read LOCAL_MACHINE\\ $timezone_specific_registry_path \\ Dynamic DST\\ $year :$EXTENDED_OS_ERROR "
32283256 );
3229- my $tz_definition = $self -> _unpack_win32_tzi_structure($binary );
3257+ my $tz_definition = $self -> _unpack_win32_tzi_structure(
3258+ $binary ,
3259+ $parent_tz_definition -> {std_name },
3260+ $parent_tz_definition -> {dst_name }
3261+ );
3262+ $self -> _initialise_undefined_tz_definition_values($tz_definition );
3263+ my @this_years_transition_times ;
3264+ my @this_years_local_time_indexes ;
3265+ my @this_years_local_time_types ;
3266+
3267+ if ( ( defined $tz_definition -> {start_day } )
3268+ && ( defined $tz_definition -> {start_week } )
3269+ && ( defined $tz_definition -> {start_month } ) )
3270+ {
3271+ my $dst_start_time =
3272+ $self -> _get_time_for_wday_week_month_year_offset(
3273+ day => $tz_definition -> {start_day },
3274+ week => $tz_definition -> {start_week },
3275+ month => $tz_definition -> {start_month },
3276+ year => $year ,
3277+ offset => (
3278+ $tz_definition -> {start_hour } * _SECONDS_IN_ONE_MINUTE()
3279+ * _MINUTES_IN_ONE_HOUR()
3280+ ) +
3281+ (
3282+ $tz_definition -> {start_minute } *
3283+ _SECONDS_IN_ONE_MINUTE()
3284+ ) +
3285+ $tz_definition -> {start_second } -
3286+ $tz_definition -> {std_offset_in_seconds }
3287+ );
3288+ push @this_years_transition_times , $dst_start_time ;
3289+ my ( $local_time_index , $local_time_type ) =
3290+ $self -> _win32_find_local_time_type(
3291+ {
3292+ gmtoff => $tz_definition -> {std_offset_in_seconds },
3293+ isdst => 0,
3294+ abbr => $parent_tz_definition -> {std_name }
3295+ },
3296+ @local_time_types
3297+ );
3298+ if ( defined $local_time_type ) {
3299+ push @this_years_local_time_types , $local_time_type ;
3300+ }
3301+ push @this_years_local_time_indexes , $local_time_index - 1;
3302+ }
3303+ if ( ( defined $tz_definition -> {end_day } )
3304+ && ( defined $tz_definition -> {end_week } )
3305+ && ( defined $tz_definition -> {end_month } ) )
3306+ {
3307+ my $dst_end_time =
3308+ $self -> _get_time_for_wday_week_month_year_offset(
3309+ day => $tz_definition -> {end_day },
3310+ week => $tz_definition -> {end_week },
3311+ month => $tz_definition -> {end_month },
3312+ year => $year ,
3313+ offset => (
3314+ $tz_definition -> {end_hour } *
3315+ _SECONDS_IN_ONE_MINUTE() *
3316+ _MINUTES_IN_ONE_HOUR()
3317+ ) +
3318+ (
3319+ $tz_definition -> {end_minute } * _SECONDS_IN_ONE_MINUTE()
3320+ ) +
3321+ $tz_definition -> {end_second } -
3322+ $tz_definition -> {dst_offset_in_seconds }
3323+ );
3324+ push @this_years_transition_times , $dst_end_time ;
3325+ my ( $local_time_index , $local_time_type ) =
3326+ $self -> _win32_find_local_time_type(
3327+ {
3328+ gmtoff => $tz_definition -> {dst_offset_in_seconds },
3329+ isdst => 1,
3330+ abbr => $parent_tz_definition -> {dst_name }
3331+ },
3332+ @local_time_types
3333+ );
3334+ if ( defined $local_time_type ) {
3335+ push @this_years_local_time_types , $local_time_type ;
3336+ }
3337+ push @this_years_local_time_indexes , $local_time_index - 1;
3338+ }
3339+ if (
3340+ ( defined $tz_definition -> {start_day } )
3341+ && ( defined $tz_definition -> {start_week } )
3342+ && ( defined $tz_definition -> {start_month } )
3343+ && ( defined $tz_definition -> {end_day } )
3344+ && ( defined $tz_definition -> {end_week } )
3345+ && ( defined $tz_definition -> {end_month } )
3346+ && ( $tz_definition -> {end_month } <
3347+ $tz_definition -> {start_month } )
3348+ )
3349+ {
3350+ @this_years_transition_times =
3351+ reverse @this_years_transition_times ;
3352+ @this_years_local_time_types =
3353+ reverse @this_years_local_time_types ;
3354+ @this_years_local_time_indexes =
3355+ reverse @this_years_local_time_indexes ;
3356+ }
3357+ push @transition_times , @this_years_transition_times ;
3358+ push @local_time_types , @this_years_local_time_types ;
3359+ push @local_time_indexes , @this_years_local_time_indexes ;
32303360 }
32313361 Win32API::Registry::RegCloseKey($timezone_dst_subkey )
32323362 or Carp::croak(
@@ -3242,7 +3372,41 @@ sub _read_win32_transition_times {
32423372" Failed to open LOCAL_MACHINE\\ $timezone_specific_registry_path :$EXTENDED_OS_ERROR "
32433373 );
32443374 }
3245- return \@transition_times ;
3375+ return (
3376+ transition_times => \@transition_times ,
3377+ local_time_types => \@local_time_types ,
3378+ local_time_indexes => \@local_time_indexes ,
3379+ );
3380+ }
3381+
3382+ sub _win32_find_local_time_type {
3383+ my ( $self , $local_time_type , @local_time_types ) = @_ ;
3384+ my $index = 0;
3385+ my $found ;
3386+ foreach my $check_type (@local_time_types ) {
3387+ $index += 1;
3388+ my $match = 1;
3389+ foreach my $key (qw( abbr) ) {
3390+ if ( $check_type -> {$key } ne $local_time_type -> {$key } ) {
3391+ $match = 0;
3392+ }
3393+ }
3394+ foreach my $key (qw( gmtoff isdst) ) {
3395+ if ( $check_type -> {$key } != $local_time_type -> {$key } ) {
3396+ $match = 0;
3397+ }
3398+ }
3399+ if ($match ) {
3400+ $found = 1;
3401+ last ;
3402+ }
3403+ }
3404+ if ($found ) {
3405+ return ($index );
3406+ }
3407+ else {
3408+ return ( $index + 1, $local_time_type );
3409+ }
32463410}
32473411
32483412sub win32_mapping {
0 commit comments