Begin versioning.
[fits.git] / src / nom / tam / fits / FitsDate.java
1 package nom.tam.fits;
2
3 /*
4  * Copyright: Thomas McGlynn 1997-1998.
5  * This code may be used for any purpose, non-commercial
6  * or commercial so long as this copyright notice is retained
7  * in the source code or included in or referred to in any
8  * derived software.
9  *
10  * This class was contributed by D. Glowacki.
11  */
12 import java.util.Calendar;
13 import java.util.Date;
14 import java.util.GregorianCalendar;
15 import java.util.TimeZone;
16 import java.text.DecimalFormat;
17
18 public class FitsDate {
19
20     private int year = -1;
21     private int month = -1;
22     private int mday = -1;
23     private int hour = -1;
24     private int minute = -1;
25     private int second = -1;
26     private int millisecond = -1;
27     private Date date = null;
28
29     /**
30      * Convert a FITS date string to a Java <CODE>Date</CODE> object.
31      * @param dStr      the FITS date
32      * @return  either <CODE>null</CODE> or a Date object
33      * @exception FitsException if <CODE>dStr</CODE> does not
34      *                                  contain a valid FITS date.
35      */
36     public FitsDate(String dStr)
37             throws FitsException {
38         // if the date string is null, we are done
39         if (dStr == null) {
40             return;
41         }
42
43         // if the date string is empty, we are done
44         dStr = dStr.trim();
45         if (dStr.length() == 0) {
46             return;
47         }
48
49         // if string contains at least 8 characters...
50         int len = dStr.length();
51         if (len >= 8) {
52             int first;
53
54             // ... and there is a "/" in the string...
55             first = dStr.indexOf('-');
56             if (first == 4 && first < len) {
57
58                 // ... this must be an new-style date
59                 buildNewDate(dStr, first, len);
60
61                 // no "/" found; maybe it is an old-style date...
62             } else {
63
64                 first = dStr.indexOf('/');
65                 if (first > 1 && first < len) {
66
67                     // ... this must be an old-style date
68                     buildOldDate(dStr, first, len);
69                 }
70             }
71         }
72
73         if (year == -1) {
74             throw new FitsException("Bad FITS date string \"" + dStr + '"');
75         }
76     }
77
78     private void buildOldDate(String dStr, int first, int len) {
79         int middle = dStr.indexOf('/', first + 1);
80         if (middle > first + 2 && middle < len) {
81
82             try {
83
84                 year = Integer.parseInt(dStr.substring(middle + 1)) + 1900;
85                 month = Integer.parseInt(dStr.substring(first + 1, middle));
86                 mday = Integer.parseInt(dStr.substring(0, first));
87
88             } catch (NumberFormatException e) {
89
90                 year = month = mday = -1;
91             }
92         }
93     }
94
95     private void parseTime(String tStr)
96             throws FitsException {
97         int first = tStr.indexOf(':');
98         if (first < 0) {
99             throw new FitsException("Bad time");
100         }
101
102         int len = tStr.length();
103
104         int middle = tStr.indexOf(':', first + 1);
105         if (middle > first + 2 && middle < len) {
106
107             if (middle + 3 < len && tStr.charAt(middle + 3) == '.') {
108                 double d = Double.valueOf(tStr.substring(middle + 3)).doubleValue();
109                 millisecond = (int) (d * 1000);
110
111                 len = middle + 3;
112             }
113
114             try {
115                 hour = Integer.parseInt(tStr.substring(0, first));
116                 minute = Integer.parseInt(tStr.substring(first + 1, middle));
117                 second = Integer.parseInt(tStr.substring(middle + 1, len));
118             } catch (NumberFormatException e) {
119                 hour = minute = second = millisecond = -1;
120             }
121         }
122     }
123
124     private void buildNewDate(String dStr, int first, int len)
125             throws FitsException {
126         // find the middle separator
127         int middle = dStr.indexOf('-', first + 1);
128         if (middle > first + 2 && middle < len) {
129
130             try {
131
132                 // if this date string includes a time...
133                 if (middle + 3 < len && dStr.charAt(middle + 3) == 'T') {
134
135                     // ... try to parse the time
136                     try {
137                         parseTime(dStr.substring(middle + 4));
138                     } catch (FitsException e) {
139                         throw new FitsException("Bad time in FITS date string \""
140                                 + dStr + "\"");
141                     }
142
143                     // we got the time; mark the end of the date string
144                     len = middle + 3;
145                 }
146
147                 // parse date string
148                 year = Integer.parseInt(dStr.substring(0, first));
149                 month = Integer.parseInt(dStr.substring(first + 1, middle));
150                 mday = Integer.parseInt(dStr.substring(middle + 1, len));
151
152             } catch (NumberFormatException e) {
153
154                 // yikes, something failed; reset everything
155                 year = month = mday = hour = minute = second = millisecond = -1;
156             }
157         }
158     }
159
160     /** Get a Java Date object corresponding to this
161      *  FITS date.
162      *  @return The Java Date object.
163      */
164     public Date toDate() {
165         if (date == null && year != -1) {
166             TimeZone tz = TimeZone.getTimeZone("GMT");
167             GregorianCalendar cal = new GregorianCalendar(tz);
168
169             cal.set(Calendar.YEAR, year);
170             cal.set(Calendar.MONTH, month - 1);
171             cal.set(Calendar.DAY_OF_MONTH, mday);
172
173             if (hour == -1) {
174
175                 cal.set(Calendar.HOUR_OF_DAY, 0);
176                 cal.set(Calendar.MINUTE, 0);
177                 cal.set(Calendar.SECOND, 0);
178                 cal.set(Calendar.MILLISECOND, 0);
179
180             } else {
181
182                 cal.set(Calendar.HOUR_OF_DAY, hour);
183                 cal.set(Calendar.MINUTE, minute);
184                 cal.set(Calendar.SECOND, second);
185                 if (millisecond == -1) {
186                     cal.set(Calendar.MILLISECOND, 0);
187                 } else {
188                     cal.set(Calendar.MILLISECOND, millisecond);
189                 }
190             }
191
192             date = cal.getTime();
193         }
194
195         return date;
196     }
197
198     /** Return the current date in FITS date format */
199     public static String getFitsDateString() {
200         return getFitsDateString(new Date(), true);
201     }
202
203     /** Create FITS format date string Java Date object.
204      *  @param epoch    The epoch to be converted to FITS format.
205      */
206     public static String getFitsDateString(Date epoch) {
207         return getFitsDateString(epoch, true);
208     }
209
210     /** Create FITS format date string.
211      *  Note that the date is not rounded.
212      *  @param epoch           The epoch to be converted to FITS format.
213      *  @param timeOfDay        Should time of day information be included?
214      */
215     public static String getFitsDateString(Date epoch, boolean timeOfDay) {
216
217         try {
218             GregorianCalendar cal = new GregorianCalendar(
219                     TimeZone.getTimeZone("GMT"));
220
221
222             cal.setTime(epoch);
223
224             StringBuffer fitsDate = new StringBuffer();
225             DecimalFormat df = new DecimalFormat("0000");
226             fitsDate.append(df.format(cal.get(Calendar.YEAR)));
227             fitsDate.append("-");
228             df = new DecimalFormat("00");
229
230             fitsDate.append(df.format(cal.get(Calendar.MONTH) + 1));
231             fitsDate.append("-");
232             fitsDate.append(df.format(cal.get(Calendar.DAY_OF_MONTH)));
233
234             if (timeOfDay) {
235                 fitsDate.append("T");
236                 fitsDate.append(df.format(cal.get(Calendar.HOUR_OF_DAY)));
237                 fitsDate.append(":");
238                 fitsDate.append(df.format(cal.get(Calendar.MINUTE)));
239                 fitsDate.append(":");
240                 fitsDate.append(df.format(cal.get(Calendar.SECOND)));
241                 fitsDate.append(".");
242                 df = new DecimalFormat("000");
243                 fitsDate.append(df.format(cal.get(Calendar.MILLISECOND)));
244             }
245
246             return new String(fitsDate);
247
248         } catch (Exception e) {
249
250             return new String("");
251         }
252     }
253
254     public String toString() {
255         if (year == -1) {
256             return "";
257         }
258
259         StringBuffer buf = new StringBuffer(23);
260         buf.append(year);
261         buf.append('-');
262         if (month < 10) {
263             buf.append('0');
264         }
265         buf.append(month);
266         buf.append('-');
267         if (mday < 10) {
268             buf.append('0');
269         }
270         buf.append(mday);
271
272         if (hour != -1) {
273
274             buf.append('T');
275             if (hour < 10) {
276                 buf.append('0');
277             }
278
279             buf.append(hour);
280             buf.append(':');
281
282             if (minute < 10) {
283                 buf.append('0');
284             }
285
286             buf.append(minute);
287             buf.append(':');
288
289             if (second < 10) {
290                 buf.append('0');
291             }
292             buf.append(second);
293
294             if (millisecond != -1) {
295                 buf.append('.');
296
297                 if (millisecond < 100) {
298                     if (millisecond < 10) {
299                         buf.append("00");
300                     } else {
301                         buf.append('0');
302                     }
303                 }
304                 buf.append(millisecond);
305             }
306         }
307
308         return buf.toString();
309     }
310
311     public static void testArgs(String args[]) {
312         for (int i = 0; i < args.length; i++) {
313
314             try {
315                 FitsDate fd = new FitsDate(args[i]);
316                 System.out.println("\"" + args[i] + "\" => " + fd + " => "
317                         + fd.toDate());
318             } catch (Exception e) {
319                 System.err.println("Date \"" + args[i] + "\" threw "
320                         + e.getClass().getName() + "(" + e.getMessage()
321                         + ")");
322             }
323         }
324     }
325
326     public static void autotest() {
327         String[] good = new String[6];
328         good[0] = "20/09/79";
329         good[1] = "1997-07-25";
330         good[2] = "1987-06-05T04:03:02.01";
331         good[3] = "1998-03-10T16:58:34";
332         good[4] = null;
333         good[5] = "        ";
334         testArgs(good);
335
336         String[] badOld = new String[4];
337         badOld[0] = "20/09/";
338         badOld[1] = "/09/79";
339         badOld[2] = "09//79";
340         badOld[3] = "20/09/79/";
341         testArgs(badOld);
342
343         String[] badNew = new String[4];
344         badNew[0] = "1997-07";
345         badNew[1] = "-07-25";
346         badNew[2] = "1997--07-25";
347         badNew[3] = "1997-07-25-";
348         testArgs(badNew);
349
350         String[] badMisc = new String[4];
351         badMisc[0] = "5-Aug-1992";
352         badMisc[1] = "28/02/91 16:32:00";
353         badMisc[2] = "18-Feb-1993";
354         badMisc[3] = "nn/nn/nn";
355         testArgs(badMisc);
356     }
357
358     public static void main(String args[]) {
359         if (args.length == 0) {
360             autotest();
361         } else {
362             testArgs(args);
363         }
364     }
365 }