KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > python > modules > time


1 // Copyright (c) Corporation for National Research Initiatives
2

3 // An implementation of the Python standard time module. Currently
4
// unimplemented:
5
//
6
// accept2dyear
7
// strptime()
8
//
9
// There may also be some incompatibilities in strftime(), because the Java
10
// tools for creating those formats don't always map to C's strftime()
11
// function.
12
//
13
// NOTE: This file is prepared for the JDK 1.2 APIs, however it is
14
// currently set up to compile cleanly under 1.1.
15
//
16
// If you would like to enable the JDK 1.2 behavior (perhaps because you
17
// are running under JDK 1.2 and would like to actually have stuff like
18
// time.tzname or time.altzone work correctly, just search for the string
19
// "XXXAPI" and stick a couple of double slashes at the beginning of each
20
// matching line.
21

22 package org.python.modules;
23
24 import org.python.core.*;
25 import java.text.DateFormatSymbols JavaDoc;
26 import java.text.DateFormat JavaDoc;
27 import java.lang.reflect.*;
28 import java.util.*;
29
30 class TimeFunctions extends PyBuiltinFunctionSet
31 {
32     public TimeFunctions(String JavaDoc name, int index, int argcount) {
33         super(name, index, argcount, argcount, false, null);
34     }
35
36     public PyObject __call__() {
37         switch (index) {
38         case 0:
39             return Py.newFloat(time.time$());
40         case 1:
41             return Py.newFloat(time.clock$());
42         default:
43             throw argCountError(0);
44         }
45     }
46 }
47
48 public class time implements ClassDictInit
49 {
50     public static PyString __doc__ = new PyString(
51         "This module provides various functions to manipulate time values.\n"+
52         "\n"+
53         "There are two standard representations of time. One is the "+
54                 "number\n"+
55         "of seconds since the Epoch, in UTC (a.k.a. GMT). It may be an "+
56                 "integer\n"+
57         "or a floating point number (to represent fractions of seconds).\n"+
58         "The Epoch is system-defined; on Unix, it is generally "+
59                 "January 1st, 1970.\n"+
60         "The actual value can be retrieved by calling gmtime(0).\n"+
61         "\n"+
62         "The other representation is a tuple of 9 integers giving "+
63                 "local time.\n"+
64         "The tuple items are:\n"+
65         " year (four digits, e.g. 1998)\n"+
66         " month (1-12)\n"+
67         " day (1-31)\n"+
68         " hours (0-23)\n"+
69         " minutes (0-59)\n"+
70         " seconds (0-59)\n"+
71         " weekday (0-6, Monday is 0)\n"+
72         " Julian day (day in the year, 1-366)\n"+
73         " DST (Daylight Savings Time) flag (-1, 0 or 1)\n"+
74         "If the DST flag is 0, the time is given in the regular time zone;\n"+
75         "if it is 1, the time is given in the DST time zone;\n"+
76         "if it is -1, mktime() should guess based on the date and time.\n"+
77         "\n"+
78         "Variables:\n"+
79         "\n"+
80         "timezone -- difference in seconds between UTC and local "+
81                 "standard time\n"+
82         "altzone -- difference in seconds between UTC and local DST time\n"+
83         "daylight -- whether local time should reflect DST\n"+
84         "tzname -- tuple of (standard time zone name, DST time zone name)\n"+
85         "\n"+
86         "Functions:\n"+
87         "\n"+
88         "time() -- return current time in seconds since the Epoch "+
89                 "as a float\n"+
90         "clock() -- return CPU time since process start as a float\n"+
91         "sleep() -- delay for a number of seconds given as a float\n"+
92         "gmtime() -- convert seconds since Epoch to UTC tuple\n"+
93         "localtime() -- convert seconds since Epoch to local time tuple\n"+
94         "asctime() -- convert time tuple to string\n"+
95         "ctime() -- convert time in seconds to string\n"+
96         "mktime() -- convert local time tuple to seconds since Epoch\n"+
97         "strftime() -- convert time tuple to string according to "+
98                 "format specification\n"+
99         "strptime() -- parse string to time tuple according to "+
100                 "format specification\n"
101     );
102
103     public static void classDictInit(PyObject dict) {
104         dict.__setitem__("time", new TimeFunctions("time", 0, 0));
105         dict.__setitem__("clock", new TimeFunctions("clock", 1, 0));
106
107         // calculate the static variables tzname, timezone, altzone, daylight
108
TimeZone tz = TimeZone.getDefault();
109
110         tzname = new PyTuple(
111             new PyObject[] {
112                 new PyString(getDisplayName(tz, false, 0)),
113                 new PyString(getDisplayName(tz, true, 0))
114             });
115
116         daylight = tz.useDaylightTime() ? 1 : 0;
117         timezone = -tz.getRawOffset() / 1000;
118         altzone = timezone - getDSTSavings(tz) / 1000;
119     }
120
121     public static double time$() {
122         return System.currentTimeMillis()/1000.0;
123     }
124
125     private static double __initialclock__ = 0.0;
126     public static double clock$() {
127         if(__initialclock__ == 0.0) {
128             // set on the first call
129
__initialclock__ = time$();
130         }
131         return time$() - __initialclock__;
132     }
133
134     private static void throwValueError(String JavaDoc msg) {
135         throw new PyException(Py.ValueError, new PyString(msg));
136     }
137
138     private static int item(PyTuple tup, int i) {
139         // knows about and asserts format on tuple items. See
140
// documentation for Python's time module for details.
141
int val = ((PyInteger)tup.__getitem__(i).__int__()).getValue();
142         boolean valid = true;
143         switch (i) {
144         case 0: break; // year
145
case 1: valid = (1 <= val && val <= 12); break; // month 1-12
146
case 2: valid = (1 <= val && val <= 31); break; // day 1 - 31
147
case 3: valid = (0 <= val && val <= 23); break; // hour 0 - 23
148
case 4: valid = (0 <= val && val <= 59); break; // minute 0 - 59
149
case 5: valid = (0 <= val && val <= 59); break; // second 0 - 59
150
case 6: valid = (0 <= val && val <= 6); break; // weekday 0 - 6
151
case 7: valid = (1 <= val && val < 367); break; // julian day 1 - 366
152
case 8: valid = (-1 <= val && val <= 1); break; // d.s. flag, -1,0,1
153
}
154         // raise a ValueError if not within range
155
if (!valid) {
156             String JavaDoc msg;
157             switch (i) {
158             case 1:
159                 msg = "month out of range (1-12)";
160                 break;
161             case 2:
162                 msg = "day out of range (1-31)";
163                 break;
164             case 3:
165                 msg = "hour out of range (0-23)";
166                 break;
167             case 4:
168                 msg = "minute out of range (0-59)";
169                 break;
170             case 5:
171                 msg = "second out of range (0-59)";
172                 break;
173             case 6:
174                 msg = "day of week out of range (0-6)";
175                 break;
176             case 7:
177                 msg = "day of year out of range (1-366)";
178                 break;
179             case 8:
180                 msg = "daylight savings flag out of range (-1,0,1)";
181                 break;
182             default:
183                 // make compiler happy
184
msg = "ignore";
185                 break;
186             }
187             throwValueError(msg);
188         }
189         // Java's months are usually 0-11
190
if (i == 1)
191             val--;
192         return val;
193     }
194
195     private static GregorianCalendar _tupletocal(PyTuple tup) {
196         return new GregorianCalendar(item(tup, 0),
197                                      item(tup, 1),
198                                      item(tup, 2),
199                                      item(tup, 3),
200                                      item(tup, 4),
201                                      item(tup, 5));
202     }
203
204     public static double mktime(PyTuple tup) {
205         GregorianCalendar cal;
206         try {
207             cal = _tupletocal(tup);
208         }
209         catch (PyException e) {
210             // CPython's mktime raises OverflowErrors... yuck!
211
e.type = Py.OverflowError;
212             throw e;
213         }
214         int dst = item(tup, 8);
215         if (dst == 0 || dst == 1) {
216             cal.set(Calendar.DST_OFFSET,
217                     dst * getDSTSavings(cal.getTimeZone()));
218         }
219         return (double)cal.getTime().getTime()/1000.0;
220     }
221
222     protected static PyTuple _timefields(double secs, TimeZone tz) {
223         GregorianCalendar cal = new GregorianCalendar(tz);
224         cal.clear();
225         cal.setTime(new Date((long)(secs*1000)));
226         // This call used to be needed to work around JVM bugs.
227
// It appears to break jdk1.2, so it's not removed.
228
// cal.clear();
229
int dow = cal.get(Calendar.DAY_OF_WEEK)-2;
230         if (dow<0)
231             dow = dow+7;
232         // TBD: is this date dst?
233
boolean isdst = tz.inDaylightTime(cal.getTime());
234         return new PyTuple(new PyObject[] {
235             new PyInteger(cal.get(Calendar.YEAR)),
236             new PyInteger(cal.get(Calendar.MONTH)+1),
237             new PyInteger(cal.get(Calendar.DAY_OF_MONTH)),
238             new PyInteger(cal.get(Calendar.HOUR) +
239                           12*cal.get(Calendar.AM_PM)),
240             new PyInteger(cal.get(Calendar.MINUTE)),
241             new PyInteger(cal.get(Calendar.SECOND)),
242             new PyInteger(dow),
243             new PyInteger(cal.get(Calendar.DAY_OF_YEAR)),
244             new PyInteger(isdst ? 1 : 0)
245         });
246     }
247
248     public static PyTuple localtime() {
249         return localtime(time$());
250     }
251
252     public static PyTuple localtime(double secs) {
253         return _timefields(secs, TimeZone.getDefault());
254     }
255
256     public static PyTuple gmtime() {
257         return gmtime(time$());
258     }
259
260     public static PyTuple gmtime(double secs) {
261         return _timefields(secs, TimeZone.getTimeZone("GMT"));
262     }
263
264     public static String JavaDoc ctime() {
265         return ctime(time$());
266     }
267
268     public static String JavaDoc ctime(double secs) {
269         return asctime(localtime(secs));
270     }
271
272     // Python's time module specifies use of current locale
273
protected static Locale currentLocale = null;
274     protected static DateFormatSymbols JavaDoc datesyms = new DateFormatSymbols JavaDoc();
275     protected static String JavaDoc[] shortdays = null;
276     protected static String JavaDoc[] shortmonths = null;
277
278     private static String JavaDoc _shortday(int dow) {
279         // we need to hand craft shortdays[] because Java and Python have
280
// different specifications. Java (undocumented) appears to be
281
// first element "", followed by 0=Sun. Python says 0=Mon
282
try {
283             if (shortdays == null) {
284                 shortdays = new String JavaDoc[7];
285                 String JavaDoc[] names = datesyms.getShortWeekdays();
286                 for (int i=0; i<6; i++)
287                     shortdays[i] = names[i+2];
288                 shortdays[6] = names[1];
289             }
290         }
291         catch (ArrayIndexOutOfBoundsException JavaDoc e) {
292             throwValueError("day of week out of range (0-6)");
293         }
294         return shortdays[dow];
295     }
296
297     private static String JavaDoc _shortmonth(int month0to11) {
298         // getShortWeekdays() returns a 13 element array with the last item
299
// being the empty string. This is also undocumented ;-/
300
try {
301             if (shortmonths == null) {
302                 shortmonths = new String JavaDoc[12];
303                 String JavaDoc[] names = datesyms.getShortMonths();
304                 for (int i=0; i<12; i++)
305                     shortmonths[i] = names[i];
306             }
307         }
308         catch (ArrayIndexOutOfBoundsException JavaDoc e) {
309             throwValueError("month out of range (1-12)");
310         }
311         return shortmonths[month0to11];
312     }
313
314     private static String JavaDoc _padint(int i, int target) {
315         String JavaDoc s = Integer.toString(i);
316         int sz = s.length();
317         if (target <= sz)
318             // no truncation
319
return s;
320         if (target == sz+1)
321             return "0"+s;
322         if (target == sz+2)
323             return "00"+s;
324         else {
325             char[] c = new char[target-sz];
326             while (target > sz) {
327                 c[target-sz] = '0';
328                 target--;
329             }
330             return new String JavaDoc(c) + s;
331         }
332     }
333
334     private static String JavaDoc _twodigit(int i) {
335         return _padint(i, 2);
336     }
337
338     private static String JavaDoc _truncyear(int year) {
339         String JavaDoc yearstr = _padint(year, 4);
340         return yearstr.substring(yearstr.length()-2, yearstr.length());
341     }
342
343     public static String JavaDoc asctime() {
344         return asctime(localtime());
345     }
346
347     public static String JavaDoc asctime(PyTuple tup) {
348         checkLocale();
349         int day = item(tup, 6);
350         int mon = item(tup, 1);
351         return _shortday(day) + " " + _shortmonth(mon) + " " +
352             _twodigit(item(tup, 2)) + " " +
353             _twodigit(item(tup, 3)) + ":" +
354             _twodigit(item(tup, 4)) + ":" +
355             _twodigit(item(tup, 5)) + " " +
356             item(tup, 0);
357     }
358
359     public static void sleep(double secs) {
360         try {
361             java.lang.Thread.sleep((long)(secs * 1000));
362         }
363         catch (java.lang.InterruptedException JavaDoc e) {
364             throw new PyException(Py.KeyboardInterrupt, "interrupted sleep");
365         }
366     }
367
368     // set by classDictInit()
369
public static int timezone;
370     public static int altzone = -1;
371     public static int daylight;
372     public static PyTuple tzname = null;
373     // TBD: should we accept 2 digit years? should we make this attribute
374
// writable but ignore its value?
375
public static final int accept2dyear = 0;
376
377     public static String JavaDoc strftime(String JavaDoc format) {
378         return strftime(format, localtime());
379     }
380
381     public static String JavaDoc strftime(String JavaDoc format, PyTuple tup) {
382         checkLocale();
383
384         String JavaDoc s = "";
385         int lastc = 0;
386         int j;
387         String JavaDoc[] syms;
388         GregorianCalendar cal = null;
389         while (lastc < format.length()) {
390             int i = format.indexOf("%", lastc);
391             if (i < 0) {
392                 // the end of the format string
393
s = s + format.substring(lastc);
394                 break;
395             }
396             if (i == format.length() - 1) {
397                 // there's a bare % at the end of the string. Python lets
398
// this go by just sticking a % at the end of the result
399
// string
400
s = s + "%";
401                 break;
402             }
403             s = s + format.substring(lastc, i);
404             i++;
405             switch (format.charAt(i)) {
406             case 'a':
407                 // abbrev weekday
408
j = item(tup, 6);
409                 s = s + _shortday(j);
410                 break;
411             case 'A':
412                 // full weekday
413
// see _shortday()
414
syms = datesyms.getWeekdays();
415                 j = item(tup, 6);
416                 if (0 <= j && j < 6)
417                     s = s + syms[j+2];
418                 else if (j== 6)
419                     s = s + syms[1];
420                 else
421                     throwValueError("day of week out of range (0 - 6)");
422                 break;
423             case 'b':
424                 // abbrev month
425
j = item(tup, 1);
426                 s = s + _shortmonth(j);
427                 break;
428             case 'B':
429                 // full month
430
syms = datesyms.getMonths();
431                 j = item(tup, 1);
432                 s = s + syms[j];
433                 break;
434             case 'c':
435                 // locale's date and time repr (essentially asctime()?)
436
s = s + asctime(tup);
437                 break;
438             case 'd':
439                 // day of month (01-31)
440
s = s + _twodigit(item(tup, 2));
441                 break;
442             case 'H':
443                 // hour (00-23)
444
s = s + _twodigit(item(tup, 3));
445                 break;
446             case 'I':
447                 // hour (01-12)
448
j = item(tup, 3) % 12;
449                 if (j == 0)
450                     j = 12; // midnight or noon
451
s = s + _twodigit(j);
452                 break;
453             case 'j':
454                 // day of year (001-366)
455
s = _padint(item(tup, 7), 3);
456                 break;
457             case 'm':
458                 // month (01-12)
459
s = s + _twodigit(item(tup, 1) + 1);
460                 break;
461             case 'M':
462                 // minute (00-59)
463
s = s + _twodigit(item(tup, 4));
464                 break;
465             case 'p':
466                 // AM/PM
467
j = item(tup, 3);
468                 syms = datesyms.getAmPmStrings();
469                 if (0 <= j && j < 12)
470                     s = s + syms[0];
471                 else if (12 <= j && j < 24)
472                     s = s + syms[1];
473                 else
474                     throwValueError("hour out of range (0-23)");
475                 break;
476             case 'S':
477                 // seconds (00-61)
478
s = s + _twodigit(item(tup, 5));
479                 break;
480             case 'U':
481                 // week of year (sunday is first day) (00-53). all days in
482
// new year preceding first sunday are considered to be in
483
// week 0
484
if (cal == null)
485                     cal = _tupletocal(tup);
486                 cal.setFirstDayOfWeek(cal.SUNDAY);
487                 cal.setMinimalDaysInFirstWeek(7);
488                 j = cal.get(cal.WEEK_OF_YEAR);
489                 if (cal.get(cal.MONTH) == cal.JANUARY && j >= 52)
490                     j = 0;
491                 s = s + _twodigit(j);
492                 break;
493             case 'w':
494                 // weekday as decimal (0=Sunday-6)
495
// tuple format has monday=0
496
j = (item(tup, 6) + 1) % 7;
497                 s = s + _twodigit(j);
498                 break;
499             case 'W':
500                 // week of year (monday is first day) (00-53). all days in
501
// new year preceding first sunday are considered to be in
502
// week 0
503
if (cal == null)
504                     cal = _tupletocal(tup);
505                 cal.setFirstDayOfWeek(cal.MONDAY);
506                 cal.setMinimalDaysInFirstWeek(7);
507                 j = cal.get(cal.WEEK_OF_YEAR);
508
509                 if (cal.get(cal.MONTH) == cal.JANUARY && j >= 52)
510                     j = 0;
511                 s = s + _twodigit(j);
512                 break;
513             case 'x':
514                 // TBD: A note about %x and %X. Python's time.strftime()
515
// by default uses the "C" locale, which is changed by
516
// using the setlocale() function. In Java, the default
517
// locale is set by user.language and user.region
518
// properties and is "en_US" by default, at least around
519
// here! Locale "en_US" differs from locale "C" in the way
520
// it represents dates and times. Eventually we might want
521
// to craft a "C" locale for Java and set JPython to use
522
// this by default, but that's too much work right now.
523
//
524
// For now, we hard code %x and %X to return values
525
// formatted in the "C" locale, i.e. the default way
526
// CPython does it. E.g.:
527
// %x == mm/dd/yy
528
// %X == HH:mm:SS
529
//
530
s = s + _twodigit(item(tup, 1) + 1) + "/" +
531                     _twodigit(item(tup, 2)) + "/" +
532                     _truncyear(item(tup, 0));
533                 break;
534             case 'X':
535                 // See comment for %x above
536
s = s + _twodigit(item(tup, 3)) + ":" +
537                     _twodigit(item(tup, 4)) + ":" +
538                     _twodigit(item(tup, 5));
539                 break;
540             case 'Y':
541                 // year w/ century
542
s = s + _padint(item(tup, 0), 4);
543                 break;
544             case 'y':
545                 // year w/o century (00-99)
546
s = s + _truncyear(item(tup, 0));
547                 break;
548             case 'Z':
549                 // timezone name
550
if (cal == null)
551                     cal = _tupletocal(tup);
552                 s = s + getDisplayName(cal.getTimeZone(),
553                         // in daylight savings time? true if == 1 -1
554
// means the information was not available;
555
// treat this as if not in dst
556
item(tup, 8) > 0, 0);
557                 break;
558             case '%':
559                 // %
560
s = s + "%";
561                 break;
562             default:
563                 // TBD: should this raise a ValueError?
564
s = s + "%" + format.charAt(i);
565                 i++;
566                 break;
567             }
568             lastc = i+1;
569             i++;
570         }
571         return s;
572     }
573
574
575     private static void checkLocale() {
576         if (!Locale.getDefault().equals(currentLocale)) {
577             currentLocale = Locale.getDefault();
578             datesyms = new DateFormatSymbols JavaDoc(currentLocale);
579             shortdays = null;
580             shortmonths = null;
581         }
582     }
583
584     private static String JavaDoc getDisplayName(TimeZone tz, boolean dst,
585                                          int style)
586     {
587         String JavaDoc version = System.getProperty("java.version");
588         if (version.compareTo("1.2") >= 0) {
589             try {
590                 Method m = tz.getClass().getMethod("getDisplayName",
591                             new Class JavaDoc[] { Boolean.TYPE, Integer.TYPE });
592                 return (String JavaDoc) m.invoke(tz, new Object JavaDoc[] {
593                             new Boolean JavaDoc(dst), new Integer JavaDoc(style) });
594             } catch (Exception JavaDoc exc) { }
595         }
596         return tz.getID();
597     }
598
599     private static int getDSTSavings(TimeZone tz) {
600         String JavaDoc version = System.getProperty("java.version");
601         if (version.compareTo("1.2") >= 0) {
602             try {
603                 Method m = tz.getClass().getMethod("getDSTSavings", (Class JavaDoc[])null);
604                 return ((Integer JavaDoc) m.invoke(tz, (Object JavaDoc[])null)).intValue();
605              } catch (Exception JavaDoc exc) { }
606         }
607         return 0;
608     }
609 }
610
Popular Tags