diff --git a/src/main/java/ch/eitchnet/utils/iso8601/DateFormat.java b/src/main/java/ch/eitchnet/utils/iso8601/DateFormat.java new file mode 100644 index 000000000..d7d918dea --- /dev/null +++ b/src/main/java/ch/eitchnet/utils/iso8601/DateFormat.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2006 - 2011 Apixxo AG Hauptgasse 25 4600 + * Olten + * + * All rights reserved. + * + */ + +package ch.eitchnet.utils.iso8601; + +/** + * interface for all date formats internally used by rsp applications + * + * @author msmock + */ +public interface DateFormat { + + /** + * format a long to string + * + * @param l + * @return the formatted string of the long value + */ + public String format(long l); + + /** + * parse a string to long + * + * @param s + * @return the value parsed + */ + public long parse(String s); + +} diff --git a/src/main/java/ch/eitchnet/utils/iso8601/DurationFormat.java b/src/main/java/ch/eitchnet/utils/iso8601/DurationFormat.java new file mode 100644 index 000000000..d7d7c6f00 --- /dev/null +++ b/src/main/java/ch/eitchnet/utils/iso8601/DurationFormat.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2006 - 2011 Apixxo AG Hauptgasse 25 4600 + * Olten + * + * All rights reserved. + * + */ + +package ch.eitchnet.utils.iso8601; + +/** + * interface for all duration formats internally used by the platform + * + * @author msmock + */ +public interface DurationFormat { + + /** + * format a long to string + * + * @param l + * @return formatted string if the long argument + */ + public String format(long l); + + /** + * parse a string to long + * + * @param s + * @return the long value parsed + */ + public long parse(String s); + +} diff --git a/src/main/java/ch/eitchnet/utils/iso8601/FormatFactory.java b/src/main/java/ch/eitchnet/utils/iso8601/FormatFactory.java new file mode 100644 index 000000000..99d43ee76 --- /dev/null +++ b/src/main/java/ch/eitchnet/utils/iso8601/FormatFactory.java @@ -0,0 +1,85 @@ +package ch.eitchnet.utils.iso8601; + +/** + * This interface defines methods for formatting values for UI representation and also defines factory methods for + * formatters for parsing and formatting duration and date values + * + * @author msmock + */ +public interface FormatFactory { + + /** + * return the formatter for dates + * + * @return RSPDurationFormat + */ + public DateFormat getDateFormat(); + + /** + * return the formatter for durations + * + * @return RSPDurationFormat + */ + public DurationFormat getDurationFormat(); + + /** + * return the formatter for work time + * + * @return RSPWorktimeFormat + */ + public WorktimeFormat getWorktimeFormat(); + + /** + * the date format used in xml import and export + * + * @return RSPDateFormat + */ + public DateFormat getXmlDateFormat(); + + /** + * the duration format used in xml import and export + * + * @return RSPDurationFormat + */ + public DurationFormat getXmlDurationFormat(); + + /** + * Formats a date using {@link #getDateFormat()} + * + * @param date + * the date to format to string + * + * @return String representation of the date + */ + 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 + * + * @param value + * the value to format + * + * @return the floating point formatted as a string + */ + public String formatFloat(double value); +} \ No newline at end of file diff --git a/src/main/java/ch/eitchnet/utils/iso8601/ISO8601.java b/src/main/java/ch/eitchnet/utils/iso8601/ISO8601.java new file mode 100644 index 000000000..496b49e96 --- /dev/null +++ b/src/main/java/ch/eitchnet/utils/iso8601/ISO8601.java @@ -0,0 +1,264 @@ +package ch.eitchnet.utils.iso8601; + +import java.text.DecimalFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import org.apache.log4j.Logger; + +/** + * + */ +@SuppressWarnings("nls") +public class ISO8601 implements DateFormat { + + private static final Logger logger = Logger.getLogger(ISO8601.class); + + /** + * misc. numeric formats used in formatting + */ + private DecimalFormat xxFormat = new DecimalFormat("00"); + private DecimalFormat xxxFormat = new DecimalFormat("000"); + private DecimalFormat xxxxFormat = new DecimalFormat("0000"); + + /** + * + */ + private Calendar parseToCalendar(String text) { + + if (text == null) { + throw new IllegalArgumentException("argument can not be null"); + } + + // check optional leading sign + char sign; + int start; + if (text.startsWith("-")) { + sign = '-'; + start = 1; + } else if (text.startsWith("+")) { + sign = '+'; + start = 1; + } else { + sign = '+'; // no sign specified, implied '+' + start = 0; + } + + /** + * format of the string is: YYYY-MM-DDThh:mm:ss.SSSTZD + */ + int year, month, day, hour, min, sec, millisec; + String timeZone; + try { + + // year (YYYY) + year = Integer.parseInt(text.substring(start, start + 4)); + start += 4; + // delimiter '-' + if (text.charAt(start) != '-') { + return null; + } + start++; + + // month (MM) + month = Integer.parseInt(text.substring(start, start + 2)); + start += 2; + // delimiter '-' + if (text.charAt(start) != '-') { + return null; + } + start++; + + // day (DD) + day = Integer.parseInt(text.substring(start, start + 2)); + start += 2; + // delimiter 'T' + if (text.charAt(start) != 'T') { + return null; + } + start++; + + // hour (hh) + hour = Integer.parseInt(text.substring(start, start + 2)); + start += 2; + // delimiter ':' + if (text.charAt(start) != ':') { + return null; + } + start++; + + // minute (mm) + min = Integer.parseInt(text.substring(start, start + 2)); + start += 2; + // delimiter ':' + if (text.charAt(start) != ':') { + return null; + } + start++; + + // second (ss) + sec = Integer.parseInt(text.substring(start, start + 2)); + start += 2; + + // delimiter '.' + if (text.charAt(start) == '.') { + start++; + // millisecond (SSS) + millisec = Integer.parseInt(text.substring(start, start + 3)); + start += 3; + } else { + millisec = 0; + } + + if (text.charAt(start) == '+' || text.charAt(start) == '-') { + timeZone = "GMT" + text.substring(start); + } else if (text.substring(start).equals("Z")) { + timeZone = "GMT"; + } else { + return null; + } + + } catch (IndexOutOfBoundsException e) { + return null; + } catch (NumberFormatException e) { + return null; + } + + TimeZone tz = TimeZone.getTimeZone(timeZone); + if (!tz.getID().equals(timeZone)) { + // invalid time zone + return null; + } + + // create Calendar + Calendar cal = Calendar.getInstance(tz); + cal.setLenient(false); + + if (sign == '-' || year == 0) { + // + cal.set(Calendar.YEAR, year + 1); + cal.set(Calendar.ERA, GregorianCalendar.BC); + } else { + cal.set(Calendar.YEAR, year); + cal.set(Calendar.ERA, GregorianCalendar.AD); + } + + // + cal.set(Calendar.MONTH, month - 1); + cal.set(Calendar.DAY_OF_MONTH, day); + cal.set(Calendar.HOUR_OF_DAY, hour); + cal.set(Calendar.MINUTE, min); + cal.set(Calendar.SECOND, sec); + cal.set(Calendar.MILLISECOND, millisec); + + try { + cal.getTime(); + } catch (IllegalArgumentException e) { + return null; + } + + return cal; + } + + /** + * + */ + private String format(Calendar cal) { + + if (cal == null) { + throw new IllegalArgumentException("argument can not be null"); + } + + // determine era and adjust year if necessary + int year = cal.get(Calendar.YEAR); + if (cal.isSet(Calendar.ERA) && cal.get(Calendar.ERA) == GregorianCalendar.BC) { + /** + * calculate year using astronomical system: year n BCE => astronomical year -n + 1 + */ + year = 0 - year + 1; + } + + /** + * format of date/time string is: YYYY-MM-DDThh:mm:ss.SSSTZD + */ + StringBuilder sWriter = new StringBuilder(); + sWriter.append(this.xxxxFormat.format(year)); + sWriter.append('-'); + sWriter.append(this.xxFormat.format(cal.get(Calendar.MONTH) + 1)); + sWriter.append('-'); + sWriter.append(this.xxFormat.format(cal.get(Calendar.DAY_OF_MONTH))); + sWriter.append('T'); + sWriter.append(this.xxFormat.format(cal.get(Calendar.HOUR_OF_DAY))); + sWriter.append(':'); + sWriter.append(this.xxFormat.format(cal.get(Calendar.MINUTE))); + sWriter.append(':'); + sWriter.append(this.xxFormat.format(cal.get(Calendar.SECOND))); + sWriter.append('.'); + sWriter.append(this.xxxFormat.format(cal.get(Calendar.MILLISECOND))); + TimeZone tz = cal.getTimeZone(); + + int offset = tz.getOffset(cal.getTimeInMillis()); + if (offset != 0) { + int hours = Math.abs((offset / (60 * 1000)) / 60); + int minutes = Math.abs((offset / (60 * 1000)) % 60); + sWriter.append(offset < 0 ? '-' : '+'); + sWriter.append(this.xxFormat.format(hours)); + sWriter.append(':'); + sWriter.append(this.xxFormat.format(minutes)); + } else { + sWriter.append('Z'); + } + return sWriter.toString(); + } + + /** + * added by msmock convert a long to ISO8601 + * + * @param timePoint + * @return time point as ISO8601 String + */ + @Override + public String format(long timePoint) { + + if (timePoint == Long.MAX_VALUE || timePoint == Long.MIN_VALUE) { + return "-"; + } + + // else + try { + Date date = new Date(); + date.setTime(timePoint); + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return format(cal); + } catch (Exception e) { + logger.error(e, e); + return null; + } + } + + /** + * parse ISO8601 date to long + * + * @param s + * the string to parse + * @return time point as long + * @throws NumberFormatException + */ + @Override + public long parse(String s) { + + if (s.equals("-")) + return Long.MAX_VALUE; + + Calendar cal = parseToCalendar(s); + if (cal != null) { + return cal.getTime().getTime(); + } + + String msg = "Input string " + s + " cannot be parsed to date."; + throw new NumberFormatException(msg); + } +} diff --git a/src/main/java/ch/eitchnet/utils/iso8601/ISO8601Duration.java b/src/main/java/ch/eitchnet/utils/iso8601/ISO8601Duration.java new file mode 100644 index 000000000..810b7b34d --- /dev/null +++ b/src/main/java/ch/eitchnet/utils/iso8601/ISO8601Duration.java @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2006 - 2011 Apixxo AG Hauptgasse 25 4600 + * Olten + * + * All rights reserved. + * + */ +package ch.eitchnet.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 + *

+ * + *

+ * 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: 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 msmock + * @author gattom (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; + } else + 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; + } else + 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; + } else { + 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.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 + * @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 "PT0S"; + + 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/src/main/java/ch/eitchnet/utils/iso8601/ISO8601FormatFactory.java b/src/main/java/ch/eitchnet/utils/iso8601/ISO8601FormatFactory.java new file mode 100644 index 000000000..1c1fed122 --- /dev/null +++ b/src/main/java/ch/eitchnet/utils/iso8601/ISO8601FormatFactory.java @@ -0,0 +1,72 @@ +package ch.eitchnet.utils.iso8601; + +import ch.eitchnet.utils.helper.MathHelper; + +/** + * Default factory for date formats used for serialization. + * + * @author msmock + */ +public class ISO8601FormatFactory implements FormatFactory { + + private static ISO8601FormatFactory instance = new ISO8601FormatFactory(); + + /** + * the singleton constructor + */ + private ISO8601FormatFactory() { + // singleton + } + + /** + * @return the instance + */ + public static ISO8601FormatFactory getInstance() { + return instance; + } + + @Override + public ISO8601 getDateFormat() { + 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(long date) { + 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)); + } +} diff --git a/src/main/java/ch/eitchnet/utils/iso8601/ISO8601Worktime.java b/src/main/java/ch/eitchnet/utils/iso8601/ISO8601Worktime.java new file mode 100644 index 000000000..ffd0c6c08 --- /dev/null +++ b/src/main/java/ch/eitchnet/utils/iso8601/ISO8601Worktime.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2006 - 2011 Apixxo AG Hauptgasse 25 4600 + * Olten + * + * All rights reserved. + * + */ +package ch.eitchnet.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 + *

+ * + *

+ * 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: 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 msmock + * @author gattom (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; + } else + 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; + } else + 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; + + } else { + 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 + * @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(); + } + +} diff --git a/src/main/java/ch/eitchnet/utils/iso8601/WorktimeFormat.java b/src/main/java/ch/eitchnet/utils/iso8601/WorktimeFormat.java new file mode 100644 index 000000000..058a5f7c3 --- /dev/null +++ b/src/main/java/ch/eitchnet/utils/iso8601/WorktimeFormat.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2006 - 2011 Apixxo AG Hauptgasse 25 4600 + * Olten + * + * All rights reserved. + * + */ + +package ch.eitchnet.utils.iso8601; + +/** + * interface for the worktime format + * + * @author msmock + */ +public interface WorktimeFormat { + + /** + * format a long to string + * + * @param l + * @return formatted string if the long argument + */ + public String format(long l); + + /** + * parse a string to long + * + * @param s + * @return the long value parsed + */ + public long parse(String s); + +}