17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert****************************************************************************** 37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* Copyright (C) 2007-2010, International Business Machines Corporation and * 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* others. All Rights Reserved. * 57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert****************************************************************************** 67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*/ 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.impl.duration; 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.duration.BasicPeriodFormatterFactory.Customizations; 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.duration.impl.DataRecord.ECountVariant; 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.duration.impl.DataRecord.EMilliSupport; 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.duration.impl.DataRecord.ESeparatorVariant; 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.duration.impl.DataRecord.ETimeDirection; 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.duration.impl.DataRecord.ETimeLimit; 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.duration.impl.PeriodFormatterData; 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Core implementation class for PeriodFormatter. 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertclass BasicPeriodFormatter implements PeriodFormatter { 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private BasicPeriodFormatterFactory factory; 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String localeName; 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private PeriodFormatterData data; 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private Customizations customs; 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert BasicPeriodFormatter(BasicPeriodFormatterFactory factory, 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String localeName, 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PeriodFormatterData data, 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Customizations customs) { 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.factory = factory; 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.localeName = localeName; 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.data = data; 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.customs = customs; 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String format(Period period) { 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!period.isSet()) { 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("period is not set"); 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return format(period.timeLimit, period.inFuture, period.counts); 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public PeriodFormatter withLocale(String locName) { 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!this.localeName.equals(locName)) { 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PeriodFormatterData newData = factory.getData(locName); 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new BasicPeriodFormatter(factory, locName, newData, 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert customs); 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String format(int tl, boolean inFuture, int[] counts) { 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int mask = 0; 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < counts.length; ++i) { 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (counts[i] > 0) { 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mask |= 1 << i; 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if the data does not allow formatting of zero periods, 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // remove these from consideration. If the result has no 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // periods set, return null to indicate we could not format 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // the duration. 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!data.allowZero()) { 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0, m = 1; i < counts.length; ++i, m <<= 1) { 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((mask & m) != 0 && counts[i] == 1) { 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mask &= ~m; 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (mask == 0) { 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if the data does not allow milliseconds but milliseconds are 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // set, merge them with seconds and force display of seconds to 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // decimal with 3 places. 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean forceD3Seconds = false; 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (data.useMilliseconds() != EMilliSupport.YES && 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert (mask & (1 << TimeUnit.MILLISECOND.ordinal)) != 0) { 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int sx = TimeUnit.SECOND.ordinal; 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int mx = TimeUnit.MILLISECOND.ordinal; 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int sf = 1 << sx; 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int mf = 1 << mx; 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (data.useMilliseconds()) { 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case EMilliSupport.WITH_SECONDS: { 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if there are seconds, merge with seconds, otherwise leave alone 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((mask & sf) != 0) { 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert counts[sx] += (counts[mx]-1)/1000; 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mask &= ~mf; 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert forceD3Seconds = true; 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } break; 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case EMilliSupport.NO: { 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // merge with seconds, reset seconds before use just in case 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((mask & sf) == 0) { 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mask |= sf; 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert counts[sx] = 1; 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert counts[sx] += (counts[mx]-1)/1000; 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mask &= ~mf; 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert forceD3Seconds = true; 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } break; 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // get the first and last units that are set. 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int first = 0; 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int last = counts.length - 1; 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (first < counts.length && (mask & (1 << first)) == 0) ++first; 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (last > first && (mask & (1 << last)) == 0) --last; 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // determine if there is any non-zero unit 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean isZero = true; 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = first; i <= last; ++i) { 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (((mask & (1 << i)) != 0) && counts[i] > 1) { 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert isZero = false; 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer sb = new StringBuffer(); 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if we've been requested to not display a limit, or there are 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // no non-zero units, do not display the limit. 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!customs.displayLimit || isZero) { 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tl = ETimeLimit.NOLIMIT; 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if we've been requested to not display the direction, or there 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // are no non-zero units, do not display the direction. 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int td; 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!customs.displayDirection || isZero) { 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert td = ETimeDirection.NODIRECTION; 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert td = inFuture ? ETimeDirection.FUTURE : ETimeDirection.PAST; 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // format the initial portion of the string before the units. 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // record whether we need to use a digit prefix (because the 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // initial portion forces it) 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean useDigitPrefix = data.appendPrefix(tl, td, sb); 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // determine some formatting params and initial values 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean multiple = first != last; 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean wasSkipped = true; // no initial skip marker 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean skipped = false; 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean countSep = customs.separatorVariant != ESeparatorVariant.NONE; 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // loop for formatting the units 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = first, j = i; i <= last; i = j) { 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (skipped) { 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // we didn't format the previous unit 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert data.appendSkippedUnit(sb); 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert skipped = false; 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert wasSkipped = true; 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (++j < last && (mask & (1 << j)) == 0) { 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert skipped = true; // skip 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeUnit unit = TimeUnit.units[i]; 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int count = counts[i] - 1; 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int cv = customs.countVariant; 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (i == last) { 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (forceD3Seconds) { 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cv = ECountVariant.DECIMAL3; 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // else leave unchanged 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cv = ECountVariant.INTEGER; 1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean isLast = i == last; 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean mustSkip = data.appendUnit(unit, count, cv, customs.unitVariant, 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert countSep, useDigitPrefix, multiple, isLast, wasSkipped, sb); 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert skipped |= mustSkip; 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert wasSkipped = false; 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (customs.separatorVariant != ESeparatorVariant.NONE && j <= last) { 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean afterFirst = i == first; 1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean beforeLast = j == last; 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean fullSep = customs.separatorVariant == ESeparatorVariant.FULL; 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert useDigitPrefix = data.appendUnitSeparator(unit, fullSep, afterFirst, beforeLast, sb); 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert useDigitPrefix = false; 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert data.appendSuffix(tl, td, sb); 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return sb.toString(); 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 196