]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/data/Timestamp.java
f1d056980de680d5343edf25776ebe56402700d1
[GpsPrune.git] / tim / prune / data / Timestamp.java
1 package tim.prune.data;
2
3 import java.text.DateFormat;
4 import java.text.ParseException;
5 import java.text.SimpleDateFormat;
6 import java.util.Calendar;
7 import java.util.Date;
8
9 /**
10  * Class to hold the timestamp of a track point
11  * and provide conversion functions
12  */
13 public class Timestamp
14 {
15         private boolean _valid = false;
16         private long _seconds = 0L;
17         private String _text = null;
18         private String _timeText = null;
19
20         private static final DateFormat DEFAULT_DATE_FORMAT = DateFormat.getDateTimeInstance();
21         private static final DateFormat DEFAULT_TIME_FORMAT = DateFormat.getTimeInstance();
22         private static final DateFormat ISO_8601_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
23         private static final DateFormat ISO_8601_FORMAT_NOZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
24         private static DateFormat[] ALL_DATE_FORMATS = null;
25         private static Calendar CALENDAR = null;
26         private static long SECS_SINCE_1970 = 0L;
27         private static long SECS_SINCE_GARTRIP = 0L;
28         private static long MSECS_SINCE_1970 = 0L;
29         private static long MSECS_SINCE_1990 = 0L;
30         private static long TWENTY_YEARS_IN_SECS = 0L;
31         private static final long GARTRIP_OFFSET = 631065600L;
32
33         /** Specifies original timestamp format */
34         public static final int FORMAT_ORIGINAL = 0;
35         /** Specifies locale-dependent timestamp format */
36         public static final int FORMAT_LOCALE = 1;
37         /** Specifies ISO 8601 timestamp format */
38         public static final int FORMAT_ISO_8601 = 2;
39
40         // Static block to initialise offsets
41         static
42         {
43                 CALENDAR = Calendar.getInstance();
44                 MSECS_SINCE_1970 = CALENDAR.getTimeInMillis();
45                 SECS_SINCE_1970 = MSECS_SINCE_1970 / 1000L;
46                 SECS_SINCE_GARTRIP = SECS_SINCE_1970 - GARTRIP_OFFSET;
47                 CALENDAR.add(Calendar.YEAR, -20);
48                 MSECS_SINCE_1990 = CALENDAR.getTimeInMillis();
49                 TWENTY_YEARS_IN_SECS = (MSECS_SINCE_1970 - MSECS_SINCE_1990) / 1000L;
50                 // Date formats
51                 ALL_DATE_FORMATS = new DateFormat[] {
52                         DEFAULT_DATE_FORMAT,
53                         new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy"),
54                         new SimpleDateFormat("HH:mm:ss dd MMM yyyy"),
55                         new SimpleDateFormat("dd MMM yyyy HH:mm:ss"),
56                         new SimpleDateFormat("yyyy MMM dd HH:mm:ss"),
57                         ISO_8601_FORMAT, ISO_8601_FORMAT_NOZ
58                 };
59         }
60
61
62         /**
63          * Constructor
64          * @param inString String containing timestamp
65          */
66         public Timestamp(String inString)
67         {
68                 // TODO: Does it really help to store timestamps in seconds rather than ms?
69                 if (inString != null && !inString.equals(""))
70                 {
71                         // Try to parse into a long
72                         try
73                         {
74                                 long rawValue = Long.parseLong(inString.trim());
75                                 // check for each format possibility and pick nearest
76                                 long diff1 = Math.abs(SECS_SINCE_1970 - rawValue);
77                                 long diff2 = Math.abs(MSECS_SINCE_1970 - rawValue);
78                                 long diff3 = Math.abs(MSECS_SINCE_1990 - rawValue);
79                                 long diff4 = Math.abs(SECS_SINCE_GARTRIP - rawValue);
80
81                                 // Start off with "seconds since 1970" format
82                                 long smallestDiff = diff1;
83                                 _seconds = rawValue;
84                                 // Now check millis since 1970
85                                 if (diff2 < smallestDiff)
86                                 {
87                                         // milliseconds since 1970
88                                         _seconds = rawValue / 1000L;
89                                         smallestDiff = diff2;
90                                 }
91                                 // Now millis since 1990
92                                 if (diff3 < smallestDiff)
93                                 {
94                                         // milliseconds since 1990
95                                         _seconds = rawValue / 1000L + TWENTY_YEARS_IN_SECS;
96                                         smallestDiff = diff3;
97                                 }
98                                 // Lastly, check gartrip offset
99                                 if (diff4 < smallestDiff)
100                                 {
101                                         // seconds since gartrip offset
102                                         _seconds = rawValue + GARTRIP_OFFSET;
103                                 }
104                                 _valid = true;
105                         }
106                         catch (NumberFormatException nfe)
107                         {
108                                 // String is not a long, so try a date/time string instead
109                                 // try each of the date formatters in turn
110                                 Date date = null;
111                                 for (int i=0; i<ALL_DATE_FORMATS.length && !_valid; i++)
112                                 {
113                                         try
114                                         {
115                                                 date = ALL_DATE_FORMATS[i].parse(inString);
116                                                 CALENDAR.setTime(date);
117                                                 _seconds = CALENDAR.getTimeInMillis() / 1000L;
118                                                 _valid = true;
119                                         }
120                                         catch (ParseException e) {}
121                                 }
122                         }
123                 }
124         }
125
126
127         /**
128          * Constructor giving each field value individually
129          * @param inYear year
130          * @param inMonth month, beginning with 1
131          * @param inDay day of month, beginning with 1
132          * @param inHour hour of day, 0-24
133          * @param inMinute minute
134          * @param inSecond seconds
135          */
136         public Timestamp(int inYear, int inMonth, int inDay, int inHour, int inMinute, int inSecond)
137         {
138                 Calendar cal = Calendar.getInstance();
139                 cal.set(Calendar.YEAR, inYear);
140                 cal.set(Calendar.MONTH, inMonth - 1);
141                 cal.set(Calendar.DAY_OF_MONTH, inDay);
142                 cal.set(Calendar.HOUR_OF_DAY, inHour);
143                 cal.set(Calendar.MINUTE, inMinute);
144                 cal.set(Calendar.SECOND, inSecond);
145                 cal.set(Calendar.MILLISECOND, 0);
146                 _seconds = cal.getTimeInMillis() / 1000;
147                 _valid = true;
148         }
149
150
151         /**
152          * Constructor giving millis
153          * @param inMillis milliseconds since 1970
154          */
155         public Timestamp(long inMillis)
156         {
157                 _seconds = inMillis / 1000;
158                 _valid = true;
159         }
160
161
162         /**
163          * @return true if timestamp is valid
164          */
165         public boolean isValid()
166         {
167                 return _valid;
168         }
169
170         /**
171          * @param inOther other Timestamp
172          * @return true if this one is after the other
173          */
174         public boolean isAfter(Timestamp inOther)
175         {
176                 return _seconds > inOther._seconds;
177         }
178
179         /**
180          * Calculate the difference between two Timestamps in seconds
181          * @param inOther other, earlier Timestamp
182          * @return number of seconds since other timestamp
183          */
184         public long getSecondsSince(Timestamp inOther)
185         {
186                 return _seconds - inOther._seconds;
187         }
188
189         /**
190          * Add the given number of seconds offset
191          * @param inOffset number of seconds to add/subtract
192          */
193         public void addOffset(long inOffset)
194         {
195                 _seconds += inOffset;
196                 _text = null;
197         }
198
199         /**
200          * Add the given TimeDifference to this Timestamp
201          * @param inOffset TimeDifference to add
202          * @return new Timestamp object
203          */
204         public Timestamp createPlusOffset(TimeDifference inOffset)
205         {
206                 return new Timestamp((_seconds + inOffset.getTotalSeconds()) * 1000L);
207         }
208
209
210         /**
211          * Subtract the given TimeDifference from this Timestamp
212          * @param inOffset TimeDifference to subtract
213          * @return new Timestamp object
214          */
215         public Timestamp createMinusOffset(TimeDifference inOffset)
216         {
217                 return new Timestamp((_seconds - inOffset.getTotalSeconds()) * 1000L);
218         }
219
220
221         /**
222          * @return Description of timestamp in locale-specific format
223          */
224         public String getText()
225         {
226                 return getText(FORMAT_LOCALE);
227         }
228
229         /**
230          * @param inFormat format of timestamp
231          * @return Description of timestamp in required format
232          */
233         public String getText(int inFormat)
234         {
235                 if (inFormat == FORMAT_ISO_8601) {
236                         return format(ISO_8601_FORMAT);
237                 }
238                 if (_text == null)
239                 {
240                         if (_valid) {
241                                 _text = format(DEFAULT_DATE_FORMAT);
242                         }
243                         else _text = "";
244                 }
245                 return _text;
246         }
247
248         /**
249          * @return Description of time part of timestamp in locale-specific format
250          */
251         public String getTimeText()
252         {
253                 if (_timeText == null)
254                 {
255                         if (_valid) {
256                                 _timeText = format(DEFAULT_TIME_FORMAT);
257                         }
258                         else _timeText = "";
259                 }
260                 return _timeText;
261         }
262
263         /**
264          * Utility method for formatting dates / times
265          * @param inFormat formatter object
266          * @return formatted String
267          */
268         private String format(DateFormat inFormat)
269         {
270                 CALENDAR.setTimeInMillis(_seconds * 1000L);
271                 return inFormat.format(CALENDAR.getTime());
272         }
273
274         /**
275          * @return a Calendar object representing this timestamp
276          */
277         public Calendar getCalendar()
278         {
279                 Calendar cal = Calendar.getInstance();
280                 cal.setTimeInMillis(_seconds * 1000L);
281                 return cal;
282         }
283 }