blob: 0d3635a322fd5c7f9dbe479bc570ac429ab986f3 [file] [log] [blame]
package org.apache.abdera2.common.date;
/**
* Basic implementation of the ISO 8601 Duration format.
* Currently, the only duration format supported is the
* P[n]Y[n]M[n]DT[n]H[n]M[n]S syntax. The alternative
* PYYYYMMDDThhmmss and P[YYYY]-[MM]-[DD]T[hh]:[mm]:[ss]
* forms are NOT supported.
*/
public class Duration {
private final double y, m, w, d, h, i, s;
public Duration(double s) {
this(0,0,0,0,0,0,s);
}
public Duration(double i, double s) {
this(0,0,0,0,0,i,s);
}
public Duration(double h, double i, double s) {
this(0,0,0,0,h,i,s);
}
public Duration(double d, double h, double i, double s) {
this(0,0,0,d,h,i,s);
}
public Duration(double w, double d, double h, double i, double s) {
this(0,0,w,d,h,i,s);
}
public Duration(double m, double w, double d, double h, double i, double s) {
this(0,m,w,d,h,i,s);
}
public Duration(double y, double m, double w, double d, double h, double i, double s) {
this.y = Math.max(0, y);
this.m = Math.max(0, m);
this.w = Math.max(0, w);
this.d = Math.max(0, d);
this.h = Math.max(0, h);
this.i = Math.max(0, i);
this.s = Math.max(0, s);
if (is_frac(y)&&!is_smallest(m,w,d,h,i,s))
throw new IllegalArgumentException();
if (is_frac(m)&&!is_smallest(w,d,h,i,s))
throw new IllegalArgumentException();
if (is_frac(w)&&!is_smallest(d,h,i,s))
throw new IllegalArgumentException();
if (is_frac(d)&&!is_smallest(h,i,s))
throw new IllegalArgumentException();
if (is_frac(h)&&!is_smallest(i,s))
throw new IllegalArgumentException();
if (is_frac(i)&&!is_smallest(s))
throw new IllegalArgumentException();
}
public double years() {
return y;
}
public double months() {
return m;
}
public double weeks() {
return w;
}
public double days() {
return d;
}
public double hours() {
return h;
}
public double minutes() {
return i;
}
public double seconds() {
return s;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(d);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(h);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(i);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(m);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(s);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(w);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(y);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Duration other = (Duration) obj;
if (Double.doubleToLongBits(d) != Double.doubleToLongBits(other.d))
return false;
if (Double.doubleToLongBits(h) != Double.doubleToLongBits(other.h))
return false;
if (Double.doubleToLongBits(i) != Double.doubleToLongBits(other.i))
return false;
if (Double.doubleToLongBits(m) != Double.doubleToLongBits(other.m))
return false;
if (Double.doubleToLongBits(s) != Double.doubleToLongBits(other.s))
return false;
if (Double.doubleToLongBits(w) != Double.doubleToLongBits(other.w))
return false;
if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
return false;
return true;
}
public String toString() {
StringBuilder buf = new StringBuilder("P");
if (y > 0)
buf.append(is_smallest(m,w,d,h,i,s)&&is_frac(y)?Double.toString(y):Integer.toString((int)y))
.append('Y');
if (m > 0)
buf.append(is_smallest(w,d,h,i,s)&&is_frac(m)?Double.toString(m):Integer.toString((int)m))
.append('M');
if (w > 0)
buf.append(is_smallest(d,h,i,s)&&is_frac(w)?Double.toString(w):Integer.toString((int)w))
.append('W');
if (d > 0)
buf.append(is_smallest(h,i,s)&&is_frac(d)?Double.toString(d):Integer.toString((int)d))
.append('D');
if (h > 0 || i > 0 || s > 0)
buf.append('T');
if (h > 0)
buf.append(is_smallest(i,s)&&is_frac(h)?Double.toString(h):Integer.toString((int)h))
.append('H');
if (i > 0)
buf.append(is_smallest(s)&&is_frac(i)?Double.toString(i):Integer.toString((int)i))
.append('M');
if (s > 0)
buf.append(is_frac(s)?Double.toString(s):Integer.toString((int)s))
.append('S');
return buf.toString();
}
private boolean is_frac(double d) {
return d%1!=0;
}
private boolean is_smallest(double... ds) {
for (double i : ds)
if (i > 0) return false;
return true;
}
public static Duration parse(String val) {
double y = 0, m = 0, w = 0, d = 0, h = 0, i = 0, s = 0;
if (val == null) return null;
int p = 0, l = val.length();
if (val.charAt(p) != 'P' && val.charAt(p) != 'p')
throw new IllegalArgumentException();
int r = ++p;
boolean t = false;
while(p < l) {
while(digit(val.charAt(r)) && r < l) r++;
String v = val.substring(p,r);
double dv = Double.parseDouble(v);
switch(val.charAt(r)) {
case 'Y': case 'y': y = dv; break;
case 'M': case 'm': if (!t) m = dv; else i = dv; break;
case 'W': case 'w': w = dv; break;
case 'H': case 'h': h = dv; break;
case 'D': case 'd': d = dv; break;
case 'S': case 's': s = dv; break;
case 'T': case 't': t = true; break;
default: throw new IllegalArgumentException();
}
p = r+1;
r = p;
}
return new Duration(y,m,w,d,h,i,s);
}
private static boolean digit(char c) {
return (c >= '0' && c <= '9') || c == '.' || c==',';
}
}