Perl: afficher les transitions heures été/hiver sur la timezone
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);