1 package net.sf.saxon.value; 2 import net.sf.saxon.expr.XPathContext; 3 import net.sf.saxon.om.FastStringBuffer; 4 import net.sf.saxon.trans.DynamicError; 5 import net.sf.saxon.trans.XPathException; 6 import net.sf.saxon.type.ItemType; 7 import net.sf.saxon.type.Type; 8 9 import java.util.StringTokenizer ; 10 11 14 15 public final class MonthDurationValue extends DurationValue implements Comparable { 16 17 20 21 private MonthDurationValue() { 22 } 23 24 28 29 public MonthDurationValue(CharSequence s) throws XPathException { 30 31 StringTokenizer tok = new StringTokenizer (trimWhitespace(s).toString(), "-+PYM", true); 32 try { 33 if (!tok.hasMoreElements()) badDuration("empty string", s); 34 String part = (String )tok.nextElement(); 35 if ("+".equals(part)) { 36 part = (String )tok.nextElement(); 37 } else if ("-".equals(part)) { 38 negative = true; 39 part = (String )tok.nextElement(); 40 } 41 if (!"P".equals(part)) badDuration("missing 'P'", s); 42 int state = 0; 43 while (tok.hasMoreElements()) { 44 part = (String )tok.nextElement(); 45 if ("T".equals(part)) { 46 state = 4; 47 part = (String )tok.nextElement(); 48 } 49 int value = Integer.parseInt(part); 50 if (!tok.hasMoreElements()) badDuration("missing unit letter at end", s); 51 char delim = ((String )tok.nextElement()).charAt(0); 52 switch (delim) { 53 case 'Y': 54 if (state > 0) badDuration("Y is out of sequence", s); 55 years = value; 56 state = 1; 57 break; 58 case 'M': 59 if (state == 4 || state==5) { 60 minutes = value; 61 state = 6; 62 break; 63 } else if (state == 0 || state==1) { 64 months = value; 65 state = 2; 66 break; 67 } else { 68 badDuration("M is out of sequence", s); 69 } 70 71 default: 72 badDuration("misplaced " + delim, s); 73 } 74 } 75 normalize(); 76 77 } catch (NumberFormatException err) { 78 badDuration("non-numeric component", s); 79 } 80 } 81 82 86 87 public CharSequence getStringValueCS() { 88 89 91 int mm = years*12 + months; 92 int y = mm / 12; 93 int m = mm % 12; 94 95 FastStringBuffer sb = new FastStringBuffer(32); 96 if (negative) { 97 sb.append('-'); 98 } 99 sb.append('P'); 100 if (y!=0) { 101 sb.append(y + "Y"); 102 } 103 if (m!=0 || y==0) { 104 sb.append(m + "M"); 105 } 106 return sb; 107 108 } 109 110 113 114 public void normalize() { 115 if (months >= 12) { 116 years += (months / 12); 117 months = months % 12; 118 } 119 } 120 121 124 125 public int getLengthInMonths() { 126 return (years*12 + months) * (negative ? -1 : +1); 127 } 128 129 132 133 public static MonthDurationValue fromMonths(int months) { 134 MonthDurationValue mdv = new MonthDurationValue(); 135 mdv.negative = (months<0); 136 mdv.months = (months<0 ? -months : months); 137 mdv.normalize(); 138 return mdv; 139 } 140 141 144 145 public DurationValue multiply(double n, XPathContext context) throws XPathException { 146 double m = (double)getLengthInMonths(); 147 double product = n*m; 148 if (Double.isInfinite(product) || product > Integer.MAX_VALUE || product < Integer.MIN_VALUE) { 149 DynamicError err = new DynamicError("Overflow when multiplying/dividing a duration by a number"); 150 err.setErrorCode("FODT0002"); 151 err.setXPathContext(context); 152 throw err; 153 } 154 return fromMonths((int)product); 155 } 156 157 163 164 public DoubleValue divide(DurationValue other, XPathContext context) throws XPathException { 165 if (other instanceof MonthDurationValue) { 166 return new DoubleValue( 167 (double)this.getLengthInMonths() / (double)((MonthDurationValue)other).getLengthInMonths()); 168 } else { 169 throw new DynamicError("Cannot divide two durations of different type"); 170 } 171 } 172 173 176 177 public DurationValue add(DurationValue other, XPathContext context) throws XPathException { 178 if (other instanceof MonthDurationValue) { 179 return fromMonths(this.getLengthInMonths() + 180 ((MonthDurationValue)other).getLengthInMonths()); 181 } else { 182 throw new DynamicError("Cannot add two durations of different type"); 183 } 184 } 185 186 189 190 public DurationValue subtract(DurationValue other, XPathContext context) throws XPathException { 191 if (other instanceof MonthDurationValue) { 192 return fromMonths(this.getLengthInMonths() - 193 ((MonthDurationValue)other).getLengthInMonths()); 194 } else { 195 throw new DynamicError("Cannot subtract two durations of different type"); 196 } 197 } 198 199 203 204 public ItemType getItemType() { 205 return Type.YEAR_MONTH_DURATION_TYPE; 206 } 207 208 211 212 public Object convertToJava(Class target, XPathContext context) throws XPathException { 213 if (target.isAssignableFrom(DurationValue.class)) { 214 return this; 215 } else if (target==String .class || target==CharSequence .class) { 216 return getStringValue(); 217 } else if (target==Object .class) { 218 return getStringValue(); 219 } else { 220 throw new DynamicError("Conversion of yearMonthDuration to " + target.getName() + 221 " is not supported"); 222 } 223 } 224 225 226 236 237 public int compareTo(Object other) { 238 if (other instanceof MonthDurationValue) { 239 return this.getLengthInMonths() - ((MonthDurationValue)other).getLengthInMonths(); 240 } else { 241 throw new ClassCastException ("Cannot compare a yearMonthDuration to an object of class " 242 + other.getClass()); 243 } 244 } 245 246 247 } 248 249 267 | Popular Tags |