Perl: afficher les transitions heures été/hiver sur la timezone

De TechWik
Aller à : navigation, rechercher

Ce script affichera par exemple

 $ perl test-tz.pl 
 dim. mars 25 01:59:59 CET 2018 --> dim. mars 25 03:00:00 CEST 2018
 dim. oct. 28 02:59:59 CEST 2018 --> dim. oct. 28 02:00:00 CET 2018

script:

  1   #!/usr/bin/perl -w
  2   #
  3   # Display DST transition times
  4   #
  5   use English;
  6   use strict;
  7   use Time::Local;
  8   use POSIX qw(strftime);
  9   use Getopt::Std;
 10   #
 11   use constant VRSN => '[1.04]';
 12   use constant SECONDS_PER_DAY => (24 * 60 * 60);
 13   use constant FALSE           => 0;
 14   use constant TRUE            => 1;
 15   use constant TWO_DATES_MODE  => 0;
 16   use constant NEXT_MODE       => 1;
 17   use constant DAYS_LEFT_MODE  => 2;
 18   #
 19   # ---------------------------------------------------------------
 20   sub problem
 21   {
 22     my $msg = $_[0];
 23     my $err = $_[1];
 24     printf STDERR ("%s: %s (%d).\n",$PROGRAM_NAME,$msg,$err);
 25     printf STDERR ("\n");
 26     return($err);
 27   } # problem 
 28   #
 29   sub usage
 30   {
 31     printf STDERR 
 32       ("\nUsage: %s [-y year | -n | -d] [-e] [-u]\n\n",
 33        $PROGRAM_NAME);
 34     printf STDERR
 35       ("  -y year  - determine time changes for year; by default, the current\n");
 36     printf STDERR
 37       ("             year is used.\n");
 38     printf STDERR
 39       ("  -n       - display only the next time change.\n");
 40     printf STDERR
 41       ("  -d       - display remaining days until next time change.\n");
 42     printf STDERR
 43       ("  -u       - print this usage message on stderr and exit.\n");
 44     printf STDERR
 45       ("  -e       - print the epoch seconds rather than the formatted times\n");
 46     printf STDERR  
 47       ("             if used with -d, display integer rather than fractional\n");
 48     printf STDERR
 49       ("             days remaining until next time change.\n\n");
 50     printf STDERR
 51       ("If successful, %s returns a zero result and writes two lines on\n",
 52        $PROGRAM_NAME);
 53     printf STDERR
 54       ("stdout of this form:\n");
 55     printf STDERR
 56       ("    Sun Apr  5 01:59:59 CST 1998 --> Sun Apr  5 03:00:00 CDT 1998\n");
 57     printf STDERR
 58       ("    Sun Oct 25 01:59:59 CDT 1998 --> Sun Oct 25 01:00:00 CST 1998\n");
 59     printf STDERR
 60       ("                            OR (if using -e option)\n");
 61     printf STDERR
 62       ("    891763199 --> 891763200\n");
 63     printf STDERR
 64       ("    909298799 --> 909298800\n\n");
 65     printf STDERR
 66       ("These indicate the time displayed at the transition time and that\n");
 67     printf STDERR
 68       ("displayed 1 second later.\n\n");
 69     printf STDERR
 70       ("A non-zero result is returned if no TZ is known or no time transition\n");
 71     printf STDERR
 72       ("occurs.\n\n");
 73     printf STDERR
 74       ("Vrsn %s\n",VRSN);
 75     return(1);
 76   } # usage
 77   #
 78   sub find_dst # returns the last epoch second $target_isdst is in effect
 79   {
 80     use integer;
 81     my $lo = $_[0];
 82     my $max_hi = $_[1];
 83     my $initial_interval = $_[2];
 84     my $target_isdst = $_[3];
 85     my ($begin_seconds,$next_seconds) = (-1,-1);
 86     my $isdst = FALSE;
 87     # advance by one interval until DST changes
 88     my $hi = $lo;
 89     my $fnd = FALSE;
 90     my $hi_knt = 0;
 91     while (!($fnd) && ($hi <= $max_hi) && ($hi_knt < 2))
 92       {
 93         $isdst = (localtime($hi))[8];
 94         if ($isdst != $target_isdst)
 95           {
 96             $fnd = TRUE;
 97           }
 98         else
 99           {
100             $lo = $hi;
101             $hi += $initial_interval;
102             if ($hi > $max_hi)
103               {
104                 $hi = $max_hi; 
105                 ++$hi_knt;
106               }
107           }
108       }
109     if ($fnd) # now start looking within $interval
110       {
111         my $go_down = TRUE;
112         my $tmp_seconds = $hi;
113         my $interval = ($hi - $lo) / 2;
114         while ($interval > 0)
115           {
116             if ($go_down)
117               {
118                 $tmp_seconds = $hi - $interval;
119                 $isdst = (localtime($tmp_seconds))[8];
120                 if ($isdst == $target_isdst)
121                   {
122                     $go_down = FALSE;
123                     $lo = $tmp_seconds;
124                   }
125                 else
126                   {
127                     $hi = $tmp_seconds;
128                   }
129               }
130             else
131               {
132                 $tmp_seconds = $lo + $interval;
133                 $isdst = (localtime($tmp_seconds))[8];
134                 if ($isdst != $target_isdst)
135                   {
136                     $go_down = TRUE;
137                     $hi = $tmp_seconds;
138                   }
139                 else
140                   {
141                     $lo = $tmp_seconds;
142                   }
143               }
144             $interval = ($hi - $lo) / 2;
145           }
146         if (((localtime($tmp_seconds))[8]) !=
147             ((localtime($tmp_seconds + 1))[8]))
148           {
149             $begin_seconds = $tmp_seconds;
150             $next_seconds = $tmp_seconds + 1;
151           }
152         else
153           {
154             $begin_seconds = $tmp_seconds - 1;
155             $next_seconds = $tmp_seconds;
156           }
157       }
158     return($begin_seconds,$next_seconds);
159   } # find_dst
160   #
161   my $year = -1;
162   my $cc = 0;
163   my $do_format = TRUE;
164   my $yr_arg_knt = 0;
165   my $mode = TWO_DATES_MODE;
166   my $now = 0;
167   #
168   our ($opt_y,$opt_n,$opt_d,$opt_u,$opt_e);
169   #
170   if (!getopts('y:ndue'))
171     {
172       $cc = 252;
173       usage();
174       exit($cc);
175     }
176   if (defined($opt_y))
177     {
178       $year = $opt_y - 1900;
179       ++$yr_arg_knt;
180     }
181   if (defined($opt_n))
182     {
183       $mode = NEXT_MODE;
184       ++$yr_arg_knt;
185     }
186   if (defined($opt_d))
187     {
188       $mode = DAYS_LEFT_MODE;
189       ++$yr_arg_knt;
190     }
191   if (defined($opt_e))
192     {
193       $do_format = FALSE;
194     }
195   if (defined($opt_u))
196     {
197       $cc = 251;
198       usage();
199       exit($cc);
200     }
201   if ($yr_arg_knt > 1 && $cc == 0)
202     {
203       $cc = 255;
204       problem("Only one -n or -y argument allowed",$cc);
205     }
206   if ($year <= 0)
207     {
208       $now = time(); 
209       $year = (localtime($now))[5];
210     }
211   if ($cc != 0)
212     {
213       exit($cc);
214     }
215   $cc = 2;
216   #
217   if (($mode == NEXT_MODE) || ($mode == DAYS_LEFT_MODE))
218     {
219       my $isdst_now = (localtime($now))[8];
220       my $seconds_Dec31 = timelocal(59,59,23,31,11,$year + 1);
221       my ($start1,$start2) = find_dst($now,$seconds_Dec31,
222                                       SECONDS_PER_DAY,$isdst_now);
223       if ($start1 > 0)
224         {
225           if ($mode == NEXT_MODE)
226             {
227               if ($do_format)
228                 {
229                   print strftime("%a %b %d %H:%M:%S %Z %Y",localtime($start1)),
230                         " --> ",
231                         strftime("%a %b %d %H:%M:%S %Z %Y",localtime($start2)),
232                         "\n";
233                 }
234               else
235                 {
236                   print $start1," --> ",$start2,"\n";
237                 }
238             }
239           else
240             {
241               if ($do_format)
242                 {
243                   printf("%.4f\n",(($start2 - $now) / SECONDS_PER_DAY));
244                 }
245               else
246                 {
247                   printf("%d\n",int(($start2 - $now) / SECONDS_PER_DAY));
248                 }
249             } 
250           $cc = 0;
251         }
252     }
253   else
254     {
255       my $seconds_Jan1 = timelocal(0,0,0,1,0,$year);
256       my $isdst_Jan1 = (localtime($seconds_Jan1))[8];
257       my $seconds_Dec31 = timelocal(59,59,23,31,11,$year);
258 
259       my ($start1,$start2) = find_dst($seconds_Jan1,$seconds_Dec31,
260                                       SECONDS_PER_DAY,$isdst_Jan1);
261       if ($start1 > 0)
262         {
263           $cc = 1;
264           if ($do_format)
265             {
266               print strftime("%a %b %d %H:%M:%S %Z %Y",localtime($start1)),
267                     " --> ",
268                     strftime("%a %b %d %H:%M:%S %Z %Y",localtime($start2)),
269                     "\n";
270             }
271           else
272             {
273               print $start1," --> ",$start2,"\n";
274             }
275           my ($end1,$end2) = find_dst($start2,$seconds_Dec31,
276                                       SECONDS_PER_DAY,!($isdst_Jan1));
277           if ($end1 > 0)
278             {
279               if ($do_format)
280                 {
281                   print strftime("%a %b %d %H:%M:%S %Z %Y",localtime($end1)),
282                         " --> ",
283                         strftime("%a %b %d %H:%M:%S %Z %Y",localtime($end2)),
284                         "\n";
285                 }
286               else
287                 {
288                   print $end1," --> ",$end2,"\n";
289                 }
290               $cc = 0;
291             }
292         }
293     }
294   exit($cc);