]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/data/Timestamp.java
Version 11, August 2010
[GpsPrune.git] / tim / prune / data / Timestamp.java
index 965853ad036e5b61a44fe1dc58af87154bfc7df0..8de7c4d7d76e62c5b1041d497a6139613be14f24 100644 (file)
@@ -5,6 +5,8 @@ import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * Class to hold the timestamp of a track point
@@ -15,18 +17,31 @@ public class Timestamp
        private boolean _valid = false;
        private long _seconds = 0L;
        private String _text = null;
+       private String _timeText = null;
 
-       private static DateFormat DEFAULT_DATE_FORMAT = DateFormat.getDateTimeInstance();
+       private static final DateFormat DEFAULT_DATE_FORMAT = DateFormat.getDateTimeInstance();
+       private static final DateFormat DEFAULT_TIME_FORMAT = DateFormat.getTimeInstance();
+       private static final DateFormat ISO_8601_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+       private static final DateFormat ISO_8601_FORMAT_NOZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        private static DateFormat[] ALL_DATE_FORMATS = null;
        private static Calendar CALENDAR = null;
+       private static final Pattern GENERAL_TIMESTAMP_PATTERN
+               = Pattern.compile("(\\d{4})\\D(\\d{2})\\D(\\d{2})\\D(\\d{2})\\D(\\d{2})\\D(\\d{2})");
+       private static Matcher GENERAL_TIMESTAMP_MATCHER = null;
        private static long SECS_SINCE_1970 = 0L;
        private static long SECS_SINCE_GARTRIP = 0L;
        private static long MSECS_SINCE_1970 = 0L;
        private static long MSECS_SINCE_1990 = 0L;
        private static long TWENTY_YEARS_IN_SECS = 0L;
-
        private static final long GARTRIP_OFFSET = 631065600L;
 
+       /** Specifies original timestamp format */
+       public static final int FORMAT_ORIGINAL = 0;
+       /** Specifies locale-dependent timestamp format */
+       public static final int FORMAT_LOCALE = 1;
+       /** Specifies ISO 8601 timestamp format */
+       public static final int FORMAT_ISO_8601 = 2;
+
        // Static block to initialise offsets
        static
        {
@@ -43,51 +58,26 @@ public class Timestamp
                        new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy"),
                        new SimpleDateFormat("HH:mm:ss dd MMM yyyy"),
                        new SimpleDateFormat("dd MMM yyyy HH:mm:ss"),
-                       new SimpleDateFormat("yyyy MMM dd HH:mm:ss")
+                       new SimpleDateFormat("yyyy MMM dd HH:mm:ss"),
+                       ISO_8601_FORMAT, ISO_8601_FORMAT_NOZ
                };
        }
 
 
        /**
         * Constructor
+        * @param inString String containing timestamp
         */
        public Timestamp(String inString)
        {
+               // TODO: Does it really help to store timestamps in seconds rather than ms?
                if (inString != null && !inString.equals(""))
                {
                        // Try to parse into a long
                        try
                        {
                                long rawValue = Long.parseLong(inString.trim());
-                               // check for each format possibility and pick nearest
-                               long diff1 = Math.abs(SECS_SINCE_1970 - rawValue);
-                               long diff2 = Math.abs(MSECS_SINCE_1970 - rawValue);
-                               long diff3 = Math.abs(MSECS_SINCE_1990 - rawValue);
-                               long diff4 = Math.abs(SECS_SINCE_GARTRIP - rawValue);
-
-                               // Start off with "seconds since 1970" format
-                               long smallestDiff = diff1;
-                               _seconds = rawValue;
-                               // Now check millis since 1970
-                               if (diff2 < smallestDiff)
-                               {
-                                       // milliseconds since 1970
-                                       _seconds = rawValue / 1000L;
-                                       smallestDiff = diff2;
-                               }
-                               // Now millis since 1990
-                               if (diff3 < smallestDiff)
-                               {
-                                       // milliseconds since 1990
-                                       _seconds = rawValue / 1000L + TWENTY_YEARS_IN_SECS;
-                                       smallestDiff = diff3;
-                               }
-                               // Lastly, check garmin offset
-                               if (diff4 < smallestDiff)
-                               {
-                                       // milliseconds since garmin offset
-                                       _seconds = rawValue + GARTRIP_OFFSET;
-                               }
+                               _seconds = getSeconds(rawValue);
                                _valid = true;
                        }
                        catch (NumberFormatException nfe)
@@ -106,11 +96,115 @@ public class Timestamp
                                        }
                                        catch (ParseException e) {}
                                }
+                               if (!_valid && inString.length() == 19) {
+                                       GENERAL_TIMESTAMP_MATCHER = GENERAL_TIMESTAMP_PATTERN.matcher(inString);
+                                       if (GENERAL_TIMESTAMP_MATCHER.matches()) {
+                                               try {
+                                                       _seconds = getSeconds(Integer.parseInt(GENERAL_TIMESTAMP_MATCHER.group(1)),
+                                                               Integer.parseInt(GENERAL_TIMESTAMP_MATCHER.group(2)),
+                                                               Integer.parseInt(GENERAL_TIMESTAMP_MATCHER.group(3)),
+                                                               Integer.parseInt(GENERAL_TIMESTAMP_MATCHER.group(4)),
+                                                               Integer.parseInt(GENERAL_TIMESTAMP_MATCHER.group(5)),
+                                                               Integer.parseInt(GENERAL_TIMESTAMP_MATCHER.group(6)));
+                                                       _valid = true;
+                                               }
+                                               catch (NumberFormatException nfe2) {} // parse shouldn't fail if matcher matched
+                                       }
+                               }
                        }
                }
        }
 
 
+       /**
+        * Constructor giving each field value individually
+        * @param inYear year
+        * @param inMonth month, beginning with 1
+        * @param inDay day of month, beginning with 1
+        * @param inHour hour of day, 0-24
+        * @param inMinute minute
+        * @param inSecond seconds
+        */
+       public Timestamp(int inYear, int inMonth, int inDay, int inHour, int inMinute, int inSecond)
+       {
+               _seconds = getSeconds(inYear, inMonth, inDay, inHour, inMinute, inSecond);
+               _valid = true;
+       }
+
+
+       /**
+        * Constructor giving millis
+        * @param inMillis milliseconds since 1970
+        */
+       public Timestamp(long inMillis)
+       {
+               _seconds = inMillis / 1000;
+               _valid = true;
+       }
+
+
+       /**
+        * Convert the given timestamp parameters into a number of seconds
+        * @param inYear year
+        * @param inMonth month, beginning with 1
+        * @param inDay day of month, beginning with 1
+        * @param inHour hour of day, 0-24
+        * @param inMinute minute
+        * @param inSecond seconds
+        * @return number of seconds
+        */
+       private static long getSeconds(int inYear, int inMonth, int inDay, int inHour, int inMinute, int inSecond)
+       {
+               Calendar cal = Calendar.getInstance();
+               cal.set(Calendar.YEAR, inYear);
+               cal.set(Calendar.MONTH, inMonth - 1);
+               cal.set(Calendar.DAY_OF_MONTH, inDay);
+               cal.set(Calendar.HOUR_OF_DAY, inHour);
+               cal.set(Calendar.MINUTE, inMinute);
+               cal.set(Calendar.SECOND, inSecond);
+               cal.set(Calendar.MILLISECOND, 0);
+               return cal.getTimeInMillis() / 1000;
+       }
+
+       /**
+        * Convert the given long parameters into a number of seconds
+        * @param inRawValue long value representing seconds / milliseconds
+        * @return number of seconds
+        */
+       private static long getSeconds(long inRawValue)
+       {
+               // check for each format possibility and pick nearest
+               long diff1 = Math.abs(SECS_SINCE_1970 - inRawValue);
+               long diff2 = Math.abs(MSECS_SINCE_1970 - inRawValue);
+               long diff3 = Math.abs(MSECS_SINCE_1990 - inRawValue);
+               long diff4 = Math.abs(SECS_SINCE_GARTRIP - inRawValue);
+
+               // Start off with "seconds since 1970" format
+               long smallestDiff = diff1;
+               long seconds = inRawValue;
+               // Now check millis since 1970
+               if (diff2 < smallestDiff)
+               {
+                       // milliseconds since 1970
+                       seconds = inRawValue / 1000L;
+                       smallestDiff = diff2;
+               }
+               // Now millis since 1990
+               if (diff3 < smallestDiff)
+               {
+                       // milliseconds since 1990
+                       seconds = inRawValue / 1000L + TWENTY_YEARS_IN_SECS;
+                       smallestDiff = diff3;
+               }
+               // Lastly, check gartrip offset
+               if (diff4 < smallestDiff)
+               {
+                       // seconds since gartrip offset
+                       seconds = inRawValue + GARTRIP_OFFSET;
+               }
+               return seconds;
+       }
+
        /**
         * @return true if timestamp is valid
         */
@@ -119,6 +213,14 @@ public class Timestamp
                return _valid;
        }
 
+       /**
+        * @param inOther other Timestamp
+        * @return true if this one is after the other
+        */
+       public boolean isAfter(Timestamp inOther)
+       {
+               return _seconds > inOther._seconds;
+       }
 
        /**
         * Calculate the difference between two Timestamps in seconds
@@ -130,21 +232,95 @@ public class Timestamp
                return _seconds - inOther._seconds;
        }
 
+       /**
+        * Add the given number of seconds offset
+        * @param inOffset number of seconds to add/subtract
+        */
+       public void addOffset(long inOffset)
+       {
+               _seconds += inOffset;
+               _text = null;
+       }
+
+       /**
+        * Add the given TimeDifference to this Timestamp
+        * @param inOffset TimeDifference to add
+        * @return new Timestamp object
+        */
+       public Timestamp createPlusOffset(TimeDifference inOffset)
+       {
+               return new Timestamp((_seconds + inOffset.getTotalSeconds()) * 1000L);
+       }
+
+
+       /**
+        * Subtract the given TimeDifference from this Timestamp
+        * @param inOffset TimeDifference to subtract
+        * @return new Timestamp object
+        */
+       public Timestamp createMinusOffset(TimeDifference inOffset)
+       {
+               return new Timestamp((_seconds - inOffset.getTotalSeconds()) * 1000L);
+       }
+
 
        /**
         * @return Description of timestamp in locale-specific format
         */
        public String getText()
        {
-               if (_text == null)
+               return getText(FORMAT_LOCALE);
+       }
+
+       /**
+        * @param inFormat format of timestamp
+        * @return Description of timestamp in required format
+        */
+       public String getText(int inFormat)
+       {
+               if (!_valid) {return "";}
+               if (inFormat == FORMAT_ISO_8601) {
+                       return format(ISO_8601_FORMAT);
+               }
+               if (_text == null) {
+                       _text = (_valid?format(DEFAULT_DATE_FORMAT):"");
+               }
+               return _text;
+       }
+
+       /**
+        * @return Description of time part of timestamp in locale-specific format
+        */
+       public String getTimeText()
+       {
+               if (_timeText == null)
                {
-                       if (_valid)
-                       {
-                               CALENDAR.setTimeInMillis(_seconds * 1000L);
-                               _text = DEFAULT_DATE_FORMAT.format(CALENDAR.getTime());
+                       if (_valid) {
+                               _timeText = format(DEFAULT_TIME_FORMAT);
                        }
-                       else _text = "";
+                       else _timeText = "";
                }
-               return _text;
+               return _timeText;
+       }
+
+       /**
+        * Utility method for formatting dates / times
+        * @param inFormat formatter object
+        * @return formatted String
+        */
+       private String format(DateFormat inFormat)
+       {
+               CALENDAR.setTimeInMillis(_seconds * 1000L);
+               return inFormat.format(CALENDAR.getTime());
+       }
+
+       /**
+        * @return a Calendar object representing this timestamp
+        */
+       public Calendar getCalendar()
+       {
+               Calendar cal = Calendar.getInstance();
+               cal.setTimeInMillis(_seconds * 1000L);
+               return cal;
        }
 }