]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.utils/src/org/simantics/utils/format/TimeFormat.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.utils / src / org / simantics / utils / format / TimeFormat.java
index 30451e149f9213e181bfccf6e4b4f0b7060ab282..89b14e8b089f2a7c43a55f671061be66a47b5ca0 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.utils.format;\r
-\r
-import java.math.BigDecimal;\r
-import java.math.MathContext;\r
-import java.math.RoundingMode;\r
-import java.text.FieldPosition;\r
-import java.text.Format;\r
-import java.text.ParseException;\r
-import java.text.ParsePosition;\r
-import java.util.regex.Matcher;\r
-import java.util.regex.Pattern;\r
-\r
-/**\r
- * Time format consists of four parts [Year Part] [Day part] [Time part] [Decimal part]\r
- *  <p>\r
- *  Year part. \r
- *    "[y]y "\r
- *    "[yy]y ", and so on.\r
- *  <p>\r
- *  Day part. \r
- *    "[d]d "\r
- *    "[dd]d ", and so on.\r
- *   \r
- *  <p>\r
- *  Time part five formats:\r
- *    "HH:mm:ss"\r
- *    "H:mm:ss"\r
- *    "mm:ss"\r
- *    "ss"\r
- *    "s"\r
- *  <p>\r
- *  When time values are formatted into Strings, hours will be\r
- *  formatted with at most two digits and the the rest is converted\r
- *  into days and years. However, while parsing TimeFormat-Strings\r
- *  into time values (double seconds), the hour part (H) can consist\r
- *  of one or more digits. This is simply for parsing convenience.\r
- *  \r
- *  <p>\r
- *  Decimal part has 1->* decimals. It is optional. It cannot exist without time part. \r
- *    ".d"\r
- *    ".dd"\r
- *    ".ddd", and so on.\r
- * \r
- * @author Toni Kalajainen\r
- */\r
-public class TimeFormat extends Format {\r
-\r
-       private static final long serialVersionUID = 1L;\r
-       \r
-       public static final Pattern PATTERN = \r
-                       Pattern.compile(\r
-                                       "(-)?" +                                    // Minus (-)\r
-                                       "(?:(\\d+)y *)?" +                                                      // Year part    "[y]y"\r
-                                       "(?:(\\d+)d *)?" +                                                      // Day part     "[d]d"\r
-                                       "(?:(?:(\\d{1,}):)??(?:(\\d{1,2}):)?(\\d{1,2}))?" +  // Time part    "[H*]H:mm:ss"\r
-                                   "(?:\\.(\\d+))?"                                                    // Decimal part ".ddd"\r
-                                       );\r
-\r
-       private static final BigDecimal TWO = BigDecimal.valueOf(2L);\r
-\r
-       double maxValue;\r
-       int decimals;\r
-       RoundingMode rounding = RoundingMode.HALF_UP;\r
-       MathContext decimalRoundingContext;\r
-       \r
-       public TimeFormat(double maxValue, int decimals)\r
-       {\r
-               this.maxValue = maxValue;\r
-               this.decimals = decimals;\r
-               this.decimalRoundingContext = new MathContext(Math.max(1, decimals+1), rounding);\r
-       }\r
-\r
-       public void setMaxValue(double maxValue) {\r
-               this.maxValue = maxValue;\r
-       }\r
-       \r
-       public void setDecimals(int decimals) {\r
-               this.decimals = decimals;\r
-               this.decimalRoundingContext = new MathContext(Math.max(1, decimals+1), rounding);\r
-       }\r
-       \r
-       public void setRounding(RoundingMode rounding) {\r
-               this.rounding = rounding;\r
-               this.decimalRoundingContext = new MathContext(Math.max(1, decimals+1), rounding);\r
-       }\r
-\r
-       @Override\r
-       public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {\r
-               // Prevent recurrent locking when invoking toAppendTo-methods.\r
-               synchronized (toAppendTo) {\r
-                       return formatSync(obj, toAppendTo, pos);\r
-               }\r
-       }\r
-\r
-       private StringBuffer formatSync(Object obj, StringBuffer toAppendTo, FieldPosition pos) {\r
-               double x = ( (Number) obj ).doubleValue(); \r
-               int initLen = toAppendTo.length();\r
-\r
-               if (Double.isInfinite(x)) {\r
-                       return toAppendTo.append((x == Float.POSITIVE_INFINITY) ? "\u221E" : "-\u221E");\r
-               } else if (Double.isNaN(x)) {\r
-                       return toAppendTo.append("NaN");\r
-               }\r
-\r
-               if (x<0) {\r
-                       toAppendTo.append("-");\r
-                       x=-x;\r
-                       initLen = toAppendTo.length();\r
-               }\r
-\r
-               // The value of x-floor(x) is between [0,1].\r
-               // We want use BigDecimal to round to the specified number of decimals.\r
-               // The problem is that if x is 0.99999... so that it will be rounded to 1.000...\r
-               // the 1 at the front will count as a decimal in the rounding logic\r
-               // and we end up losing 1 actual decimal.\r
-               // Therefore we add 1.0 to x make it be between [1,2] in which case\r
-               // we can just round to n+1 decimals and it will always work.\r
-               BigDecimal decimalPart = new BigDecimal(x - Math.floor(x) + 1.0);\r
-               decimalPart = decimalPart.round(decimalRoundingContext);\r
-               // decimal is now [1.000..,2.000...].\r
-               // If decimalPart equals 2.0 it means that the\r
-               // requested decimal part value was close enough\r
-               // to 1.0 that it overflows and becomes 000...\r
-               // This means that the overflow must be added to/subtracted from\r
-               // the integer part of the input number.\r
-               boolean needToRound = TWO.compareTo(decimalPart) == 0;\r
-\r
-               double max = Math.max(this.maxValue, x);\r
-               long xl = needToRound ? (long) Math.round( x ) : (long) Math.floor( x );\r
-\r
-               // Write years\r
-               if (xl>=(24L*60L*60L*365L)) {\r
-                       long years = xl / (24L*60L*60L*365L);\r
-                       toAppendTo.append( (long) years );\r
-                       toAppendTo.append("y");\r
-               }\r
-\r
-               // Write days\r
-               if (xl>=(24L*60L*60L)) {\r
-                       if (toAppendTo.length()!=initLen) toAppendTo.append(' ');\r
-                       long days = (xl % (24L*60L*60L*365L)) / (24L*60L*60L); \r
-                       toAppendTo.append( (long) days );\r
-                       toAppendTo.append("d");\r
-               }\r
-\r
-               // Write HH:mm:ss\r
-               if (decimals>=-5) {\r
-                       if (toAppendTo.length()!=initLen) toAppendTo.append(' ');\r
-                       // Seconds of the day\r
-                       long seconds = xl % 86400L;\r
-                       \r
-                       // Write HH:\r
-                       if (max>=24*60) {\r
-                               long hh = seconds / 3600;\r
-                               if (x>3600) {\r
-                                       toAppendTo.append( hh/10 );\r
-                               }\r
-                               toAppendTo.append( hh%10 );\r
-                               toAppendTo.append(":");\r
-                       }\r
-                       \r
-                       // Write mm:\r
-                       if (max>=60) {\r
-                               long mm = (seconds / 60) % 60;\r
-                               toAppendTo.append( mm/10 );\r
-                               toAppendTo.append( mm%10 );\r
-                               toAppendTo.append(":");\r
-                       }\r
-                       \r
-                       // Write ss\r
-                       {\r
-                               long ss = seconds % 60;\r
-                               if (x>=10 || initLen!=toAppendTo.length()) {\r
-                                       toAppendTo.append( ss/10 );\r
-                               }\r
-                               toAppendTo.append( ss%10 );\r
-                       }\r
-                       \r
-                       // Write milliseconds and more\r
-                       if (decimals>0) {\r
-                               // add the decimal separator and part to the result.\r
-                               toAppendTo.append('.');\r
-                               String dps = decimalPart.toString();\r
-                               int decimalPartLen = dps.length();\r
-                               int trailingZeros = decimals;\r
-                               if (decimalPartLen > 2) {\r
-                                       // If the original number was exact (e.g. 1)\r
-                                       // dp will contain only "1"\r
-                                       toAppendTo.append(dps, 2, decimalPartLen);\r
-                                       trailingZeros -= decimalPartLen - 2; \r
-                               }\r
-                               for (int d = 0; d < trailingZeros; ++d)\r
-                                       toAppendTo.append('0');\r
-                       }\r
-               }\r
-               \r
-               if (toAppendTo.length()==initLen) toAppendTo.append('-');\r
-               \r
-               return toAppendTo;\r
-       }\r
-\r
-       @Override\r
-       public Object parseObject(String source) throws ParseException {\r
-               Matcher m = PATTERN.matcher(source);\r
-               if (!m.matches()) {\r
-                       try {\r
-                               return Double.parseDouble( source );\r
-                       } catch (NumberFormatException nfe) {\r
-                               throw new ParseException("TimeFormat.parseObject('" + source + "') failed", m.regionStart());\r
-                       }\r
-               }\r
-               \r
-               String negG = m.group(1);\r
-               String yearG = m.group(2);\r
-               String dayG = m.group(3);\r
-               String hourG = m.group(4);\r
-               String minuteG = m.group(5);\r
-               String secondG = m.group(6);\r
-               String decimalG = m.group(7);\r
-               boolean negative = negG==null?false:negG.equals("-");\r
-               double years = yearG==null?0.:Double.parseDouble(yearG);\r
-               double days = dayG==null?0.:Double.parseDouble(dayG);\r
-               double hours = hourG==null?0.:Double.parseDouble(hourG);\r
-               double minutes = minuteG==null?0.:Double.parseDouble(minuteG);\r
-               double seconds = secondG==null?0.:Double.parseDouble(secondG);\r
-               double decimals = decimalG==null?0.:Double.parseDouble(decimalG)/Math.pow(10, decimalG.length());\r
-\r
-               double value = years*31536000. + days*86400. + hours*3600. + minutes*60. + seconds + decimals;\r
-               if ( negative ) value = -value;\r
-               return value;\r
-       }\r
-       \r
-       @Override\r
-       public Object parseObject(String source, ParsePosition pos) {\r
-               try {\r
-            return parseObject(source);\r
-        } catch (ParseException e) {\r
-            pos.setErrorIndex(e.getErrorOffset());\r
-            return null;\r
-        }\r
-       }\r
-       \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.utils.format;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.math.RoundingMode;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParseException;
+import java.text.ParsePosition;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Time format consists of four parts [Year Part] [Day part] [Time part] [Decimal part]
+ *  <p>
+ *  Year part. 
+ *    "[y]y "
+ *    "[yy]y ", and so on.
+ *  <p>
+ *  Day part. 
+ *    "[d]d "
+ *    "[dd]d ", and so on.
+ *   
+ *  <p>
+ *  Time part five formats:
+ *    "HH:mm:ss"
+ *    "H:mm:ss"
+ *    "mm:ss"
+ *    "ss"
+ *    "s"
+ *  <p>
+ *  When time values are formatted into Strings, hours will be
+ *  formatted with at most two digits and the the rest is converted
+ *  into days and years. However, while parsing TimeFormat-Strings
+ *  into time values (double seconds), the hour part (H) can consist
+ *  of one or more digits. This is simply for parsing convenience.
+ *  
+ *  <p>
+ *  Decimal part has 1->* decimals. It is optional. It cannot exist without time part. 
+ *    ".d"
+ *    ".dd"
+ *    ".ddd", and so on.
+ * 
+ * @author Toni Kalajainen
+ */
+public class TimeFormat extends Format {
+
+       private static final long serialVersionUID = 1L;
+       
+       public static final Pattern PATTERN = 
+                       Pattern.compile(
+                                       "(-)?" +                                    // Minus (-)
+                                       "(?:(\\d+)y *)?" +                                                      // Year part    "[y]y"
+                                       "(?:(\\d+)d *)?" +                                                      // Day part     "[d]d"
+                                       "(?:(?:(\\d{1,}):)??(?:(\\d{1,2}):)?(\\d{1,2}))?" +  // Time part    "[H*]H:mm:ss"
+                                   "(?:\\.(\\d+))?"                                                    // Decimal part ".ddd"
+                                       );
+
+       private static final BigDecimal TWO = BigDecimal.valueOf(2L);
+
+       double maxValue;
+       int decimals;
+       RoundingMode rounding = RoundingMode.HALF_UP;
+       MathContext decimalRoundingContext;
+       
+       public TimeFormat(double maxValue, int decimals)
+       {
+               this.maxValue = maxValue;
+               this.decimals = decimals;
+               this.decimalRoundingContext = new MathContext(Math.max(1, decimals+1), rounding);
+       }
+
+       public void setMaxValue(double maxValue) {
+               this.maxValue = maxValue;
+       }
+       
+       public void setDecimals(int decimals) {
+               this.decimals = decimals;
+               this.decimalRoundingContext = new MathContext(Math.max(1, decimals+1), rounding);
+       }
+       
+       public void setRounding(RoundingMode rounding) {
+               this.rounding = rounding;
+               this.decimalRoundingContext = new MathContext(Math.max(1, decimals+1), rounding);
+       }
+
+       @Override
+       public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
+               // Prevent recurrent locking when invoking toAppendTo-methods.
+               synchronized (toAppendTo) {
+                       return formatSync(obj, toAppendTo, pos);
+               }
+       }
+
+       private StringBuffer formatSync(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
+               double x = ( (Number) obj ).doubleValue(); 
+               int initLen = toAppendTo.length();
+
+               if (Double.isInfinite(x)) {
+                       return toAppendTo.append((x == Float.POSITIVE_INFINITY) ? "\u221E" : "-\u221E");
+               } else if (Double.isNaN(x)) {
+                       return toAppendTo.append("NaN");
+               }
+
+               if (x<0) {
+                       toAppendTo.append("-");
+                       x=-x;
+                       initLen = toAppendTo.length();
+               }
+
+               // The value of x-floor(x) is between [0,1].
+               // We want use BigDecimal to round to the specified number of decimals.
+               // The problem is that if x is 0.99999... so that it will be rounded to 1.000...
+               // the 1 at the front will count as a decimal in the rounding logic
+               // and we end up losing 1 actual decimal.
+               // Therefore we add 1.0 to x make it be between [1,2] in which case
+               // we can just round to n+1 decimals and it will always work.
+               BigDecimal decimalPart = new BigDecimal(x - Math.floor(x) + 1.0);
+               decimalPart = decimalPart.round(decimalRoundingContext);
+               // decimal is now [1.000..,2.000...].
+               // If decimalPart equals 2.0 it means that the
+               // requested decimal part value was close enough
+               // to 1.0 that it overflows and becomes 000...
+               // This means that the overflow must be added to/subtracted from
+               // the integer part of the input number.
+               boolean needToRound = TWO.compareTo(decimalPart) == 0;
+
+               double max = Math.max(this.maxValue, x);
+               long xl = needToRound ? (long) Math.round( x ) : (long) Math.floor( x );
+
+               // Write years
+               if (xl>=(24L*60L*60L*365L)) {
+                       long years = xl / (24L*60L*60L*365L);
+                       toAppendTo.append( (long) years );
+                       toAppendTo.append("y");
+               }
+
+               // Write days
+               if (xl>=(24L*60L*60L)) {
+                       if (toAppendTo.length()!=initLen) toAppendTo.append(' ');
+                       long days = (xl % (24L*60L*60L*365L)) / (24L*60L*60L); 
+                       toAppendTo.append( (long) days );
+                       toAppendTo.append("d");
+               }
+
+               // Write HH:mm:ss
+               if (decimals>=-5) {
+                       if (toAppendTo.length()!=initLen) toAppendTo.append(' ');
+                       // Seconds of the day
+                       long seconds = xl % 86400L;
+                       
+                       // Write HH:
+                       if (max>=24*60) {
+                               long hh = seconds / 3600;
+                               if (x>3600) {
+                                       toAppendTo.append( hh/10 );
+                               }
+                               toAppendTo.append( hh%10 );
+                               toAppendTo.append(":");
+                       }
+                       
+                       // Write mm:
+                       if (max>=60) {
+                               long mm = (seconds / 60) % 60;
+                               toAppendTo.append( mm/10 );
+                               toAppendTo.append( mm%10 );
+                               toAppendTo.append(":");
+                       }
+                       
+                       // Write ss
+                       {
+                               long ss = seconds % 60;
+                               if (x>=10 || initLen!=toAppendTo.length()) {
+                                       toAppendTo.append( ss/10 );
+                               }
+                               toAppendTo.append( ss%10 );
+                       }
+                       
+                       // Write milliseconds and more
+                       if (decimals>0) {
+                               // add the decimal separator and part to the result.
+                               toAppendTo.append('.');
+                               String dps = decimalPart.toString();
+                               int decimalPartLen = dps.length();
+                               int trailingZeros = decimals;
+                               if (decimalPartLen > 2) {
+                                       // If the original number was exact (e.g. 1)
+                                       // dp will contain only "1"
+                                       toAppendTo.append(dps, 2, decimalPartLen);
+                                       trailingZeros -= decimalPartLen - 2; 
+                               }
+                               for (int d = 0; d < trailingZeros; ++d)
+                                       toAppendTo.append('0');
+                       }
+               }
+               
+               if (toAppendTo.length()==initLen) toAppendTo.append('-');
+               
+               return toAppendTo;
+       }
+
+       @Override
+       public Object parseObject(String source) throws ParseException {
+               Matcher m = PATTERN.matcher(source);
+               if (!m.matches()) {
+                       try {
+                               return Double.parseDouble( source );
+                       } catch (NumberFormatException nfe) {
+                               throw new ParseException("TimeFormat.parseObject('" + source + "') failed", m.regionStart());
+                       }
+               }
+               
+               String negG = m.group(1);
+               String yearG = m.group(2);
+               String dayG = m.group(3);
+               String hourG = m.group(4);
+               String minuteG = m.group(5);
+               String secondG = m.group(6);
+               String decimalG = m.group(7);
+               boolean negative = negG==null?false:negG.equals("-");
+               double years = yearG==null?0.:Double.parseDouble(yearG);
+               double days = dayG==null?0.:Double.parseDouble(dayG);
+               double hours = hourG==null?0.:Double.parseDouble(hourG);
+               double minutes = minuteG==null?0.:Double.parseDouble(minuteG);
+               double seconds = secondG==null?0.:Double.parseDouble(secondG);
+               double decimals = decimalG==null?0.:Double.parseDouble(decimalG)/Math.pow(10, decimalG.length());
+
+               double value = years*31536000. + days*86400. + hours*3600. + minutes*60. + seconds + decimals;
+               if ( negative ) value = -value;
+               return value;
+       }
+       
+       @Override
+       public Object parseObject(String source, ParsePosition pos) {
+               try {
+            return parseObject(source);
+        } catch (ParseException e) {
+            pos.setErrorIndex(e.getErrorOffset());
+            return null;
+        }
+       }
+       
+}