tmf: Bug 433518: Add support for unit of seconds in TmfTimestampFormat
authorPatrick Tasse <patrick.tasse@gmail.com>
Tue, 10 May 2016 20:45:43 +0000 (16:45 -0400)
committerPatrick Tasse <patrick.tasse@gmail.com>
Tue, 17 May 2016 19:35:27 +0000 (15:35 -0400)
The T pattern can be augmented with a suffix to indicate the unit of
seconds to be used by the format. The following patterns are supported:
T (sec), Td (deci), Tc (centi), Tm (milli), Tu (micro), Tn (nano).

The S pattern is modified to represent fractions of this unit.

Change-Id: I81014132b7579093da7761861babe0447fd30b0b
Signed-off-by: Patrick Tasse <patrick.tasse@gmail.com>
Reviewed-on: https://git.eclipse.org/r/72840
Reviewed-by: Hudson CI
Reviewed-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Tested-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Reviewed-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
Tested-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
tmf/org.eclipse.tracecompass.tmf.core.tests/src/org/eclipse/tracecompass/tmf/core/tests/event/TmfTimestampFormatTest.java
tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/timestamp/TmfTimestampFormat.java

index 65e03588851ff1639bcab4d2b1f085995cef70ac..3bd50fc6cbc2b464dcb9d4a8ef93f5288e8ad911 100644 (file)
@@ -198,6 +198,53 @@ public class TmfTimestampFormatTest {
         assertEquals(-7100000000L, new TmfTimestampFormat("T.S").parseValue("-7.1"));
     }
 
+    /**
+     * Test unit of seconds format
+     *
+     * @throws ParseException
+     *             should not happen, if it does, the test is a failure
+     */
+    @Test
+    public void testUnitOfSecondsFormat() throws ParseException {
+        assertEquals("000000071.234567890", new TmfTimestampFormat("TTTTTTTTTd.SSSSSSSSS").format(7123456789L));
+        assertEquals("71.234567890", new TmfTimestampFormat("Td.SSSSSSSSS").format(7123456789L));
+        assertEquals("71.23456789", new TmfTimestampFormat("Td.SSSSSSSS").format(7123456789L));
+
+        assertEquals("000000712.345678900", new TmfTimestampFormat("TTTTTTTTTc.SSSSSSSSS").format(7123456789L));
+        assertEquals("712.345678900", new TmfTimestampFormat("Tc.SSSSSSSSS").format(7123456789L));
+        assertEquals("712.3456789", new TmfTimestampFormat("Tc.SSSSSSS").format(7123456789L));
+
+        assertEquals("000007123.456789000", new TmfTimestampFormat("TTTTTTTTTm.SSSSSSSSS").format(7123456789L));
+        assertEquals("7123.456789000", new TmfTimestampFormat("Tm.SSSSSSSSS").format(7123456789L));
+        assertEquals("7123.456789", new TmfTimestampFormat("Tm.SSSSSS").format(7123456789L));
+
+        assertEquals("007123456.789000000", new TmfTimestampFormat("TTTTTTTTTu.SSSSSSSSS").format(7123456789L));
+        assertEquals("7123456.789000000", new TmfTimestampFormat("Tu.SSSSSSSSS").format(7123456789L));
+        assertEquals("7123456.789", new TmfTimestampFormat("Tu.SSS").format(7123456789L));
+
+        assertEquals("7123456789.000000000", new TmfTimestampFormat("TTTTTTTTTn.SSSSSSSSS").format(7123456789L));
+        assertEquals("7123456789.000000000", new TmfTimestampFormat("Tn.SSSSSSSSS").format(7123456789L));
+        assertEquals("7123456789", new TmfTimestampFormat("Tn").format(7123456789L));
+
+        assertEquals(7123456789L, new TmfTimestampFormat("Td.SSSSSSSS").parseValue("71.23456789"));
+        assertEquals(7123456789L, new TmfTimestampFormat("Tc.SSSSSSS").parseValue("712.3456789"));
+        assertEquals(7123456789L, new TmfTimestampFormat("Tm.SSSSSS").parseValue("7123.456789"));
+        assertEquals(7123456789L, new TmfTimestampFormat("Tu.SSS").parseValue("7123456.789"));
+        assertEquals(7123456789L, new TmfTimestampFormat("Tn").parseValue("7123456789"));
+
+        assertEquals(-100000L, new TmfTimestampFormat("Tm.S").parseValue("-0.1"));
+        assertEquals(-100000L, new TmfTimestampFormat("Tm.S").parseValue("-.1"));
+        assertEquals(-7000000L, new TmfTimestampFormat("Tm.S").parseValue("-7"));
+        assertEquals(-7000000L, new TmfTimestampFormat("Tm.S").parseValue("-7."));
+        assertEquals(-7000000L, new TmfTimestampFormat("Tm.S").parseValue("-7.0"));
+        assertEquals(-7100000L, new TmfTimestampFormat("Tm.S").parseValue("-7.1"));
+
+        assertEquals("9223372036854775807", new TmfTimestampFormat("Tn").format(9223372036854775807L));
+        assertEquals(9223372036854775807L, new TmfTimestampFormat("Tn").parseValue("9223372036854775807"));
+        assertEquals("-9223372036854775808", new TmfTimestampFormat("Tn").format(-9223372036854775808L));
+        assertEquals(-9223372036854775808L, new TmfTimestampFormat("Tn").parseValue("-9223372036854775808"));
+    }
+
     /**
      * Test parsing of date and time patterns
      *
@@ -324,6 +371,13 @@ public class TmfTimestampFormatTest {
 
         time = new TmfTimestampFormat("yyyy MM dd HH mm ss SSS SSS SSS", GMT, CA).parseValue("2014 \t 1 \t 2 \t 3 \t 4 \t 5 \t 123 456 789");
         assertEquals("2014-01-02 03:04:05.123456789", tsf.format(time));
+
+        time = new TmfTimestampFormat("yyyy-MM-dd HH:mm:ss.SSS", GMT, CA).parseValue("1970-01-01 00:00:00.000");
+        assertEquals("1970-01-01 00:00:00.000000000", tsf.format(time));
+
+        time = new TmfTimestampFormat("yyyy-MM-dd HH:mm:ss.SSS", GMT, CA).parseValue("1969-12-31 23:59:59.123");
+        assertEquals("1969-12-31 23:59:59.123000000", tsf.format(time));
+
     }
 
     /**
index 8ec5f4efb2541a5e52fa5beaeb621a4312db55c0..66b042bbb7c1542f9545c1012246cf8f36a88105 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2015 Ericsson
+ * Copyright (c) 2012, 2016 Ericsson
  *
  * All rights reserved. This program and the accompanying materials are
  * made available under the terms of the Eclipse Public License v1.0 which
@@ -20,8 +20,10 @@ import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.TimeZone;
 
 /**
@@ -38,22 +40,47 @@ import java.util.TimeZone;
  * supported with the following exceptions:
  * <blockquote>
  * <table border=0 cellspacing=3 cellpadding=0 >
- *     <tr bgcolor="#ccccff">
+ *     <tr>
  *         <th align=left>Format
  *         <th align=left>Description
  *         <th align=left>Value Range
  *         <th align=left>Example
- *     <tr bgcolor="#eeeeff">
+ *     <tr>
  *         <td><code>T</code>
  *         <td>The seconds since the epoch
  *         <td><code>0-9223372036</code>
  *         <td><code>1332170682</code>
  *     <tr>
+ *         <td><code>Td</code>
+ *         <td>The deciseconds since the epoch
+ *         <td><code>0-92233720368</code>
+ *         <td><code>13321706825</code>
+ *     <tr>
+ *         <td><code>Tc</code>
+ *         <td>The centiseconds since the epoch
+ *         <td><code>0-922337203685</code>
+ *         <td><code>133217068253</code>
+ *     <tr>
+ *         <td><code>Tm</code>
+ *         <td>The milliseconds since the epoch
+ *         <td><code>0-9223372036854</code>
+ *         <td><code>1332170682539</code>
+ *     <tr>
+ *         <td><code>Tu</code>
+ *         <td>The microseconds since the epoch
+ *         <td><code>0-9223372036854775</code>
+ *         <td><code>1332170682539677</code>
+ *     <tr>
+ *         <td><code>Tn</code>
+ *         <td>The nanoseconds since the epoch
+ *         <td><code>0-9223372036854775807</code>
+ *         <td><code>1332170682539677389</code>
+ *     <tr>
  *         <td><code>S</code>
  *         <td>Millisecond
  *         <td><code>N/A</code>
  *         <td><code>Not supported</code>
- *     <tr bgcolor="#eeeeff">
+ *     <tr>
  *         <td><code>W</code>
  *         <td>Week in month
  *         <td><code>N/A</code>
@@ -73,17 +100,17 @@ import java.util.TimeZone;
  * <h4>Sub-Seconds Patterns</h4>
  * <blockquote>
  * <table border=0 cellspacing=3 cellpadding=0 >
- *     <tr bgcolor="#ccccff">
+ *     <tr>
  *         <th align=left>Format
  *         <th align=left>Description
  *         <th align=left>Value Range
  *         <th align=left>Example
  *     <tr>
  *         <td><code>S</code>
- *         <td>Fraction of second
+ *         <td>Fraction of second (or unit of second)
  *         <td><code>0-999999999</code>
  *         <td><code>123456789</code>
- *     <tr bgcolor="#eeeeff">
+ *     <tr>
  *         <td><code>C</code>
  *         <td>Microseconds in ms
  *         <td><code>0-999</code>
@@ -131,27 +158,33 @@ import java.util.TimeZone;
  *
  * <blockquote>
  * <table border=0 cellspacing=3 cellpadding=0>
- *     <tr bgcolor="#ccccff">
+ *     <tr>
  *         <th align=left>Date and Time Pattern
  *         <th align=left>Result
  *     <tr>
  *         <td><code>"yyyy-MM-dd HH:mm:ss.SSS.SSS.SSS"</code>
  *         <td><code>2012-03-19 11:24:42.539.677.389</code>
- *     <tr bgcolor="#eeeeff">
+ *     <tr>
  *         <td><code>"yyyy-MM-dd HH:mm:ss.SSS.SSS"</code>
  *         <td><code>2012-03-19 11:24:42.539.677</code>
  *     <tr>
  *         <td><code>"yyyy-D HH:mm:ss.SSS.SSS"</code>
  *         <td><code>2012-79 11:24:42.539.677</code>
- *     <tr bgcolor="#eeeeff">
+ *     <tr>
  *         <td><code>"ss,SSSS"</code>
  *         <td><code>42,5397</code>
  *     <tr>
  *         <td><code>"T.SSS SSS SSS"</code>
  *         <td><code>1332170682.539 677 389</code>
- *     <tr bgcolor="#eeeeff">
+ *     <tr>
  *         <td><code>"T"</code>
  *         <td><code>1332170682</code>
+ *     <tr>
+ *         <td><code>"Tm.SSSSSS"</code>
+ *         <td><code>1332170682539.677389</code>
+ *     <tr>
+ *         <td><code>"Tn"</code>
+ *         <td><code>1332170682539677389</code>
  * </table>
  * </blockquote>
  * <p>
@@ -206,6 +239,9 @@ public class TmfTimestampFormat extends SimpleDateFormat {
     // The list of supplementary patterns
     private List<String> fSupplPatterns = new ArrayList<>();
 
+    // The unit of seconds denominator e.g. 10^9 for ns
+    private long fUnitOfSeconds = 1;
+
     // The locale
     private final Locale fLocale;
 
@@ -224,6 +260,20 @@ public class TmfTimestampFormat extends SimpleDateFormat {
      * The optional sub-second delimiter characters.
      */
     protected String fDelimiterChars = " .,-_:;/'\""; //$NON-NLS-1$
+    /**
+     * The map of optional unit of seconds suffix characters that can follow the
+     * T pattern. The map value is the unit of seconds denominator.
+     *
+     * @since 2.0
+     */
+    protected Map<Character, Long> fUnitOfSecondsMap = new HashMap<>();
+    {
+        fUnitOfSecondsMap.put('d', 10L);
+        fUnitOfSecondsMap.put('c', 100L);
+        fUnitOfSecondsMap.put('m', 1000L);
+        fUnitOfSecondsMap.put('u', 1000000L);
+        fUnitOfSecondsMap.put('n', 1000000000L);
+    }
 
     /*
      * The bracketing symbols used to mitigate the risk of a format string
@@ -370,16 +420,16 @@ public class TmfTimestampFormat extends SimpleDateFormat {
         // Split the timestamp value into its sub-components
         long date = value / 1000000; // milliseconds since January 1, 1970, 00:00:00 GMT
         long sec = value / 1000000000;    // seconds since January 1, 1970, 00:00:00 GMT
-        long ms  = Math.abs((value % 1000000000) / 1000000); // milliseconds
-        long cs  = Math.abs((value % 1000000)    / 1000);    // microseconds
-        long ns  = Math.abs(value % 1000);                   // nanoseconds
+        long ms  = Math.abs((value % 1000000000) / 1000000); // 0-999 milliseconds
+        long us  = Math.abs((value % 1000000)    / 1000);    // 0-999 microseconds
+        long ns  = Math.abs(value % 1000);                   // 0-999 nanoseconds
 
         // Adjust for negative value when formatted as a date
-        if (value < 0 && ms + cs + ns > 0 && !super.toPattern().contains(fOpenBracket + "T")) { //$NON-NLS-1$
+        if (value < 0 && ms + us + ns > 0 && !super.toPattern().contains(fOpenBracket + "T")) { //$NON-NLS-1$
             date -= 1;
-            long nanosec = 1000000000 - (1000000 * ms + 1000 * cs + ns);
+            long nanosec = 1000000000 - (1000000 * ms + 1000 * us + ns);
             ms = nanosec / 1000000;
-            cs = (nanosec % 1000000) / 1000;
+            us = (nanosec % 1000000) / 1000;
             ns = nanosec % 1000;
         }
 
@@ -402,14 +452,22 @@ public class TmfTimestampFormat extends SimpleDateFormat {
                         result.insert(0, '-');
                     }
                     val = sec;
+                    if (fUnitOfSeconds != 1) {
+                        // Avoid multiplication to prevent overflow
+                        val = value / (1000000000 / fUnitOfSeconds);
+                    }
                     bufLength = Math.min(length, 10);
                     break;
                 case 'S':
-                    val = 1000000 * ms + 1000 * cs + ns;
+                    val = 1000000 * ms + 1000 * us + ns;
+                    if (fUnitOfSeconds != 1) {
+                        val *= fUnitOfSeconds;
+                        val %= 1000000000;
+                    }
                     bufLength = 9;
                     break;
                 case 'C':
-                    val = cs;
+                    val = us;
                     bufLength = Math.min(length, 3);
                     break;
                 case 'N':
@@ -456,32 +514,35 @@ public class TmfTimestampFormat extends SimpleDateFormat {
             return 0;
         }
 
-        long seconds  = 0;
-        boolean isNegative = source.charAt(0) == '-';
-        boolean isDateTimeFormat = true;
-
         int index = indexOfSourceDecimalSeparator(source);
 
         // Check for seconds in epoch pattern
         for (String pattern : fSupplPatterns) {
             if (pattern.charAt(0) == 'T') {
-                isDateTimeFormat = false;
-                // Remove everything up to the first "." and compute the
+                long unitsOfSecond  = 0;
+                boolean isNegative = source.charAt(0) == '-';
+                // Remove everything up to the decimal separator and compute the
                 // number of seconds since the epoch. If there is no period,
                 // assume an integer value and return immediately
                 if (index == 0 || (isNegative && index <= 1)) {
-                    seconds = 0;
+                    unitsOfSecond = 0;
                 } else if (index == source.length()) {
-                    return new DecimalFormat("0").parse(source).longValue() * 1000000000; //$NON-NLS-1$
+                    return new DecimalFormat("0").parse(source).longValue() * (1000000000 / fUnitOfSeconds); //$NON-NLS-1$
                 } else {
-                    seconds = new DecimalFormat("0").parse(source.substring(0, index)).longValue(); //$NON-NLS-1$
+                    unitsOfSecond = new DecimalFormat("0").parse(source.substring(0, index)).longValue(); //$NON-NLS-1$
                 }
-                break;
+                long nanos = parseSubSeconds(source.substring(index));
+                if (isNegative) {
+                    nanos = -nanos;
+                }
+                // Compute the value in ns
+                return unitsOfSecond * (1000000000 / fUnitOfSeconds) + nanos;
             }
         }
 
-        // If there was no "T" (thus not an interval), parse as a date
-        if (isDateTimeFormat && super.toPattern().length() > 0) {
+        // If there was no "T", parse as a date
+        long seconds  = 0;
+        if (super.toPattern().length() > 0) {
             Date baseDate = super.parse(source.substring(0, index));
             getCalendar();
 
@@ -533,15 +594,13 @@ public class TmfTimestampFormat extends SimpleDateFormat {
             } else {
                 seconds = baseDate.getTime() / 1000;
             }
-        } else if (isDateTimeFormat && ref != Long.MIN_VALUE) {
+        } else if (ref != Long.MIN_VALUE) {
             // If the date and time pattern is empty, adjust for reference
             seconds = ref / 1000000000;
         }
 
         long nanos = parseSubSeconds(source.substring(index));
-        if (isNegative && !isDateTimeFormat) {
-            nanos = -nanos;
-        }
+
         // Compute the value in ns
         return seconds * 1000000000 + nanos;
     }
@@ -690,7 +749,7 @@ public class TmfTimestampFormat extends SimpleDateFormat {
             patternIndex++;
             inputIndex++;
         }
-        return Long.parseLong(digits.toString());
+        return Long.parseLong(digits.toString()) / fUnitOfSeconds;
     }
 
     /**
@@ -757,6 +816,14 @@ public class TmfTimestampFormat extends SimpleDateFormat {
                     pat.append(c);
                     i++;
                 }
+                if (c == 'T' && (i + 1) < length) {
+                    c = pattern.charAt(i + 1);
+                    Long unitOfSeconds = fUnitOfSecondsMap.get(c);
+                    if (unitOfSeconds != null) {
+                        fUnitOfSeconds = unitOfSeconds;
+                        i++;
+                    }
+                }
                 result.append(fCloseBracket);
                 if (includeQuotes) {
                     result.append("'"); //$NON-NLS-1$
This page took 0.031402 seconds and 5 git commands to generate.