blob: 0ae61c507295f8e7922ddee03c927d6d9044f772 [file] [log] [blame]
/*******************************************************************************
* Crown Copyright (c) 2006, 2007, Copyright (c) 2006, 2007 Jiva Medical.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Jiva Medical - initial API and implementation
*******************************************************************************/
package org.eclipse.uomo.util.impl;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.apache.commons.lang.StringUtils;
import org.eclipse.osgi.util.NLS;
import org.eclipse.uomo.core.UOMoException;
import org.eclipse.uomo.util.internal.Messages;
/**
* ISO 8601 Dates
*
* HL7 uses a date format which is conforms to the constrained ISO 8601 that is
* defined in ISO 8824 (ASN.1) under clause 32 (generalized time).
*
* Because of the ubiquity of HL7 interfaces, and the general utility of this
* time format representation, it's encountered fairly often in healthcare
*
* This Date class represents the notion of a date time that may have years,
* months, days, hours, minutes, seconds, milliseconds and timezones specified.
*
* There is three ways to interact with this date - read and write the component
* fields directly - read and write the string form using parse() and render() -
* get and set the time as a java Date object using getAsDate and setAsDate
*
* It's possible to set the component fields to non-sensical values. Use
* validate() to check whether the values are okay.
*
* Note about parsing:
*
* There is several entry points to the parser. The simplest takes only the
* actual string to parse. If the string is a proper value according to the
* specifications referenced above, it will be read in.
*
* In addition, there is another entry point that allows the caller to specify a
* mask that describes what parts of the date are required, and what is allowed,
* Consult the ISO_DATE_VALIDATION_FULL constant for an example of how to use
* the mask. In addition, the caller can specify what to do with the timezone
*
* Finally, there is a static routine that takes the same parameters and returns
* a date or throws an exception
*
*/
public class Iso8601Date {
// public constants FIXME change to enum values
/**
* timezone information will be ignored
*/
public static final int IGNORE = 0;
/**
* timezone is required
*/
public static final int REQUIRED = 1;
/**
* timezone is optional
*/
public static final int OPTIONAL = 2;
/**
* timezone is prohibited
*/
public static final int PROHIBITED = 3;
/**
* parsing: timezone information will be cleared
*/
public static final int CLEAR = 4;
/**
* timezone information will be set to local value
*/
public static final int SETLOCAL = 5;
/**
* use timezone information if specified
*/
public static final int IF_PRESENT = 6;
/**
* parsing mask for a fully optional date other than the year, which is
* required
*/
public static final String ISO_DATE_VALIDATION_FULL = Messages.Iso8601Date_ISO_DATE_VALIDATION_FULL;
/**
* just the date, with optional month and day
*/
public static final String ISO_DATE_VALIDATION_DATE = Messages.Iso8601Date_ISO_DATE_VALIDATION_DATE;
/**
* default format for writing
*/
public static final String DEF_OUTPUT_FORMAT = Messages.Iso8601Date_DEF_OUTPUT_FORMAT;
// private fields
private int year;
private int month;
private int day;
private int hour;
private int minute;
private int second;
private int milli;
private int tzHour;
private int tzMinute;
private Boolean tzNegative = null; // null means no timezone specified
// administration
public Iso8601Date() {
super();
reset(true);
}
private void reset(boolean timezoneToo) {
year = -1;
month = -1;
day = -1;
hour = -1;
minute = -1;
second = -1;
milli = -1;
if (timezoneToo) {
tzHour = 0;
tzMinute = 0;
tzNegative = null;
}
}
/**
*
* @return a string describing any errors with the component field values
*/
public String validate(boolean checkYearReasonable) {
StringBuffer s = new StringBuffer();
// TODO use Units where possible
boolean content = false;
content = checkField(s, milli, content, 0, 999,
Messages.Iso8601Date_MILIS);
content = checkField(s, second, content, 0, 59,
Messages.Iso8601Date_SECONDS);
content = checkField(s, minute, content, 0, 59,
Messages.Iso8601Date_MINUTES);
content = checkField(s, hour, content, 0, 23,
Messages.Iso8601Date_HOURS);
content = checkField(s, day, content, 1, 31, Messages.Iso8601Date_DAYS);
content = checkField(s, month, content, 1, 12,
Messages.Iso8601Date_MONTHS);
if (checkYearReasonable)
content = checkField(s, year, content, 1000, 2500,
Messages.Iso8601Date_YEARS);
else
content = checkField(s, year, content, Integer.MIN_VALUE,
Integer.MAX_VALUE, "years"); //$NON-NLS-1$
if (!content)
s.append(Messages.Iso8601Date_NO_VALUES_SET);
if (year != -1 && month != -1 && day != -1
&& day > daysForMonth(month, year))
s.append(Messages.Iso8601Date_THE_DAY
+ Integer.toString(day)
+ " is not valid for the month " + Integer.toString(month) + " in the year " + Integer.toString(year) + "\r\n"); //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
if (tzNegative != null) {
content = checkField(s, tzMinute, content, 0, 59,
Messages.Iso8601Date_TZ_MINUTES);
content = checkField(s, tzHour, content, 0, 13,
Messages.Iso8601Date_TZ_HOURS);
}
if (s.length() > 0)
return s.toString();
else
return null;
};
private boolean checkField(StringBuffer s, int value, boolean required,
int min, int max, String desc) {
if (value == -1) {
if (required)
s.append(Messages.Iso8601Date_VALUE_MISSING + desc
+ " is missing and required in this context"); //$NON-NLS-2$
return required;
} else {
if (value < min || value > max)
s.append(Messages.Iso8601Date_VALUE_INVALID
+ desc
+ " is invalid (is " + Integer.toString(value) + " should be " + Integer.toString(min) + " - " + Integer.toString(max) + ")"); //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
return true;
}
}
// component field access
/**
* @return the year. -1 means not set
*/
public int getYear() {
return year;
}
/**
* @param year
* the year to set. -1 means not set
*/
public void setYear(int year) {
this.year = year;
}
/**
* @return the month. -1 means not set
*/
public int getMonth() {
return month;
}
/**
* @param month
* the month to set. -1 means not set
*/
public void setMonth(int month) {
this.month = month;
}
/**
* @return the day. -1 means not set
*/
public int getDay() {
return day;
}
/**
* @param day
* the day to set. -1 means not set
*/
public void setDay(int day) {
this.day = day;
}
/**
* @return the hour. -1 means not set
*/
public int getHour() {
return hour;
}
/**
* @param hour
* the hour to set. -1 means not set
*/
public void setHour(int hour) {
this.hour = hour;
}
/**
* @return the minute. -1 means not set
*/
public int getMinute() {
return minute;
}
/**
* @param minute
* the minute to set. -1 means not set
*/
public void setMinute(int minute) {
this.minute = minute;
}
/**
* @return the second. -1 means not set
*/
public int getSecond() {
return second;
}
/**
* @param second
* the second to set. -1 means not set
*/
public void setSecond(int second) {
this.second = second;
}
/**
* @return the milliseconds. -1 means not set
*/
public int getMilli() {
return milli;
}
/**
* @param milli
* the milliseconds to set. -1 means not set
*/
public void setMilli(int milli) {
this.milli = milli;
}
/**
* @return the timezone Hour. use tzNegative to see whether timezone is set
*/
public int getTzHour() {
return tzHour;
}
/**
* @param tzHour
* the timezone Hour to set. use tzNegative to see whether
* timezone is set
*/
public void setTzHour(int tzHour) {
this.tzHour = tzHour;
}
/**
* @return the timezone Minute. use tzNegative to see whether timezone is
* set
*/
public int getTzMinute() {
return tzMinute;
}
/**
* @param tzMinute
* the timezone Minute to set. use tzNegative to see whether
* timezone is set
*/
public void setTzMinute(int tzMinute) {
this.tzMinute = tzMinute;
}
/**
* @return the tzNegative - true if the timezone is negative, false it it's
* positive, and null if there's no timezone info
*/
public Boolean getTzNegative() {
return tzNegative;
}
/**
* @param tzNegative
* the tzNegative to set - true if the timezone is negative,
* false it it's positive, and null if there's no timezone info
*/
public void setTzNegative(Boolean tzNegative) {
this.tzNegative = tzNegative;
}
// Utilities
public Iso8601Date correctForTZ() {
Iso8601Date result = new Iso8601Date();
result.year = year;
result.month = month;
result.day = day;
result.hour = hour;
result.minute = minute;
result.second = second;
result.milli = milli;
if (tzNegative != null) {
if (tzNegative.booleanValue()) {
result.addMin(-(tzHour * 60 + tzMinute));
} else {
result.addMin((tzHour * 60 + tzMinute));
}
}
return result;
}
// TODO: remove if nolonger used
// private void addSec(int i) {
// if (i != 0) {
// if (second == -1)
// addMin(i / 60);
// else {
// second = second + i;
// int min = 0;
// while (second < 0) {
// second = second + 60;
// min = min - 1;
// }
// while (second >= 60) {
// second = second - 60;
// min = min + 1;
// }
// addMin(min);
// }
// }
// }
private void addMin(int i) {
if (i != 0) {
if (minute == -1)
addHour(i / 60);
else {
minute = minute + i;
int hr = 0;
while (minute < 0) {
minute = minute + 60;
hr = hr - 1;
}
while (minute >= 60) {
minute = minute - 60;
hr = hr + 1;
}
addHour(hr);
}
}
}
private void addHour(int i) {
if (i != 0) {
if (hour == -1)
addDay(i / 24);
else {
hour = hour + i;
int d = 0;
while (hour < 0) {
hour = hour + 24;
d = d - 1;
}
while (hour >= 24) {
hour = hour - 24;
d = d + 1;
}
addDay(d);
}
}
}
private void addDay(int i) {
if (i != 0 && day != -1) {
day = day + i;
while (day < 1 || day > daysForMonth(month, year)) {
if (day < 1) {
day = day + daysForMonth(month, year);
month = month - 1;
if (month == 0) {
month = 12;
year = year - 1;
}
}
if (day > daysForMonth(month, year)) {
month = month + 1;
if (month == 13) {
month = 1;
year = year + 1;
}
day = day - daysForMonth(month, year);
}
}
}
}
// Date access
/**
* get the date specified as a Date.
*
* @param timezone
* - REQUIRED, IF_PRESENT or IGNORE
* @throws OHFException
*/
public Date getAsDate(int timezone) throws UOMoException {
GregorianCalendar cal = new GregorianCalendar();
cal.clear();
if (year != -1)
cal.set(Calendar.YEAR, year);
if (month != -1)
cal.set(Calendar.MONTH, month - 1); // Calendar month start with 0
if (day != -1)
cal.set(Calendar.DAY_OF_MONTH, day);
if (hour != -1)
cal.set(Calendar.HOUR_OF_DAY, hour);
if (minute != -1)
cal.set(Calendar.MINUTE, minute);
if (second != -1)
cal.set(Calendar.SECOND, second);
if (milli != -1)
cal.set(Calendar.MILLISECOND, milli);
if (timezone == REQUIRED || timezone == IF_PRESENT
|| timezone == OPTIONAL) {
if (timezone == REQUIRED && tzNegative == null)
throw new UOMoException(Messages.Iso8601Date_TZ_NOT_DEFINED);
if (tzNegative != null) {
TimeZone tzMsg = TimeZone.getTimeZone(Messages.Iso8601Date_GMT
+ prepTimezone());
cal.setTimeZone(tzMsg);
}
}
return cal.getTime();
}
/**
*
* @param date
* the date to set the component fields to
* @param timezone
* - what to do about timezone (CLEAR, SETLOCAL or IGNORE)
*/
public void setAsDate(Date date, int timezone) {
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(date);
reset(timezone != IGNORE);
year = cal.get(Calendar.YEAR);
month = cal.get(Calendar.MONTH) + 1; // java Month starts from 0, but
// ours starts from 1
day = cal.get(Calendar.DAY_OF_MONTH);
hour = cal.get(Calendar.HOUR_OF_DAY);
minute = cal.get(Calendar.MINUTE);
second = cal.get(Calendar.SECOND);
milli = cal.get(Calendar.MILLISECOND);
if (timezone == CLEAR) {
tzHour = 0;
tzMinute = 0;
tzNegative = null;
} else if (timezone == SETLOCAL) {
TimeZone tzLcl = TimeZone.getDefault();
int offset = tzLcl.getOffset(date.getTime());
if (offset < 0) {
tzNegative = new Boolean(true);
offset = -offset;
} else {
tzNegative = new Boolean(true);
}
tzHour = offset / (1000 * 60 * 60);
tzMinute = (offset - (tzHour * 1000 * 60 * 60)) / (1000 * 60);
}
}
// String format
/**
* get the date as a formatted string
*
* @param format
* - the format to use. Must be consistent with the components
* provided. Will be cross-checked
* @param timezone
* - what to do about timezone (REQUIRED, IF_PRESENT, PROHIBITED,
* IGNORE)
* @return
* @throws OHFException
* if cross check fails
*/
public String render(String format, boolean checkValues, int timezone)
throws UOMoException {
String v = validate(false);
if (v != null)
throw new UOMoException(v);
StringBuffer str = new StringBuffer();
render(str,
checkValues,
format.length() >= 4
&& Messages.Iso8601Date_yyyy.equalsIgnoreCase(format
.substring(0, 4)), 4, year, format,
Messages.Iso8601Date_year, null);
render(str,
checkValues,
format.length() >= 6
&& Messages.Iso8601Date_mm.equalsIgnoreCase(format
.substring(4, 6)), 2, month, format,
Messages.Iso8601Date_month, null);
render(str,
checkValues,
format.length() >= 8
&& Messages.Iso8601Date_dd.equalsIgnoreCase(format
.substring(6, 8)), 2, day, format,
Messages.Iso8601Date_day, null);
render(str,
checkValues,
format.length() >= 10
&& Messages.Iso8601Date_hh.equalsIgnoreCase(format
.substring(8, 10)), 2, hour, format,
Messages.Iso8601Date_hour, null);
render(str,
checkValues,
format.length() >= 12
&& Messages.Iso8601Date_nn.equalsIgnoreCase(format
.substring(10, 12)), 2, minute, format,
Messages.Iso8601Date_minute, null);
render(str,
checkValues,
format.length() >= 14
&& Messages.Iso8601Date_ss.equalsIgnoreCase(format
.substring(12, 14)), 2, second, format,
Messages.Iso8601Date_second, null);
if (format.length() >= 18
&& Messages.Iso8601Date_sss.equalsIgnoreCase(format.substring(
15, 18))) {
render(str, checkValues, true, 3, milli, format,
Messages.Iso8601Date_milisecond, Messages.Iso8601Date_DOT);
} else if (format.length() == 17
&& "ss".equalsIgnoreCase(format.substring(15, 17))) { //$NON-NLS-1$
render(str, checkValues, true, 2, milli / 10, format,
"millisecond", Messages.Iso8601Date_DOT); //$NON-NLS-1$
} else if (format.length() == 16
&& Messages.Iso8601Date_s.equalsIgnoreCase(format.substring(15,
16))) {
render(str, checkValues, true, 1, milli / 100, format,
"millisecond", "."); //$NON-NLS-1$ //$NON-NLS-2$
}
if (timezone == REQUIRED || timezone == IF_PRESENT) {
if (timezone == REQUIRED && tzNegative == null)
throw new UOMoException(
Messages.Iso8601Date_TZ_REQUIRED_BUT_NOT_DEFINED);
if (tzNegative != null) {
if (tzNegative.booleanValue())
str.append('-');
else
str.append('+');
render(str, checkValues, true, 2, tzHour, format,
Messages.Iso8601Date_tz_hour, null);
render(str, checkValues, true, 2, tzMinute, format,
Messages.Iso8601Date_tz_minutes, null);
}
}
if (timezone == PROHIBITED && tzNegative != null)
throw new UOMoException(
Messages.Iso8601Date_TZ_PROHIBITED_BUT_DEFINED);
return str.toString();
}
private void render(StringBuffer str, boolean checkValues, boolean render,
int len, int value, String format, String desc, String prefix)
throws UOMoException {
if (render) {
if (value != -1) {
if (prefix != null)
str.append(prefix);
str.append(StringUtils.leftPad(Integer.toString(value), len,
Messages.Iso8601Date_ZERO));
} else if (checkValues)
throw new UOMoException(
Messages.Iso8601Date_NO_SUCH_VALUE_PROVIDED
+ format
+ "' specifies " + desc + " but no such value has been provided"); //$NON-NLS-2$ //$NON-NLS-3$
}
}
/**
* Parse the value. no rules other than the base format rules
*
* @param value
* - the value to parse
*/
public void parse(String value) {
parse(value, ISO_DATE_VALIDATION_FULL, OPTIONAL);
}
/**
* Parse the value. check that it conforms to the specified format and
* timezone rules
*
* @param value
* - the value to parse
* @param format
* - the format rules to adhere to
* @param timezone
* - rules for timezone (REQUIRED, OPTIONAL, PROHIBITED, IGNORE)
* @return - String description of parsing error, or null if no error
* encountered
*/
public String parse(String value, String format, int timezone) {
reset(timezone != IGNORE);
String[] parts = { value };
tzNegative = null;
if (value.indexOf('+') > 0) {
parts = StringUtils.split(value, "+", 2); //$NON-NLS-1$
tzNegative = new Boolean(false);
} else if (value.indexOf('-') > 0) {
parts = StringUtils.split(value, "-", 2); //$NON-NLS-1$
tzNegative = new Boolean(true);
}
String error = checkSections(parts[0], value, format);
if (error != null)
return error;
if (parts.length > 1 && timezone != IGNORE)
error = checkSections(parts[1], value, Messages.Iso8601Date_58);
if (error != null)
return error;
if (timezone == REQUIRED) {
if (parts.length < 2)
return Messages.Iso8601Date_59;
} else if (timezone == PROHIBITED && parts.length > 1)
return Messages.Iso8601Date_60;
return null;
}
/**
* Parse the value to a Date. check that it conforms to the specified format
* and timezone rules
*
* @param value
* - the value to parse
* @param format
* - the format rules to adhere to
* @param timezone
* - rules for timezone (REQUIRED, OPTIONAL, PROHIBITED, IGNORE)
* @return - Date (or throw exception if conversion not successful
*/
public static Date parseToDate(String value, String format, int timezone)
throws UOMoException {
Iso8601Date d = new Iso8601Date();
String err = d.parse(value, format, timezone);
if (err != null)
throw new UOMoException(Messages.Iso8601Date_61 + value
+ Messages.Iso8601Date_62 + err);
return d.getAsDate(timezone);
}
public static String renderFromDate(Date date, String format, int timezone)
throws UOMoException {
Iso8601Date d = new Iso8601Date();
d.setAsDate(date, timezone == REQUIRED ? SETLOCAL : CLEAR);
return d.render(format, true, timezone);
}
// private parsing routines
private boolean inFraction;
private String checkSections(String content, String whole, String mask) {
String workingMask = StringUtils.strip(mask, Messages.Iso8601Date_63);
String[] parts = { "", workingMask }; //$NON-NLS-1$
boolean first = true;
inFraction = false;
do {
parts = StringUtils.splitPreserveAllTokens(parts[1],
Messages.Iso8601Date_65, 2);
String token = parts[0];
if (token != null) { // support use of [ at first point to make
// everything optional
String section = content == null
|| content.length() < token.length() ? null : content
.substring(0, token.length()); // sSection =
// copy(sContent, 1,
// length(sToken));
if (section == null) { // if sSection = '' then
if (!first) {
if (content != null
&& content.length() < token.length())
return Messages.Iso8601Date_66 + content
+ Messages.Iso8601Date_67 + token;
else
return Messages.Iso8601Date_68 + token
+ Messages.Iso8601Date_69 + mask
+ Messages.Iso8601Date_70 + whole;
}
} else if (section.length() < token.length()) {
return Messages.Iso8601Date_71 + token
+ Messages.Iso8601Date_72 + mask
+ Messages.Iso8601Date_73 + whole
+ Messages.Iso8601Date_74 + section;
} else {
String error = checkSection(token, section);
if (error != null)
return error;
else if (section.length() >= content.length())
content = null;
else
content = content.substring(section.length());
}
}
first = false;
} while (parts.length > 1 && content != null); // until not result or
// (sFormat = '') or
// (sContent = '');
if (content != null) {
return Messages.Iso8601Date_75 + content + Messages.Iso8601Date_76
+ whole + Messages.Iso8601Date_77 + mask;
} else
return null;
}
private boolean starts(String source, String test) {
return source == null || source.length() < test.length() ? false
: source.substring(0, test.length()).equals(test);
}
private String checkSection(String token, String content) {
String error = null;
if (starts(token, Messages.Iso8601Date_YYYY)) {
error = checkYear(content.substring(0, 4));
if (error != null)
return error;
token = token.substring(4, token.length());
content = content.substring(4, content.length());
}
;
if (starts(token, Messages.Iso8601Date_MM)) {
error = checkMonth(content.substring(0, 2));
if (error != null)
return error;
token = token.substring(2, token.length());
content = content.substring(2, content.length());
}
;
if (starts(token, Messages.Iso8601Date_DD)) {
error = checkDay(content.substring(0, 2));
if (error != null)
return error;
token = token.substring(2, token.length());
content = content.substring(2, content.length());
}
;
if (starts(token, Messages.Iso8601Date_HH)) {
error = checkHour(content.substring(0, 2), false);
if (error != null)
return error;
token = token.substring(2, token.length());
content = content.substring(2, content.length());
}
;
if (starts(token, Messages.Iso8601Date_TT)) {
error = checkHour(content.substring(0, 2), true);
if (error != null)
return error;
token = token.substring(2, token.length());
content = content.substring(2, content.length());
}
;
if (starts(token, Messages.Iso8601Date_NN)) {
error = checkMinute(content.substring(0, 2), false);
if (error != null)
return error;
token = token.substring(2, token.length());
content = content.substring(2, content.length());
}
;
if (starts(token, Messages.Iso8601Date_tt)) {
error = checkMinute(content.substring(0, 2), true);
if (error != null)
return error;
token = token.substring(2, token.length());
content = content.substring(2, content.length());
}
;
if (starts(token, Messages.Iso8601Date_SS) && !inFraction) {
error = checkSecond(content.substring(0, 2));
if (error != null)
return error;
token = token.substring(2, token.length());
content = content.substring(2, content.length());
}
;
if (starts(token, ".") && !inFraction) { //$NON-NLS-1$
error = checkDot(content.substring(0, 1));
if (error != null)
return error;
token = token.substring(1, token.length());
content = content.substring(1, content.length());
}
;
while (starts(token, Messages.Iso8601Date_U) && inFraction) {
error = checkFraction(content.substring(0, 1));
if (error != null)
return error;
token = token.substring(1, token.length());
content = content.substring(1, content.length());
}
;
if (!(token == null || token.equals(""))) //$NON-NLS-1$
return Messages.Iso8601Date_DATE_FRAGMENT_NOT_KNOWN + token
+ " is not known"; //$NON-NLS-2$
return null;
}
private String checkYear(String value) {
if (value.length() != 4)
return "Year Value " + value + " is not 4 digits in length"; //$NON-NLS-1$ //$NON-NLS-2$
else if (!StringUtils.isNumeric(value))
return Messages.Iso8601Date_YEAR_VALUE_NOT_NUMERICAL + value
+ " is not numerical"; //$NON-NLS-2$
else {
year = Integer.parseInt(value);
if (year <= 0)
return Messages.Iso8601Date_YEAR_VALUE_NEGATIVE_NOT_SUPPORTED
+ value + ": negative numbers are not supported"; //$NON-NLS-2$
else
return null;
}
}
private String checkMonth(String value) {
if (value.length() != 2)
return Messages.Iso8601Date_MONTH_VALUE_NOT_2_DIGITS + value
+ " is not 2 digits in length"; //$NON-NLS-2$
else if (!StringUtils.isNumeric(value))
return Messages.Iso8601Date_MONTH_VALUE_NOT_NUMERICAL + value
+ " is not numerical"; //$NON-NLS-2$
else {
month = Integer.parseInt(value);
if (month <= 0 || month > 12)
return Messages.Iso8601Date_MONTH_VALUE_MUST_BE_1_12 + value
+ ": month must be 1 - 12"; //$NON-NLS-2$
else
return null;
}
}
private String checkDay(String value) {
if (value.length() != 2)
return Messages.Iso8601Date_DAY_VALUE_NOT_2_DIGITS + value
+ " is not 2 digits in length"; //$NON-NLS-2$
else if (!StringUtils.isNumeric(value))
return Messages.Iso8601Date_DAY_VALUE_NOT_NUMERICAL + value
+ " is not numerical"; //$NON-NLS-2$
else {
day = Integer.parseInt(value);
if (day <= 0)
return Messages.Iso8601Date_DAY_VALUE_MUST_BE_POSITIVE + value
+ ": Day must be >= 1"; //$NON-NLS-2$
else if (month == 0)
return Messages.Iso8601Date_DAY_VALUE_MONTH_MUST_BE_KNOWN
+ value + ": Month must be known"; //$NON-NLS-2$
else if (year == 0)
return Messages.Iso8601Date_DAY_VALUE_YEAR_MUST_BE_KNOWN
+ value + ": Year must be known"; //$NON-NLS-2$
else if (day > daysForMonth(month, year))
return Messages.Iso8601Date_DAY_VALUE_ILLEGAL_FOR_MONTH
+ value
+ ": is illegal for the month " + Integer.toString(month) + "-" + Integer.toString(year); //$NON-NLS-2$ //$NON-NLS-3$
else
return null;
}
}
private int daysForMonth(int m, int y) {
int[] daysInMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (m < 1 || m > 12)
return 30;
else if (m == 2 && new GregorianCalendar().isLeapYear(y))
return 29;
else
return daysInMonth[m - 1];
}
private String checkHour(String value, boolean inTimezone) {
if (value.length() != 2)
return Messages.Iso8601Date_HOUR_VALUE_NOT_2_DIGITS + value
+ " is not 2 digits in length"; //$NON-NLS-2$
else if (!StringUtils.isNumeric(value))
return Messages.Iso8601Date_HOUR_VALUE_NOT_NUMERICAL + value
+ " is not numerical"; //$NON-NLS-2$
else if (inTimezone) {
tzHour = Integer.parseInt(value);
if (tzHour < 0)
return Messages.Iso8601Date_TZ_HOUR_VALUE_MUST_BE_0_OR_POSITIVE
+ value + ": Hour must be >= 0"; //$NON-NLS-2$
else if (tzHour > 12)
return Messages.Iso8601Date_TZ_HOUR_VALUE_MUST_BE_12_OR_LESS
+ value + ": Hour must be <= 12"; //$NON-NLS-2$
} else {
hour = Integer.parseInt(value);
if (hour < 0)
return Messages.Iso8601Date_HOUR_VALUE_MUST_BE_0_OR_POSITIVE
+ value + ": Hour must be >= 0"; //$NON-NLS-2$
else if (inTimezone && hour > 12)
return Messages.Iso8601Date_HOUR_VALUE_MUST_BE_12_OR_LESS
+ value + ": Hour must be <= 12"; //$NON-NLS-2$
else if (hour > 23)
return Messages.Iso8601Date_TZ_HOUR_VALUE_MUST_BE_23_OR_LESS
+ value + ": Hour must be <= 23"; //$NON-NLS-2$
}
return null;
}
private String checkMinute(String value, boolean inTimezone) {
if (value.length() != 2)
return Messages.Iso8601Date_MINUTE_VALUE_NOT_2_DIGITS_LONG + value
+ " is not 2 digits in length"; //$NON-NLS-2$
else if (!StringUtils.isNumeric(value))
return Messages.Iso8601Date_MINUTE_VALUE_NOT_NUMERICAL + value
+ " is not numerical"; //$NON-NLS-2$
else if (inTimezone) {
tzMinute = Integer.parseInt(value);
if (tzMinute != 0 && tzMinute != 30)
return Messages.Iso8601Date_TZ_MINUTE_VALUE_MUST_BE_0_OR_30
+ value + ": Minute must be 0 or 30"; //$NON-NLS-2$
} else {
minute = Integer.parseInt(value);
if (minute < 0 || minute > 59)
return Messages.Iso8601Date_MINUTE_VALUE_MUST_BE_0_AND_59
+ value + ": Minute must be 0 and 59"; //$NON-NLS-2$
}
return null;
}
private String checkSecond(String value) {
if (value.length() != 2)
return Messages.Iso8601Date_SECOND_VALUE_NOT_2_DIGITS_LONG + value
+ " is not 2 digits in length"; //$NON-NLS-2$
else if (!StringUtils.isNumeric(value))
return Messages.Iso8601Date_SECOND_VALUE_NOT_NUMERICAL + value
+ " is not numerical"; //$NON-NLS-2$
else {
second = Integer.parseInt(value);
if (second < 0 || second > 59)
return NLS.bind(
Messages.Iso8601Date_SECOND_VALUE_MUST_BE_0_AND_59,
value);
else
return null;
}
}
private String checkDot(String value) {
if (value.equals(".")) { //$NON-NLS-1$
inFraction = true;
return null;
} else
return Messages.Iso8601Date_EXPECTED_DOT;
}
private String checkFraction(String value) {
// TODO - read milliseconds
if (!StringUtils.isNumeric(value))
return Messages.Iso8601Date_FRACT_VAL_NOT_NUMERICAL + value
+ " is not numerical"; //$NON-NLS-2$
else
return null;
}
private String prepTimezone() {
return (tzNegative.booleanValue() ? Messages.Iso8601Date_MINUS
: Messages.Iso8601Date_PLUS)
+ StringUtils.leftPad(Integer.toString(tzHour), 2, '0')
+ StringUtils.leftPad(Integer.toString(tzMinute), 2, '0');
}
}