c9bdf9c27adf3bf101799ca3963fb4059b507446
[platform/upstream/nspr.git] / nspr / pr / tests / timetest.c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 /*
7  * file: timetest.c
8  * description: test time and date routines
9  */
10 /***********************************************************************
11 ** Includes
12 ***********************************************************************/
13 /* Used to get the command line option */
14 #include "plgetopt.h"
15
16 #include "prinit.h"
17 #include "prtime.h"
18 #include "prprf.h"
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 int failed_already=0;
25 PRBool debug_mode = PR_FALSE;
26
27 static char *dayOfWeek[] =
28         { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "???" };
29 static char *month[] =
30         { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
31           "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" };
32
33 static void PrintExplodedTime(const PRExplodedTime *et) {
34     PRInt32 totalOffset;
35     PRInt32 hourOffset, minOffset;
36     const char *sign;
37
38     /* Print day of the week, month, day, hour, minute, and second */
39     if (debug_mode) printf("%s %s %ld %02ld:%02ld:%02ld ",
40             dayOfWeek[et->tm_wday], month[et->tm_month], et->tm_mday,
41             et->tm_hour, et->tm_min, et->tm_sec);
42
43     /* Print time zone */
44     totalOffset = et->tm_params.tp_gmt_offset + et->tm_params.tp_dst_offset;
45     if (totalOffset == 0) {
46         if (debug_mode) printf("UTC ");
47     } else {
48         sign = "+";
49         if (totalOffset < 0) {
50             totalOffset = -totalOffset;
51             sign = "-";
52         }
53         hourOffset = totalOffset / 3600;
54         minOffset = (totalOffset % 3600) / 60;
55         if (debug_mode) 
56             printf("%s%02ld%02ld ", sign, hourOffset, minOffset);
57     }
58
59     /* Print year */
60     if (debug_mode) printf("%hd", et->tm_year);
61 }
62
63 static int ExplodedTimeIsEqual(const PRExplodedTime *et1,
64         const PRExplodedTime *et2)
65 {
66     if (et1->tm_usec == et2->tm_usec &&
67             et1->tm_sec == et2->tm_sec &&
68             et1->tm_min == et2->tm_min &&
69             et1->tm_hour == et2->tm_hour &&
70             et1->tm_mday == et2->tm_mday &&
71             et1->tm_month == et2->tm_month &&
72             et1->tm_year == et2->tm_year &&
73             et1->tm_wday == et2->tm_wday &&
74             et1->tm_yday == et2->tm_yday &&
75             et1->tm_params.tp_gmt_offset == et2->tm_params.tp_gmt_offset &&
76             et1->tm_params.tp_dst_offset == et2->tm_params.tp_dst_offset) {
77         return 1;
78     } else {
79         return 0;
80     }
81 }
82
83 static void
84 testParseTimeString(PRTime t)
85 {
86     PRExplodedTime et;
87     PRTime t2;
88     char timeString[128];
89     char buf[128];
90     PRInt32 totalOffset;
91     PRInt32 hourOffset, minOffset;
92     const char *sign;
93     PRInt64 usec_per_sec;
94
95     /* Truncate the microsecond part of PRTime */
96     LL_I2L(usec_per_sec, PR_USEC_PER_SEC);
97     LL_DIV(t, t, usec_per_sec);
98     LL_MUL(t, t, usec_per_sec);
99
100     PR_ExplodeTime(t, PR_LocalTimeParameters, &et);
101
102     /* Print day of the week, month, day, hour, minute, and second */
103     PR_snprintf(timeString, 128, "%s %s %ld %02ld:%02ld:%02ld ",
104             dayOfWeek[et.tm_wday], month[et.tm_month], et.tm_mday,
105             et.tm_hour, et.tm_min, et.tm_sec);
106     /* Print time zone */
107     totalOffset = et.tm_params.tp_gmt_offset + et.tm_params.tp_dst_offset;
108     if (totalOffset == 0) {
109         strcat(timeString, "GMT ");  /* I wanted to use "UTC" here, but
110                                       * PR_ParseTimeString doesn't 
111                                       * understand "UTC".  */
112     } else {
113         sign = "+";
114         if (totalOffset < 0) {
115             totalOffset = -totalOffset;
116             sign = "-";
117         }
118         hourOffset = totalOffset / 3600;
119         minOffset = (totalOffset % 3600) / 60;
120         PR_snprintf(buf, 128, "%s%02ld%02ld ", sign, hourOffset, minOffset);
121         strcat(timeString, buf);
122     }
123     /* Print year */
124     PR_snprintf(buf, 128, "%hd", et.tm_year);
125     strcat(timeString, buf);
126
127     if (PR_ParseTimeString(timeString, PR_FALSE, &t2) == PR_FAILURE) {
128         fprintf(stderr, "PR_ParseTimeString() failed\n");
129         exit(1);
130     }
131     if (LL_NE(t, t2)) {
132         fprintf(stderr, "PR_ParseTimeString() incorrect\n");
133         PR_snprintf(buf, 128, "t is %lld, t2 is %lld, time string is %s\n",
134                 t, t2, timeString);
135         fprintf(stderr, "%s\n", buf);
136         exit(1);
137     }
138 }
139
140 int main(int argc, char** argv)
141 {
142         /* The command line argument: -d is used to determine if the test is being run
143         in debug mode. The regress tool requires only one line output:PASS or FAIL.
144         All of the printfs associated with this test has been handled with a if (debug_mode)
145         test.
146         Usage: test_name -d
147         */
148         PLOptStatus os;
149         PLOptState *opt;
150     
151     PR_STDIO_INIT();
152         opt = PL_CreateOptState(argc, argv, "d");
153         while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
154     {
155                 if (PL_OPT_BAD == os) continue;
156         switch (opt->option)
157         {
158         case 'd':  /* debug mode */
159                         debug_mode = PR_TRUE;
160             break;
161          default:
162             break;
163         }
164     }
165         PL_DestroyOptState(opt);
166
167  /* main test */
168         
169     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
170
171     /* Testing zero PRTime (the epoch) */
172     {
173         PRTime t;
174         PRExplodedTime et;
175
176         LL_I2L(t, 0);
177         if (debug_mode) printf("The NSPR epoch is:\n");
178         PR_ExplodeTime(t, PR_LocalTimeParameters, &et);
179         PrintExplodedTime(&et);
180         if (debug_mode) printf("\n");
181         PR_ExplodeTime(t, PR_GMTParameters, &et);
182         PrintExplodedTime(&et);
183         if (debug_mode) printf("\n\n");
184         testParseTimeString(t);
185     }
186
187     /*
188      *************************************************************
189      **
190      **  Testing PR_Now(), PR_ExplodeTime, and PR_ImplodeTime
191      **  on the current time
192      **
193      *************************************************************
194      */
195
196     {
197         PRTime t1, t2;
198         PRExplodedTime et;
199
200         if (debug_mode) {
201         printf("*********************************************\n");
202         printf("**                                         **\n");
203     printf("** Testing PR_Now(), PR_ExplodeTime, and   **\n");
204         printf("** PR_ImplodeTime on the current time      **\n");
205         printf("**                                         **\n");
206         printf("*********************************************\n\n");
207         }
208         t1 = PR_Now();
209
210         /* First try converting to UTC */
211
212         PR_ExplodeTime(t1, PR_GMTParameters, &et);
213         if (et.tm_params.tp_gmt_offset || et.tm_params.tp_dst_offset) {
214             if (debug_mode) printf("ERROR: UTC has nonzero gmt or dst offset.\n");
215                 else failed_already=1;
216             return 1;
217         }
218         if (debug_mode) printf("Current UTC is ");
219         PrintExplodedTime(&et);
220         if (debug_mode) printf("\n");
221
222         t2 = PR_ImplodeTime(&et);
223         if (LL_NE(t1, t2)) {
224             if (debug_mode) printf("ERROR: Explode and implode are NOT inverse.\n");
225                 else printf("FAIL\n");
226             return 1;
227         }
228
229         /* Next, try converting to local (US Pacific) time */
230
231         PR_ExplodeTime(t1, PR_LocalTimeParameters, &et);
232         if (debug_mode) printf("Current local time is ");
233         PrintExplodedTime(&et);
234         if (debug_mode) printf("\n");
235         if (debug_mode) printf("GMT offset is %ld, DST offset is %ld\n",
236                 et.tm_params.tp_gmt_offset, et.tm_params.tp_dst_offset);
237         t2 = PR_ImplodeTime(&et);
238         if (LL_NE(t1, t2)) {
239             if (debug_mode) printf("ERROR: Explode and implode are NOT inverse.\n");
240             return 1;
241         }
242
243         if (debug_mode) printf("Please examine the results\n");
244         testParseTimeString(t1);
245     }
246
247
248     /*
249      *******************************************
250      **
251      ** Testing PR_NormalizeTime()
252      **
253      *******************************************
254      */
255
256     /* July 4, 2001 is Wednesday */
257     {
258         PRExplodedTime et;
259
260         if (debug_mode)  {
261         printf("\n");
262         printf("**********************************\n");
263         printf("**                              **\n");
264         printf("** Testing PR_NormalizeTime()   **\n");
265         printf("**                              **\n");
266         printf("**********************************\n\n");
267         }
268         et.tm_year    = 2001;
269         et.tm_month   = 7 - 1;
270         et.tm_mday    = 4;
271         et.tm_hour    = 0;
272         et.tm_min     = 0;
273         et.tm_sec     = 0;
274         et.tm_usec    = 0;
275         et.tm_params  = PR_GMTParameters(&et);
276
277         PR_NormalizeTime(&et, PR_GMTParameters);
278
279         if (debug_mode) printf("July 4, 2001 is %s.\n", dayOfWeek[et.tm_wday]);
280         if (et.tm_wday == 3) {
281             if (debug_mode) printf("PASS\n");
282         } else {
283             if (debug_mode) printf("ERROR: It should be Wednesday\n");
284                         else failed_already=1;
285             return 1;
286         }
287         testParseTimeString(PR_ImplodeTime(&et));
288
289         /* June 12, 1997 23:00 PST == June 13, 1997 00:00 PDT */
290         et.tm_year    = 1997;
291         et.tm_month   = 6 - 1;
292         et.tm_mday    = 12;
293         et.tm_hour    = 23;
294         et.tm_min     = 0;
295         et.tm_sec     = 0;
296         et.tm_usec    = 0;
297         et.tm_params.tp_gmt_offset = -8 * 3600;
298         et.tm_params.tp_dst_offset = 0;
299
300         PR_NormalizeTime(&et, PR_USPacificTimeParameters);
301
302         if (debug_mode) {
303             printf("Thu Jun 12, 1997 23:00:00 PST is ");
304         }
305         PrintExplodedTime(&et);
306         if (debug_mode) printf(".\n");
307         if (et.tm_wday == 5) {
308             if (debug_mode) printf("PASS\n");
309         } else {
310             if (debug_mode) printf("ERROR: It should be Friday\n");
311                         else failed_already=1;
312             return 1;
313         }
314         testParseTimeString(PR_ImplodeTime(&et));
315
316         /* Feb 14, 1997 00:00:00 PDT == Feb 13, 1997 23:00:00 PST */
317         et.tm_year    = 1997;
318         et.tm_month   = 2 - 1;
319         et.tm_mday    = 14;
320         et.tm_hour    = 0;
321         et.tm_min     = 0;
322         et.tm_sec     = 0;
323         et.tm_usec    = 0;
324         et.tm_params.tp_gmt_offset = -8 * 3600;
325         et.tm_params.tp_dst_offset = 3600;
326
327         PR_NormalizeTime(&et, PR_USPacificTimeParameters);
328
329         if (debug_mode) {
330             printf("Fri Feb 14, 1997 00:00:00 PDT is ");
331         }
332         PrintExplodedTime(&et);
333         if (debug_mode) printf(".\n");
334         if (et.tm_wday == 4) {
335             if (debug_mode) printf("PASS\n");
336         } else {
337             if (debug_mode) printf("ERROR: It should be Thursday\n");
338                         else failed_already=1;
339             return 1;
340         }
341         testParseTimeString(PR_ImplodeTime(&et));
342
343         /* What time is Nov. 7, 1996, 18:29:23 PDT? */
344         et.tm_year    = 1996;
345         et.tm_month   = 11 - 1;
346         et.tm_mday    = 7;
347         et.tm_hour    = 18;
348         et.tm_min     = 29;
349         et.tm_sec     = 23;
350         et.tm_usec    = 0;
351         et.tm_params.tp_gmt_offset = -8 * 3600;  /* PDT */
352         et.tm_params.tp_dst_offset = 3600; 
353
354         PR_NormalizeTime(&et, PR_LocalTimeParameters);
355         if (debug_mode) printf("Nov 7 18:29:23 PDT 1996 is ");
356         PrintExplodedTime(&et);
357         if (debug_mode) printf(".\n");
358         testParseTimeString(PR_ImplodeTime(&et));
359
360         /* What time is Oct. 7, 1995, 18:29:23 PST? */
361         et.tm_year    = 1995;
362         et.tm_month   = 10 - 1;
363         et.tm_mday    = 7;
364         et.tm_hour    = 18;
365         et.tm_min     = 29;
366         et.tm_sec     = 23;
367         et.tm_params.tp_gmt_offset = -8 * 3600;  /* PST */
368         et.tm_params.tp_dst_offset = 0;
369
370         PR_NormalizeTime(&et, PR_LocalTimeParameters);
371         if (debug_mode) printf("Oct 7 18:29:23 PST 1995 is ");
372         PrintExplodedTime(&et);
373         if (debug_mode) printf(".\n");
374         testParseTimeString(PR_ImplodeTime(&et));
375
376         if (debug_mode) printf("Please examine the results\n");
377     }
378
379     /*
380      **************************************************************
381      **
382      ** Testing range of years
383      **
384      **************************************************************
385      */
386
387     {
388         PRExplodedTime et1, et2;
389     PRTime  ttt;
390         PRTime secs;
391
392         if (debug_mode) {
393         printf("\n");
394         printf("***************************************\n");
395         printf("**                                   **\n");
396         printf("**  Testing range of years           **\n");
397         printf("**                                   **\n");
398         printf("***************************************\n\n");
399         }
400         /* April 4, 1917 GMT */
401         et1.tm_usec = 0;
402         et1.tm_sec = 0;
403         et1.tm_min = 0;
404         et1.tm_hour = 0;
405         et1.tm_mday = 4;
406         et1.tm_month = 4 - 1;
407         et1.tm_year = 1917;
408         et1.tm_params = PR_GMTParameters(&et1);
409         PR_NormalizeTime(&et1, PR_LocalTimeParameters);
410         secs = PR_ImplodeTime(&et1);
411         if (LL_GE_ZERO(secs)) {
412             if (debug_mode)
413                 printf("ERROR: April 4, 1917 GMT returns a nonnegative second count\n");
414                 failed_already = 1;
415             return 1;
416         }
417         PR_ExplodeTime(secs, PR_LocalTimeParameters, &et2);
418         if (!ExplodedTimeIsEqual(&et1, &et2)) {
419                 if (debug_mode)
420                 printf("ERROR: PR_ImplodeTime and PR_ExplodeTime are not inverse for April 4, 1917 GMT\n");
421                 failed_already=1;
422             return 1;
423         }
424     ttt = PR_ImplodeTime(&et1);
425         testParseTimeString( ttt );
426
427         if (debug_mode) printf("Test passed for April 4, 1917\n");
428
429         /* July 4, 2050 */
430         et1.tm_usec = 0;
431         et1.tm_sec = 0;
432         et1.tm_min = 0;
433         et1.tm_hour = 0;
434         et1.tm_mday = 4;
435         et1.tm_month = 7 - 1;
436         et1.tm_year = 2050;
437         et1.tm_params = PR_GMTParameters(&et1);
438         PR_NormalizeTime(&et1, PR_LocalTimeParameters);
439         secs = PR_ImplodeTime(&et1);
440         if (!LL_GE_ZERO(secs)) {
441             if (debug_mode)
442                         printf("ERROR: July 4, 2050 GMT returns a negative second count\n");
443                 failed_already = 1;
444             return 1;
445         }
446         PR_ExplodeTime(secs, PR_LocalTimeParameters, &et2);
447         if (!ExplodedTimeIsEqual(&et1, &et2)) {
448             if (debug_mode)
449                 printf("ERROR: PR_ImplodeTime and PR_ExplodeTime are not inverse for July 4, 2050 GMT\n");
450                 failed_already=1;
451             return 1;
452         }
453         testParseTimeString(PR_ImplodeTime(&et1));
454
455         if (debug_mode) printf("Test passed for July 4, 2050\n");
456
457     }
458
459     /*
460      **************************************************************
461      **
462      **  Stress test
463      *
464      **      Go through four years, starting from
465      **      00:00:00 PST Jan. 1, 2005, incrementing
466      **      every 10 minutes.
467      **
468      **************************************************************
469      */
470
471     {
472         PRExplodedTime et, et1, et2;
473         PRInt64 usecPer10Min;
474         int day, hour, min;
475         PRTime usecs;
476         int dstInEffect = 0;
477
478         if (debug_mode) {
479         printf("\n");
480         printf("*******************************************************\n");
481         printf("**                                                   **\n");
482         printf("**        Stress test  Pacific Time                  **\n");
483         printf("**  Starting from midnight Jan. 1, 2005 PST,         **\n");
484         printf("**  going through four years in 10-minute increment  **\n");
485         printf("**                                                   **\n");
486         printf("*******************************************************\n\n");
487         }
488         LL_I2L(usecPer10Min, 600000000L);
489
490         /* 00:00:00 PST Jan. 1, 2005 */
491         et.tm_usec = 0;
492         et.tm_sec = 0;
493         et.tm_min = 0;
494         et.tm_hour = 0;
495         et.tm_mday = 1;
496         et.tm_month = 0;
497         et.tm_year = 2005;
498         et.tm_params.tp_gmt_offset = -8 * 3600;
499         et.tm_params.tp_dst_offset = 0;
500         usecs = PR_ImplodeTime(&et);
501
502         for (day = 0; day < 4 * 365 + 1; day++) {
503             for (hour = 0; hour < 24; hour++) {
504                 for (min = 0; min < 60; min += 10) {
505                     LL_ADD(usecs, usecs, usecPer10Min);
506                     PR_ExplodeTime(usecs, PR_USPacificTimeParameters, &et1);
507
508                     et2 = et;
509                     et2.tm_usec += 600000000L;
510                     PR_NormalizeTime(&et2, PR_USPacificTimeParameters);
511
512                     if (!ExplodedTimeIsEqual(&et1, &et2)) {
513                         printf("ERROR: componentwise comparison failed\n");
514                         PrintExplodedTime(&et1);
515                         printf("\n");
516                         PrintExplodedTime(&et2);
517                         printf("\n");
518                         failed_already=1;
519                         return 1;
520                     }
521
522                     if (LL_NE(usecs, PR_ImplodeTime(&et1))) { 
523                         printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n");
524                         PrintExplodedTime(&et1);
525                         printf("\n");
526                         failed_already=1;
527                         return 1;
528                     }
529                     testParseTimeString(usecs);
530
531                     if (!dstInEffect && et1.tm_params.tp_dst_offset) {
532                         dstInEffect = 1;
533                         if (debug_mode) {
534                             printf("DST changeover from ");
535                             PrintExplodedTime(&et);
536                             printf(" to ");
537                             PrintExplodedTime(&et1);
538                             printf(".\n");
539                         }
540                     } else if (dstInEffect && !et1.tm_params.tp_dst_offset) {
541                         dstInEffect = 0;
542                         if (debug_mode) {
543                             printf("DST changeover from ");
544                             PrintExplodedTime(&et);
545                             printf(" to ");
546                             PrintExplodedTime(&et1);
547                             printf(".\n");
548                         }
549                     }
550
551                     et = et1;
552                 }
553             }
554         }
555         if (debug_mode) printf("Test passed\n");
556     }
557
558
559     /* Same stress test, but with PR_LocalTimeParameters */
560
561     {
562         PRExplodedTime et, et1, et2;
563         PRInt64 usecPer10Min;
564         int day, hour, min;
565         PRTime usecs;
566         int dstInEffect = 0;
567
568         if (debug_mode) {
569         printf("\n");
570         printf("*******************************************************\n");
571         printf("**                                                   **\n");
572         printf("**         Stress test    Local Time                 **\n");
573         printf("**  Starting from midnight Jan. 1, 2005 PST,         **\n");
574         printf("**  going through four years in 10-minute increment  **\n");
575         printf("**                                                   **\n");
576         printf("*******************************************************\n\n");
577         }
578         
579         LL_I2L(usecPer10Min, 600000000L);
580
581         /* 00:00:00 PST Jan. 1, 2005 */
582         et.tm_usec = 0;
583         et.tm_sec = 0;
584         et.tm_min = 0;
585         et.tm_hour = 0;
586         et.tm_mday = 1;
587         et.tm_month = 0;
588         et.tm_year = 2005;
589         et.tm_params.tp_gmt_offset = -8 * 3600;
590         et.tm_params.tp_dst_offset = 0;
591         usecs = PR_ImplodeTime(&et);
592
593         for (day = 0; day < 4 * 365 + 1; day++) {
594             for (hour = 0; hour < 24; hour++) {
595                 for (min = 0; min < 60; min += 10) {
596                     LL_ADD(usecs, usecs, usecPer10Min);
597                     PR_ExplodeTime(usecs, PR_LocalTimeParameters, &et1);
598
599                     et2 = et;
600                     et2.tm_usec += 600000000L;
601                     PR_NormalizeTime(&et2, PR_LocalTimeParameters);
602
603                     if (!ExplodedTimeIsEqual(&et1, &et2)) {
604                         printf("ERROR: componentwise comparison failed\n");
605                         PrintExplodedTime(&et1);
606                         printf("\n");
607                         PrintExplodedTime(&et2);
608                         printf("\n");
609                         return 1;
610                     }
611
612                     if (LL_NE(usecs, PR_ImplodeTime(&et1))) {
613                         printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n");
614                         PrintExplodedTime(&et1);
615                         printf("\n");
616                         failed_already=1;
617                         return 1;
618                     }
619                     testParseTimeString(usecs);
620
621                     if (!dstInEffect && et1.tm_params.tp_dst_offset) {
622                         dstInEffect = 1;
623                         if (debug_mode) {
624                             printf("DST changeover from ");
625                             PrintExplodedTime(&et);
626                             printf(" to ");
627                             PrintExplodedTime(&et1);
628                             printf(".\n");
629                         }
630                     } else if (dstInEffect && !et1.tm_params.tp_dst_offset) {
631                         dstInEffect = 0;
632                         if (debug_mode) {
633                             printf("DST changeover from ");
634                             PrintExplodedTime(&et);
635                             printf(" to ");
636                             PrintExplodedTime(&et1);
637                             printf(".\n");
638                         }
639                     }
640
641                     et = et1;
642                 }
643             }
644         }
645         if (debug_mode) printf("Test passed\n");
646     }
647
648     /* Same stress test, but with PR_LocalTimeParameters and going backward */
649
650     {
651         PRExplodedTime et, et1, et2;
652         PRInt64 usecPer10Min;
653         int day, hour, min;
654         PRTime usecs;
655         int dstInEffect = 0;
656
657         if (debug_mode) {
658         printf("\n");
659         printf("*******************************************************\n");
660         printf("**                                                   **\n");
661         printf("**           Stress test    Local Time               **\n");
662         printf("**  Starting from midnight Jan. 1, 2009 PST,         **\n");
663         printf("**  going back four years in 10-minute increment     **\n");
664         printf("**                                                   **\n");
665         printf("*******************************************************\n\n");
666         }
667
668         LL_I2L(usecPer10Min, 600000000L);
669
670         /* 00:00:00 PST Jan. 1, 2009 */
671         et.tm_usec = 0;
672         et.tm_sec = 0;
673         et.tm_min = 0;
674         et.tm_hour = 0;
675         et.tm_mday = 1;
676         et.tm_month = 0;
677         et.tm_year = 2009;
678         et.tm_params.tp_gmt_offset = -8 * 3600;
679         et.tm_params.tp_dst_offset = 0;
680         usecs = PR_ImplodeTime(&et);
681
682         for (day = 0; day < 4 * 365 + 1; day++) {
683             for (hour = 0; hour < 24; hour++) {
684                 for (min = 0; min < 60; min += 10) {
685                     LL_SUB(usecs, usecs, usecPer10Min);
686                     PR_ExplodeTime(usecs, PR_LocalTimeParameters, &et1);
687
688                     et2 = et;
689                     et2.tm_usec -= 600000000L;
690                     PR_NormalizeTime(&et2, PR_LocalTimeParameters);
691
692                     if (!ExplodedTimeIsEqual(&et1, &et2)) {
693                         printf("ERROR: componentwise comparison failed\n");
694                         PrintExplodedTime(&et1);
695                         printf("\n");
696                         PrintExplodedTime(&et2);
697                         printf("\n");
698                         return 1;
699                     }
700
701                     if (LL_NE(usecs, PR_ImplodeTime(&et1))) {
702                         printf("ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n");
703                         PrintExplodedTime(&et1);
704                         printf("\n");
705                         failed_already=1;
706                         return 1;
707                     }
708                     testParseTimeString(usecs);
709
710                     if (!dstInEffect && et1.tm_params.tp_dst_offset) {
711                         dstInEffect = 1;
712                         if (debug_mode) {
713                             printf("DST changeover from ");
714                             PrintExplodedTime(&et);
715                             printf(" to ");
716                             PrintExplodedTime(&et1);
717                             printf(".\n");
718                         }
719                     } else if (dstInEffect && !et1.tm_params.tp_dst_offset) {
720                         dstInEffect = 0;
721                         if (debug_mode) {
722                             printf("DST changeover from ");
723                             PrintExplodedTime(&et);
724                             printf(" to ");
725                             PrintExplodedTime(&et1);
726                             printf(".\n");
727                         }
728                     }
729
730                     et = et1;
731                 }
732             }
733         }
734     }
735
736         if (failed_already) return 1;
737         else return 0;
738
739 }