From 2697f5947c81dfcb2f9d0e44f5156a6a4c4eaa6c Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Mon, 9 Sep 2019 14:40:28 +0200 Subject: [PATCH] [Major] Removed ISO8061Duration, replace with PeriodDuration --- .../model/query/ParameterSelection.java | 10 - .../java/li/strolch/model/ModelGenerator.java | 4 +- .../model/parameter/DurationParameter.java | 66 ++++- .../visitor/SetParameterValueVisitor.java | 3 +- .../model/parameter/ParameterTest.java | 7 +- .../execution/policy/DurationExecution.java | 2 +- .../strolch/utils/iso8601/DurationFormat.java | 45 --- .../strolch/utils/iso8601/FormatFactory.java | 63 +--- .../utils/iso8601/ISO8601Duration.java | 270 ------------------ .../utils/iso8601/ISO8601FormatFactory.java | 35 --- .../utils/iso8601/ISO8601Worktime.java | 245 ---------------- 11 files changed, 61 insertions(+), 689 deletions(-) delete mode 100644 li.strolch.utils/src/main/java/li/strolch/utils/iso8601/DurationFormat.java delete mode 100644 li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Duration.java delete mode 100644 li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Worktime.java diff --git a/li.strolch.agent/src/main/java/li/strolch/model/query/ParameterSelection.java b/li.strolch.agent/src/main/java/li/strolch/model/query/ParameterSelection.java index bac8163d4..2e8cc01c2 100644 --- a/li.strolch.agent/src/main/java/li/strolch/model/query/ParameterSelection.java +++ b/li.strolch.agent/src/main/java/li/strolch/model/query/ParameterSelection.java @@ -22,7 +22,6 @@ import java.util.List; import li.strolch.utils.StringMatchMode; import li.strolch.utils.collections.DateRange; import li.strolch.utils.dbc.DBC; -import li.strolch.utils.iso8601.ISO8601FormatFactory; /** * @author Robert von Burg @@ -100,15 +99,6 @@ public abstract class ParameterSelection implements Selection { return new DateParameterSelection(bagKey, paramKey, value); } - public static DurationParameterSelection durationSelection(String bagKey, String paramKey, String valueAsString) { - return durationSelection(bagKey, paramKey, - ISO8601FormatFactory.getInstance().getDurationFormat().parse(valueAsString)); - } - - public static DurationParameterSelection durationSelection(String bagKey, String paramKey, long value) { - return new DurationParameterSelection(bagKey, paramKey, value); - } - public static DateRangeParameterSelection dateRangeSelection(String bagKey, String paramKey, DateRange dateRange) { return new DateRangeParameterSelection(bagKey, paramKey, dateRange); } diff --git a/li.strolch.model/src/main/java/li/strolch/model/ModelGenerator.java b/li.strolch.model/src/main/java/li/strolch/model/ModelGenerator.java index deb3f7fa7..99d965326 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/ModelGenerator.java +++ b/li.strolch.model/src/main/java/li/strolch/model/ModelGenerator.java @@ -29,7 +29,7 @@ import li.strolch.model.policy.PolicyDefs; import li.strolch.model.timedstate.*; import li.strolch.model.timevalue.impl.*; import li.strolch.utils.helper.StringHelper; -import li.strolch.utils.iso8601.ISO8601FormatFactory; +import li.strolch.utils.time.PeriodDuration; /** * Class which can be used to generate objects which implement {@link StrolchElement}. These generated classes can then @@ -479,7 +479,7 @@ public class ModelGenerator { bag.addParameter(stringListP); DurationParameter durationParam = new DurationParameter(PARAM_DURATION_ID, PARAM_DURATION_NAME, - ISO8601FormatFactory.getInstance().getDurationFormat().parse("P1D")); + PeriodDuration.parse("P1D")); durationParam.setIndex(8); bag.addParameter(durationParam); diff --git a/li.strolch.model/src/main/java/li/strolch/model/parameter/DurationParameter.java b/li.strolch.model/src/main/java/li/strolch/model/parameter/DurationParameter.java index e0317637c..e835b7b99 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/parameter/DurationParameter.java +++ b/li.strolch.model/src/main/java/li/strolch/model/parameter/DurationParameter.java @@ -15,17 +15,20 @@ */ package li.strolch.model.parameter; +import java.time.Duration; +import java.time.Period; + import li.strolch.model.StrolchValueType; import li.strolch.model.visitor.StrolchElementVisitor; import li.strolch.utils.dbc.DBC; -import li.strolch.utils.iso8601.ISO8601FormatFactory; +import li.strolch.utils.time.PeriodDuration; /** * @author Robert von Burg */ -public class DurationParameter extends AbstractParameter { +public class DurationParameter extends AbstractParameter { - private Long value; + private PeriodDuration value; /** * Empty constructor @@ -44,31 +47,61 @@ public class DurationParameter extends AbstractParameter { * @param value * the value */ - public DurationParameter(String id, String name, Long value) { + public DurationParameter(String id, String name, PeriodDuration value) { super(id, name); setValue(value); } + /** + * Default Constructor + * + * @param id + * the id + * @param name + * the name + * @param millis + * the value as milliseconds + */ + public DurationParameter(String id, String name, long millis) { + super(id, name); + setValue(PeriodDuration.of(Period.ZERO, Duration.ofMillis(millis))); + } + @Override public String getValueAsString() { - return ISO8601FormatFactory.getInstance().formatDuration(this.value); + return this.value.toString(); } @SuppressWarnings("unchecked") @Override - public Long getValue() { + public PeriodDuration getValue() { return this.value; } @Override - public void setValue(Long value) { + public void setValue(PeriodDuration value) { assertNotReadonly(); validateValue(value); this.value = value; } + public void setValueFrom(long millis) { + assertNotReadonly(); + this.value = PeriodDuration.of(Period.ZERO, Duration.ofMillis(millis)); + } + + public void setValueFrom(Period value) { + assertNotReadonly(); + this.value = PeriodDuration.of(value); + } + + public void setValueFrom(Duration duration) { + assertNotReadonly(); + this.value = PeriodDuration.of(duration); + } + @Override - public void setValueFrom(Parameter parameter) { + public void setValueFrom(Parameter parameter) { assertNotReadonly(); this.value = parameter.getValue(); } @@ -81,24 +114,28 @@ public class DurationParameter extends AbstractParameter { @Override public void clear() { assertNotReadonly(); - this.value = 0L; + this.value = PeriodDuration.ZERO; } @Override public boolean isEmpty() { - return this.value == 0L; + return this.value.equals(PeriodDuration.ZERO); } @Override - public boolean isEqualTo(Parameter otherValue) { + public boolean isEqualTo(Parameter otherValue) { return this.value.equals(otherValue.getValue()); } @Override - public boolean isEqualTo(Long otherValue) { + public boolean isEqualTo(PeriodDuration otherValue) { return this.value.equals(otherValue); } + public long toMillis() { + return this.value.toMillis(); + } + @Override public void setValueFromString(String valueAsString) { setValue(parseFromString(valueAsString)); @@ -130,8 +167,8 @@ public class DurationParameter extends AbstractParameter { return visitor.visitDurationParam(this); } - public static Long parseFromString(String valueS) { - return ISO8601FormatFactory.getInstance().getDurationFormat().parse(valueS); + public static PeriodDuration parseFromString(String valueS) { + return PeriodDuration.parse(valueS); } @Override @@ -139,5 +176,4 @@ public class DurationParameter extends AbstractParameter { DBC.PRE.assertEquals("Not same Parameter types!", this.getType(), o.getType()); return this.getValue().compareTo(((DurationParameter) o).getValue()); } - } diff --git a/li.strolch.model/src/main/java/li/strolch/model/visitor/SetParameterValueVisitor.java b/li.strolch.model/src/main/java/li/strolch/model/visitor/SetParameterValueVisitor.java index 62755aa82..7eeb9fda8 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/visitor/SetParameterValueVisitor.java +++ b/li.strolch.model/src/main/java/li/strolch/model/visitor/SetParameterValueVisitor.java @@ -19,6 +19,7 @@ import java.util.Date; import java.util.List; import li.strolch.model.parameter.*; +import li.strolch.utils.time.PeriodDuration; /** * @author Robert von Burg @@ -45,7 +46,7 @@ public class SetParameterValueVisitor implements ParameterVisitor { @Override public Void visitDurationParam(DurationParameter param) { - param.setValue((Long) this.value); + param.setValue((PeriodDuration) this.value); return null; } diff --git a/li.strolch.model/src/test/java/li/strolch/model/parameter/ParameterTest.java b/li.strolch.model/src/test/java/li/strolch/model/parameter/ParameterTest.java index 31083ef3f..b2a4d3c24 100644 --- a/li.strolch.model/src/test/java/li/strolch/model/parameter/ParameterTest.java +++ b/li.strolch.model/src/test/java/li/strolch/model/parameter/ParameterTest.java @@ -11,7 +11,7 @@ import java.util.Date; import li.strolch.model.ModelGenerator; import li.strolch.model.Resource; -import li.strolch.utils.iso8601.ISO8601FormatFactory; +import li.strolch.utils.time.PeriodDuration; import org.junit.Before; import org.junit.Test; @@ -187,11 +187,12 @@ public class ParameterTest { DurationParameter other = new DurationParameter("other", "other", 42L); DurationParameter p = resource.getParameter(BAG_ID, PARAM_DURATION_ID, true); - assertEquals(Long.valueOf(ISO8601FormatFactory.getInstance().getDurationFormat().parse("P1D")), p.getValue()); + assertEquals(PeriodDuration.parse("P1D"), p.getValue()); p.clear(); assertTrue(p.isEmpty()); - assertEquals(Long.valueOf(0L), p.getValue()); + assertEquals(PeriodDuration.ZERO, p.getValue()); + assertEquals(0L, p.toMillis()); p.setValueFrom(other); assertTrue(p.isEqualTo(other.getValue())); diff --git a/li.strolch.service/src/main/java/li/strolch/execution/policy/DurationExecution.java b/li.strolch.service/src/main/java/li/strolch/execution/policy/DurationExecution.java index 05c447336..218b82601 100644 --- a/li.strolch.service/src/main/java/li/strolch/execution/policy/DurationExecution.java +++ b/li.strolch.service/src/main/java/li/strolch/execution/policy/DurationExecution.java @@ -30,7 +30,7 @@ public class DurationExecution extends SimpleExecution { String realmName = tx().getRealmName(); Locator locator = action.getLocator(); logger.info("Executing action " + action.getLocator() + " has a duration of " + durationP.getValueAsString()); - getDelayedExecutionTimer().execute(realmName, getContainer(), locator, durationP.getValue()); + getDelayedExecutionTimer().execute(realmName, getContainer(), locator, durationP.toMillis()); super.toExecution(action); } diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/DurationFormat.java b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/DurationFormat.java deleted file mode 100644 index 9511fab8b..000000000 --- a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/DurationFormat.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013 Martin Smock - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package li.strolch.utils.iso8601; - -/** - * Interface for duration formatting - * - * @author Martin Smock <smock.martin@gmail.com> - */ -public interface DurationFormat { - - /** - * format a long to string - * - * @param l - * the long duration to format - * - * @return formatted string if the long argument - */ - public String format(long l); - - /** - * parse a string to long - * - * @param s - * the string to parse - * - * @return the long value parsed - */ - public long parse(String s); - -} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/FormatFactory.java b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/FormatFactory.java index 24c99d249..b5d148284 100644 --- a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/FormatFactory.java +++ b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/FormatFactory.java @@ -28,24 +28,10 @@ public interface FormatFactory { /** * return the formatter for dates * - * @return {@link DurationFormat} + * @return {@link DateFormat} */ public DateFormat getDateFormat(); - /** - * return the formatter for durations - * - * @return {@link DurationFormat} - */ - public DurationFormat getDurationFormat(); - - /** - * return the formatter for work time - * - * @return {@link WorktimeFormat} - */ - public WorktimeFormat getWorktimeFormat(); - /** * the date format used in xml import and export * @@ -53,13 +39,6 @@ public interface FormatFactory { */ public DateFormat getXmlDateFormat(); - /** - * the duration format used in xml import and export - * - * @return {@link DurationFormat} - */ - public DurationFormat getXmlDurationFormat(); - /** * Formats a date using {@link #getDateFormat()} * @@ -80,26 +59,6 @@ public interface FormatFactory { */ public String formatDate(long date); - /** - * Formats a duration using {@link #getDateFormat()} - * - * @param duration - * the duration to format to string - * - * @return String representation of the duration - */ - public String formatDuration(long duration); - - /** - * Formats a work time duration using {@link #getDateFormat()} - * - * @param worktime - * the work time duration to format to string - * - * @return String representation of the work time duration - */ - public String formatWorktime(long worktime); - /** * Formats a floating point number to have the configured number of decimals * @@ -119,24 +78,4 @@ public interface FormatFactory { * @return the date */ public Date parseDate(String date); - - /** - * Parses a duration using {@link #getDateFormat()} - * - * @param duration - * the string to parse to duration - * - * @return the duration - */ - public long parseDuration(String duration); - - /** - * Parses a work time duration using {@link #getDateFormat()} - * - * @param worktime - * the string duration to parse to work time - * - * @return the work time - */ - public long parseWorktime(String worktime); } \ No newline at end of file diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Duration.java b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Duration.java deleted file mode 100644 index 653c4d4e2..000000000 --- a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Duration.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright 2013 Martin Smock - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package li.strolch.utils.iso8601; - -/** - *

- * Duration is defined as a duration of time, as specified in ISO 8601, Section 5.5.3.2. Its lexical representation is - * the ISO 8601 extended format: PnYnMnDnTnHnMnS - *

- *
    - *
  • The "P" (period) is required
  • - *
  • "n" represents a positive number
  • - *
  • years is (Y)
  • - *
  • months is (M)
  • - *
  • days is (D)
  • - *
  • time separator is (T), required if any lower terms are given
  • - *
  • hours is (H)
  • - *
  • minutes is (M)
  • - *
  • seconds is (S)
  • - *
- *

- * An optional preceding minus sign ("-") is also allowed to indicate a negative duration. If the sign is omitted then a - * positive duration is assumed. For example: <an_element duration="PT2H5M2.37S" /> is a 2 hour, 5 minute, - * and 2.37 second duration - *

- *

- * Remark: since a duration of a day may be measured in hours may vary from 23 an 25 a duration day unit doesn't - * have a meaning, if we do not know either the start or the end, we restrict ourself to measure a duration in hours, - * minutes and seconds - *

- * - * @author Martin Smock <smock.martin@gmail.com> - * @author Michael Gatto <michael@gatto.ch> (reimplementation using enum) - */ -@SuppressWarnings("nls") -public class ISO8601Duration implements DurationFormat { - - /** - * The time representations available, as enum, with the associated millis. - * - * @author gattom - */ - public enum TimeDuration { - SECOND(1000, 'S'), - MINUTE(60 * SECOND.duration(), 'M'), - HOUR(60 * MINUTE.duration(), 'H'), - DAY(24 * HOUR.duration(), 'D'), - WEEK(7 * DAY.duration(), 'W'), - MONTH(30 * DAY.duration(), 'M'), - YEAR(12 * MONTH.duration(), 'Y'); - - final long millis; - final char isoChar; - - TimeDuration(long milli, char isorep) { - this.millis = milli; - this.isoChar = isorep; - } - - public long duration() { - return this.millis; - } - - public static TimeDuration getTimeDurationFor(String isostring, int unitIndex) { - char duration = isostring.charAt(unitIndex); - switch (duration) { - case 'S': - if (isostring.substring(0, unitIndex).contains("T")) - return SECOND; - throw new NumberFormatException( - duration + " is not a valid unit of time in ISO8601 without a preceeding T (e.g.: PT1S)"); - case 'H': - if (isostring.substring(0, unitIndex).contains("T")) - return HOUR; - throw new NumberFormatException( - duration + " is not a valid unit of time in ISO8601 without a preceeding T (e.g.: PT1H)"); - case 'D': - return DAY; - case 'W': - return WEEK; - case 'Y': - return YEAR; - case 'M': - if (isostring.substring(0, unitIndex).contains("T")) - return MINUTE; - return MONTH; - default: - throw new NumberFormatException(duration + " is not a valid unit of time in ISO8601"); - } - } - } - - /** - * check if c is a number char including the decimal decimal dot (.) - * - * @param c - * the character to check - * - * @return boolean return true if the given char is a number or a decimal dot (.), false otherwise - */ - private static boolean isNumber(char c) { - - boolean isNumber = Character.isDigit(c) || (c == '.'); - return isNumber; - - } - - /** - * Parses the given string to a pseudo ISO 8601 duration - * - * @param s - * the string to be parsed to a duration which must be coded as a ISO8601 value - * - * @return long the time value which represents the duration - */ - @Override - public long parse(String s) { - - long newResult = 0; - - // throw exception, if the string is not of length > 2 - if (s == null || s.length() < 3) - throw new NumberFormatException(s + " cannot be parsed to ISO 8601 Duration"); - - char p = s.charAt(0); - - // the first char must be a P for ISO8601 duration - if (p != 'P') - throw new NumberFormatException(s + " cannot be parsed to ISO 8601 Duration"); - - int newposition = 1; - do { - if (s.charAt(newposition) == 'T') { - // skip the separator specifying where the time starts. - newposition++; - } - - // read the string representing the numeric value - String val = parseNumber(newposition, s); - double numVal = Double.parseDouble(val); - newposition += val.length(); - - // get the time unit - TimeDuration unit = TimeDuration.getTimeDurationFor(s, newposition); - - // skip the time duration character - newposition++; - - // increment the value. - newResult += unit.duration() * numVal; - - } while (newposition < s.length()); - - return newResult; - } - - /** - * Return the substring of s starting at index i (in s) that contains a numeric string. - * - * @param index - * The start index in string s - * @param s - * The string to analyze - * - * @return the substring containing the numeric portion of s starting at index i. - */ - private String parseNumber(int index, String s) { - int i = index; - int start = i; - while (i < s.length()) { - if (!isNumber(s.charAt(i))) - break; - i++; - } - String substring = s.substring(start, i); - return substring; - } - - /** - * Format the given time duration unit into the string buffer. This function displays the given duration in units of - * the given unit, and returns the remainder. - *

- * Thus, a duration of 86401000 (one day and one second) will add the representation of one day if unit is DAY (1D) - * and return 1000 as the remainder with respect of this unit. If the given unit is HOUR, then this function adds - * 24H to the {@link StringBuilder}, and returns 1000 as the remainder. - * - * @param sb - * The {@link StringBuilder} to add the given duration with the right unit - * @param duration - * The duration to add - * @param unit - * The unit of this duration - * - * @return The remainder of the given duration, modulo the time unit. - */ - private long formatTimeDuration(StringBuilder sb, long duration, TimeDuration unit) { - - long remainder = duration; - if (unit.equals(TimeDuration.SECOND) || remainder >= unit.duration()) { - - long quantity = remainder / unit.duration(); - remainder = remainder % unit.duration(); - sb.append(quantity); - - if (unit.equals(TimeDuration.SECOND)) { - long millis = remainder; - if (millis == 0) { - // to not have the decimal point - } else if (millis > 99) { - sb.append("." + millis); - } else if (millis > 9) { - sb.append(".0" + millis); - } else { - sb.append(".00" + millis); - } - } - - sb.append(unit.isoChar); - } - - return remainder; - } - - /** - * Formats the given time duration to a pseudo ISO 8601 duration string - * - * @param duration - * the duration - * - * @return String the duration formatted as a ISO8601 duration string - */ - @Override - public String format(long duration) { - - // XXX this is a preliminary help to solve the situation where this method sometimes returns P - if (duration < 0l) - throw new RuntimeException("A duration can not be negative!"); - - if (duration == 0l) - return "P0D"; - - StringBuilder sb = new StringBuilder(); - sb.append('P'); - - long remainder = formatTimeDuration(sb, duration, TimeDuration.YEAR); - remainder = formatTimeDuration(sb, remainder, TimeDuration.MONTH); - remainder = formatTimeDuration(sb, remainder, TimeDuration.DAY); - if (remainder > 0) { - sb.append('T'); - remainder = formatTimeDuration(sb, remainder, TimeDuration.HOUR); - remainder = formatTimeDuration(sb, remainder, TimeDuration.MINUTE); - remainder = formatTimeDuration(sb, remainder, TimeDuration.SECOND); - } - return sb.toString(); - } - -} diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601FormatFactory.java b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601FormatFactory.java index 7c80403f9..5c8c8fd52 100644 --- a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601FormatFactory.java +++ b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601FormatFactory.java @@ -47,26 +47,11 @@ public class ISO8601FormatFactory implements FormatFactory { return new ISO8601(); } - @Override - public ISO8601Duration getDurationFormat() { - return new ISO8601Duration(); - } - - @Override - public ISO8601Worktime getWorktimeFormat() { - return new ISO8601Worktime(); - } - @Override public ISO8601 getXmlDateFormat() { return new ISO8601(); } - @Override - public ISO8601Duration getXmlDurationFormat() { - return new ISO8601Duration(); - } - @Override public String formatDate(Date date) { return getDateFormat().format(date); @@ -77,16 +62,6 @@ public class ISO8601FormatFactory implements FormatFactory { return getDateFormat().format(date); } - @Override - public String formatDuration(long duration) { - return getDurationFormat().format(duration); - } - - @Override - public String formatWorktime(long worktime) { - return getDurationFormat().format(worktime); - } - @Override public String formatFloat(double value) { return Double.toString(MathHelper.toPrecision(value)); @@ -96,14 +71,4 @@ public class ISO8601FormatFactory implements FormatFactory { public Date parseDate(String date) { return getDateFormat().parse(date); } - - @Override - public long parseDuration(String duration) { - return getDurationFormat().parse(duration); - } - - @Override - public long parseWorktime(String worktime) { - return getDurationFormat().parse(worktime); - } } diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Worktime.java b/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Worktime.java deleted file mode 100644 index e278201a4..000000000 --- a/li.strolch.utils/src/main/java/li/strolch/utils/iso8601/ISO8601Worktime.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2013 Martin Smock - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package li.strolch.utils.iso8601; - -/** - *

- * Duration is defined as a duration of time, as specified in ISO 8601, Section 5.5.3.2. Its lexical representation is - * the ISO 8601 extended format: PnYnMnDnTnHnMnS - *

- *
    - *
  • The "P" (period) is required
  • - *
  • "n" represents a positive number
  • - *
  • years is (Y)
  • - *
  • months is (M)
  • - *
  • days is (D)
  • - *
  • time separator is (T), required if any lower terms are given
  • - *
  • hours is (H)
  • - *
  • minutes is (M)
  • - *
  • seconds is (S)
  • - *
- *

- * An optional preceding minus sign ("-") is also allowed to indicate a negative duration. If the sign is omitted then a - * positive duration is assumed. For example: <an_element duration="PT2H5M2.37S" /> is a 2 hour, 5 minute, - * and 2.37 second duration - *

- *

- * Remark: since a duration of a day may be measured in hours may vary from 23 an 25 a duration day unit doesn't - * have a meaning, if we do not know either the start or the end, we restrict ourself to measure a duration in hours, - * minutes and seconds - *

- * - * @author Martin Smock <smock.martin@gmail.com> - * @author Michael Gatto <michael@gatto.ch> (reimplementation using enum) - */ -@SuppressWarnings("nls") -public class ISO8601Worktime implements WorktimeFormat { - - /** - * The time representations available, as enum, with the associated millis. - * - * @author gattom - */ - public enum TimeDuration { - - SECOND(1000, 'S'), - MINUTE(60 * SECOND.duration(), 'M'), - HOUR(60 * MINUTE.duration(), 'H'); - - final long millis; - final char isoChar; - - TimeDuration(long milli, char isorep) { - this.millis = milli; - this.isoChar = isorep; - } - - public long duration() { - return this.millis; - } - - public static TimeDuration getTimeDurationFor(String isostring, int unitIndex) { - char duration = isostring.charAt(unitIndex); - switch (duration) { - case 'S': - if (isostring.substring(0, unitIndex).contains("T")) - return SECOND; - throw new NumberFormatException( - duration + " is not a valid unit of time in ISO8601 without a preceeding T (e.g.: PT1S)"); - case 'H': - if (isostring.substring(0, unitIndex).contains("T")) - return HOUR; - throw new NumberFormatException( - duration + " is not a valid unit of time in ISO8601 without a preceeding T (e.g.: PT1H)"); - case 'M': - return MINUTE; - default: - throw new NumberFormatException(duration + " is not a valid unit of time in ISO8601"); - } - } - - } - - /** - * check if c is a number char including the decimal decimal dot (.) - * - * @param c - * the character to check - * - * @return boolean return true if the given char is a number or a decimal dot (.), false otherwise - */ - private static boolean isNumber(char c) { - boolean isNumber = Character.isDigit(c) || (c == '.'); - return isNumber; - } - - /** - * Parses the given string to a pseudo ISO 8601 duration - * - * @param s - * the string to be parsed to a duration which must be coded as a ISO8601 value - * - * @return long the time value which represents the duration - */ - @Override - public long parse(String s) { - - long newResult = 0; - - // throw exception, if the string is not of length > 2 - if (s.length() < 3) - throw new NumberFormatException(s + " cannot be parsed to ISA 8601 Duration"); - - char p = s.charAt(0); - - if (p == 'P') { - int newposition = 1; - do { - if (s.charAt(newposition) == 'T') { - // skip the separator specifying where the time starts. - newposition++; - } - // read the string representing the numeric value - String val = parseNumber(newposition, s); - double numVal = Double.parseDouble(val); - newposition += val.length(); - // get the time unit - TimeDuration unit = TimeDuration.getTimeDurationFor(s, newposition); - // skip the time duration character - newposition++; - // increment the value. - newResult += unit.duration() * numVal; - } while (newposition < s.length()); - - return newResult; - } - - throw new NumberFormatException(s + " cannot be parsed to ISO 8601 Duration"); - } - - /** - * Return the substring of s starting at index i (in s) that contains a numeric string. - * - * @param index - * The start index in string s - * @param s - * The string to analyze - * - * @return the substring containing the numeric portion of s starting at index i. - */ - private String parseNumber(int index, String s) { - int i = index; - int start = i; - while (i < s.length()) { - if (!isNumber(s.charAt(i))) - break; - i++; - } - String substring = s.substring(start, i); - return substring; - } - - /** - * Format the given time duration unit into the string buffer. This function displays the given duration in units of - * the given unit, and returns the remainder. - *

- * Thus, a duration of 86401000 (one day and one second) will add the representation of one day if unit is DAY (1D) - * and return 1000 as the remainder with respect of this unit. If the given unit is HOUR, then this function adds - * 24H to the {@link StringBuilder}, and returns 1000 as the remainder. - * - * @param sb - * The {@link StringBuilder} to add the given duration with the right unit - * @param duration - * The duration to add - * @param unit - * The unit of this duration - * - * @return The remainder of the given duration, modulo the time unit. - */ - private long formatTimeDuration(StringBuilder sb, long duration, TimeDuration unit) { - - long remainder = duration; - - if (unit.equals(TimeDuration.SECOND) || remainder >= unit.duration()) { - - long quantity = remainder / unit.duration(); - remainder = remainder % unit.duration(); - sb.append(quantity); - - if (unit.equals(TimeDuration.SECOND)) { - - long millis = remainder; - if (millis == 0) { - // to not have the decimal point - } else if (millis > 99) { - sb.append("." + millis); - } else if (millis > 9) { - sb.append(".0" + millis); - } else { - sb.append(".00" + millis); - } - } - - sb.append(unit.isoChar); - } - return remainder; - } - - /** - * Formats the given time duration to a pseudo ISO 8601 duration string - * - * @param duration - * the duration - * - * @return String the duration formatted as a ISO8601 duration string - */ - @Override - public String format(long duration) { - - if (duration == 0) - return "PT0S"; - - StringBuilder sb = new StringBuilder(); - sb.append('P'); - sb.append('T'); - long remainder = formatTimeDuration(sb, duration, TimeDuration.HOUR); - remainder = formatTimeDuration(sb, remainder, TimeDuration.MINUTE); - remainder = formatTimeDuration(sb, remainder, TimeDuration.SECOND); - - return sb.toString(); - } - -}