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