View Javadoc

1   package edu.iris.Fissures.model;
2   
3   import java.text.DateFormat;
4   import java.text.DecimalFormat;
5   import java.text.ParsePosition;
6   import java.text.SimpleDateFormat;
7   import java.util.Calendar;
8   import java.util.Date;
9   import java.util.TimeZone;
10  
11  /***
12   * ISOTime.java Created: Fri Jul 9 13:45:39 1999
13   * 
14   * @author Philip Crotwell
15   * @version
16   */
17  public class ISOTime {
18  
19      /***
20       * parses a ISO8601 string into its component parts. Currently we only
21       * support the 4 month based, full formats, <break>
22       * yyyy-mm-ddThh:mm:ss.ddddZTD <BREAK>yyyy-mm-ddThhmmss.ddddZTD <BREAK>
23       * yyyymmddThh:mm:ss.ddddZTD <BREAK>yyyymmddThhmmss.ddddZTD, <BREAK>plus the
24       * similar julian day formats, <BREAK>yyyyjjjThh:mm:ss.ddddZTD and
25       * yyyyjjjThhmmss.ddddZTD. The time zone part, ZTD, is either Z for zulu, ie
26       * UTC, or a offset from UTC in the form of +hh:mm or -hh:mm.
27       */
28      public ISOTime(String s) throws UnsupportedFormat {
29          orig = s;
30          // check for TIME_UNKNOWN and default DMC 2599 values
31          if(s.equals(edu.iris.Fissures.TIME_UNKNOWN.value)
32                  || s.equals("25991231235959.0000GMT")) {
33              date = TimeUtils.future;
34          } else {
35              String clean = cleanDate(s);
36              Date d = null;
37              for(int i = 0; i < dateFormats.length; i++) {
38                  synchronized(dateFormats[i]) {
39                      d = dateFormats[i].parse(clean, new ParsePosition(0));
40                  }
41                  if(d != null) {
42                      break;
43                  }
44              }
45              if(d == null) {
46                  // no patterns worked
47                  throw new UnsupportedFormat(s);
48              }
49              date = new MicroSecondDate(d);
50          } // end of else
51      }
52  
53      public ISOTime(int year, int jday, int hour, int minute, float second) {
54          this(getISOString(year, jday, hour, minute, second));
55      }
56  
57      public static String getISOString(int year,
58                                        int jday,
59                                        int hour,
60                                        int minute,
61                                        float second) {
62          DecimalFormat xxFormat = new DecimalFormat("00");
63          DecimalFormat xxxFormat = new DecimalFormat("000");
64          DecimalFormat floatFormat = new DecimalFormat("00.000#");
65          return xxxFormat.format(year) + xxxFormat.format(jday) + "T"
66                  + xxFormat.format(hour) + xxFormat.format(minute)
67                  + floatFormat.format(second) + "Z";
68      }
69  
70      private static final DateFormat[] dateFormats;
71  
72      public static final String[] patterns = {"yyyyDDD'J'HHmmss.SSSz",
73                                               "yyyyMMddHHmmss.SSSz",
74                                               "yyyyMMdd'T'HH:mm:ss.SSSz",
75                                               "yyyy-MM-dd'T'HH:mm:ss.SSSz",
76                                               "yyyyDDD'J'HH:mm:ss.SSSz",
77                                               "yyyyMMdd'T'HHmmss.SSSz",
78                                               "yyyy-MM-dd'T'HHmmss.SSSz",
79                                               "yyyyMMdd HH:mm:ss.SSSz",
80                                               "yyyyMMdd HHmmss.SSSz",
81                                               "yyyy-MM-dd HH:mm:ss.SSSz",
82                                               "yyyy-MM-dd HHmmss.SSSz",
83                                               "yyyyDDD'J'HH:mm:ssz",
84                                               "yyyyDDD'J'HHmmssz",
85                                               "yyyyMMdd'T'HH:mm:ssz",
86                                               "yyyyMMdd'T'HHmmssz",
87                                               "yyyy-MM-dd'T'HH:mm:ssz",
88                                               "yyyy-MM-dd'T'HHmmssz",
89                                               "yyyyMMdd HH:mm:ssz",
90                                               "yyyyMMdd HHmmssz",
91                                               "yyyy-MM-dd HH:mm:ssz",
92                                               "yyyy-MM-dd HHmmssz",
93                                               "yyyyMMddHHmmssz"};
94  
95      static int[] matches = new int[patterns.length];
96      static {
97          dateFormats = new DateFormat[patterns.length];
98          TimeZone gmt = TimeZone.getTimeZone("GMT");
99          for(int i = 0; i < patterns.length; i++) {
100             dateFormats[i] = new SimpleDateFormat(patterns[i]);
101             dateFormats[i].setTimeZone(gmt);
102         }
103     }
104 
105     protected String cleanDate(String s) {
106         int zoneIndex = s.indexOf('Z');
107         if(zoneIndex == -1) {
108             //not zulu, try +
109             zoneIndex = s.indexOf('+');
110             if(zoneIndex == -1) {
111                 // not +, try -, but remember it might be used within first
112                 // 8 charaters for separating year, month and day, yyyy-mm-dd
113                 zoneIndex = s.indexOf('-', 8);
114             }
115         }
116         if(zoneIndex == -1) {
117             // no time zone info
118             zoneIndex = s.length();
119         }
120         // check for more than 3 digits, millis not supported by
121         // java's SimpleDateFormat
122         int endIndex;
123         if(s.lastIndexOf('.') == -1) {
124             // no decimal seconds
125             endIndex = zoneIndex;
126         } else if(zoneIndex - s.lastIndexOf('.') > 3) {
127             endIndex = s.lastIndexOf('.') + 4;
128         } else {
129             endIndex = zoneIndex;
130         }
131         String out = s.substring(0, endIndex);
132         // System.out.println("ISOTime out="+out+" z-.="+(zoneIndex -
133         // s.lastIndexOf('.')));
134         // pad out to 3 decimal points...
135         if(zoneIndex - s.lastIndexOf('.') == 3) {
136             out += "0";
137         } else if(zoneIndex - s.lastIndexOf('.') == 2) {
138             out += "00";
139         } else if(zoneIndex - s.lastIndexOf('.') == 1) {
140             out += "000";
141         }
142         // check for Julian day format, yyyyddd, if found
143         // change T to J so parser uses correct pattern
144         if(out.indexOf('T') == 7) {
145             out = out.replace('T', 'J');
146         }
147         if(zoneIndex == s.length()) {
148             // assume GMT time???
149             out += "GMT";
150             // for local time...
151             //out += TimeZone.getDefault().getID();
152         } else if(s.charAt(zoneIndex) == 'Z') {
153             // assume GMT
154             out += "GMT";
155         } else {
156             String tzString = s.substring(zoneIndex);
157             if(tzString.length() == 3) {
158                 // assume TZ info is only GMT+hh, so to
159                 // work around bug in SImpleDateFormat we
160                 // must add :00 for 0 minutes
161                 tzString += ":00";
162             }
163             out += "GMT" + tzString;
164         }
165         return out;
166     }
167 
168     protected MicroSecondDate date;
169 
170     protected String orig;
171 
172     public String getOrigString() {
173         return orig;
174     }
175 
176     /***
177      * Get a java.unil.Calendar object initialized to be this ISOTime. Note that
178      * a reduction of precision may occur as the default GregorianCalendar only
179      * supports millisecond precision.
180      */
181     public Calendar getCalendar() {
182         Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
183         cal.setTime(date);
184         return cal;
185     }
186 
187     public MicroSecondDate getDate() {
188         return date;
189     }
190 
191     public static String getISOString(MicroSecondDate ms) {
192         SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss.SSS");
193         df.setTimeZone(TimeZone.getTimeZone("GMT"));
194         String s = df.format(ms);
195         long micros = ms.getMicroSeconds();
196         if(micros == 0) {
197             // nothing
198         } else if(micros < 10) {
199             s += "00" + micros;
200         } else if(micros < 100) {
201             if(micros % 10 == 0) {
202                 s += "0" + (micros % 10);
203             } else {
204                 s += "0" + micros;
205             }
206         } else {
207             if(micros % 100 == 0) {
208                 s += micros % 100;
209             } else if(micros % 10 == 0) {
210                 s += micros % 10;
211             } else {
212                 s += micros;
213             }
214         }
215         return s + "Z";
216     }
217 
218     public static String getISOString(Date ms) {
219         if(ms instanceof MicroSecondDate) { return getISOString((MicroSecondDate)ms); }
220         SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss.SSSz");
221         df.setTimeZone(TimeZone.getTimeZone("GMT"));
222         return df.format(ms);
223     }
224 
225     public String toString() {
226         java.text.DateFormat df = java.text.DateFormat.getDateTimeInstance(java.text.DateFormat.FULL,
227                                                                            java.text.DateFormat.FULL);
228         df.setTimeZone(TimeZone.getTimeZone("GMT"));
229         return df.format(getCalendar().getTime());
230         //  return getYear()+" "+getMonth()+" "+getDay()+" "+getHour()+" "+
231         //    getMinute()+" "+getSecond();
232     }
233 
234     /***
235      * just for testing, parses and outputs a few ISO8601 strings.
236      */
237     public static void main(String[] args) {
238         String[] s = {"19990101T120030.1111Z",
239                       "1999-01-01T000030.1111Z",
240                       "19990101T00:00:30.1111Z",
241                       "1999-01-01T00:00:30.1111Z",
242                       "1999001T00:00:30.1111Z",
243                       "1999001T000030.1111Z",
244                       "1999-12-21T00:00:30.1234Z",
245                       "2048-01-01T16:00:30.1111+01",
246                       "1999-01-01T00:59:30.1111+01:30",
247                       "1999-01-01T23:59:59.999-01:30",
248                       "19990101T120030Z"};
249         try {
250             for(int i = 0; i < s.length; i++) {
251                 ISOTime iso = new ISOTime(s[i]);
252                 System.out.println(iso + " = " + iso.getOrigString());
253             }
254             System.out.println(ISOTime.getISOString(1999, 1, 2, 3, 3.456f));
255         } catch(Exception e) {
256             System.out.println(e);
257             e.printStackTrace();
258         }
259     }
260 } // ISOTime