org.pojava.datetime.Shift Maven / Gradle / Ivy
package org.pojava.datetime;
/**
* Shift describes an offset in time in terms of CalendarUnit increments of various proportions.
* Compare this to the "Duration" class, which describes fixed units of time in a self-contained
* manner. A Shift, by contrast, may use a 23, 24 or 25 hour day depending on Daylight Saving
* Time, or a 28, 29, 30, or 31 day month. The amount of time described by a Shift is dependent
* on a start time and a time zone, both external to the Shift object itself.
*
* @author John Pile
*
*/
public class Shift {
/**
* Nanoseconds per second
*/
private static final long NPS = 1000000000;
/**
* Seconds per Minute
*/
private static final long SPM = 60;
/**
* Minutes per Hour
*/
private static final long MPH = 60;
private int year = 0;
private int month = 0;
private int week = 0;
private int day = 0;
private int hour = 0;
private int minute = 0;
private int second = 0;
private long nanosec = 0;
public Shift() {
// default constructor
}
/**
* Constructor parsing from a string.
*
* @param iso8601
* String representation of a duration.
*/
public Shift(String iso8601) {
char[] chars = iso8601.toCharArray();
double accum = 0.0;
double dec = 1.0;
int sign = 1;
int time = 0;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (c == '.') {
dec /= 10;
} else if (c == '-') {
sign = -1;
} else if (c >= '0' && c <= '9') {
if (dec == 1.0) {
accum = accum * 10 + sign * dec * (c - '0');
} else {
accum += sign * dec * (c - '0');
dec /= 10;
}
} else if (c == 'T') {
time = 1;
} else if (c == 'Y') {
if (accum != 0) {
shiftYears(accum);
accum=0;
dec = 1;
sign = 1;
}
} else if (c == 'W') {
if (accum != 0) {
shiftWeeks(accum);
accum=0;
dec = 1;
sign = 1;
}
} else if (c == 'D') {
if (accum != 0) {
shiftDays(accum);
accum = 0;
dec = 1;
sign = 1;
}
} else if (c == 'H') {
if (accum != 0) {
shiftHours(accum);
accum = 0;
dec = 1;
sign = 1;
}
} else if (c == 'M') {
if (accum != 0) {
if (time==0) {
shiftMonths(accum);
} else {
shiftMinutes(accum);
}
accum = 0;
dec = 1;
sign = 1;
}
} else if (c == 'S') {
if (accum != 0) {
shiftSeconds(accum);
accum = 0;
dec = 1;
sign = 1;
}
}
}
}
public void shiftYears(double accum) {
if (accum >= 1.0 || accum <= -1.0) {
year += (long) accum;
accum -= (long) accum;
}
if (accum != 0) {
shiftMonths(accum * 12);
}
}
public void shiftMonths(double accum) {
if (accum >= 1.0 || accum <= -1.0) {
month += (long) accum;
accum -= (long) accum;
}
if (accum != 0) {
shiftDays(accum * 30);
}
}
public void shiftWeeks(double accum) {
if (accum >= 1.0 || accum <= -1.0) {
week += (long) accum;
accum -= (long) accum;
}
if (accum != 0) {
shiftHours(accum * 7);
}
}
public void shiftDays(double accum) {
if (accum >= 1.0 || accum <= -1.0) {
day += (long) accum;
accum -= (long) accum;
}
if (accum != 0) {
shiftHours(accum * 24);
}
}
public void shiftHours(double accum) {
if (accum >= 1.0 || accum <= -1.0) {
hour += (long) accum;
accum -= (long) accum;
}
if (accum != 0) {
shiftMinutes(accum * MPH);
}
}
public void shiftMinutes(double accum) {
if (accum >= 1.0 || accum <= -1.0) {
minute += (long) accum;
accum -= (long) accum;
}
if (accum != 0) {
shiftSeconds(accum * SPM);
}
}
public void shiftSeconds(double accum) {
if (accum >= 1.0 || accum <= -1.0) {
second += (long) accum;
accum -= (long) accum;
}
if (accum != 0) {
accum += (accum < 0 ? -0.0000000005 : 0.0000000005);
nanosec += (long)(accum * 1000000000);
}
}
private void settleContents() {
if (nanosec >= NPS || nanosec <= -NPS) {
long calcsec = nanosec / NPS;
second += calcsec;
nanosec -= calcsec * NPS;
}
if (second >= SPM || second <= -SPM) {
long calcmin = second / SPM;
minute += calcmin;
second -= calcmin * SPM;
}
if (minute >= MPH || minute <= -MPH) {
long calchour = minute / MPH;
hour += calchour;
minute -= calchour * MPH;
}
}
public String toString() {
// See ISO 8601
settleContents();
StringBuilder sb = new StringBuilder();
sb.append('P');
if (year != 0) {
sb.append(year);
sb.append('Y');
}
if (month != 0) {
sb.append(month);
sb.append('M');
}
if (week != 0) {
sb.append(week);
sb.append('W');
}
if (day != 0) {
sb.append(day);
sb.append('D');
}
if (hour != 0 || minute != 0 || second != 0 || nanosec != 0) {
sb.append('T');
if (hour != 0) {
sb.append(hour);
sb.append('H');
}
if (minute != 0) {
sb.append(minute);
sb.append('M');
}
if (second != 0 || nanosec != 0) {
if (nanosec == 0) {
sb.append(second);
} else {
sb.append((double)(second+nanosec/1000000000.0));
}
sb.append('S');
}
}
return sb.toString();
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getWeek() {
return week;
}
public void setWeek(int week) {
this.week = week;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public int getHour() {
return hour;
}
public void setHour(int hour) {
this.hour = hour;
}
public int getMinute() {
return minute;
}
public void setMinute(int minute) {
this.minute = minute;
settleContents();
}
public int getSecond() {
return second;
}
public void setSecond(int second) {
this.second = second;
settleContents();
}
public int getNanosec() {
return (int) nanosec;
}
public void setNanosec(int nanosec) {
this.nanosec = nanosec;
settleContents();
}
public void setNanosec(long nanosec) {
this.nanosec = nanosec;
settleContents();
}
}