in asterixdb/asterix-om/src/main/java/org/apache/asterix/om/base/temporal/DateTimeFormatUtils.java [311:987]
public boolean parseDateTime(AMutableInt64 outChronon, Mutable<Boolean> outTimeZoneExists,
AMutableInt32 outTimeZone, Mutable<Character> dateTimeSeparatorOut, byte[] data, int dataStart,
int dataLength, byte[] format, int formatStart, int formatLength, DateTimeParseMode parseMode,
boolean raiseParseDataError, char altSeparatorChar, boolean adjustChrononByTimezone)
throws AsterixTemporalTypeParseException {
int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0, ms = 0, timezone = 0;
boolean timezoneExists = false;
boolean negativeYear = false;
int formatCharCopies;
int dataStringPointer = 0, formatPointer = 0;
char separatorChar = '\0';
char lastSeparatorChar = '\0';
char dateTimeSeparatorChar = 'T'; //default dateTimeSeparator
DateTimeProcessState processState;
int pointerMove;
while (dataStringPointer < dataLength && formatPointer < formatLength) {
formatCharCopies = 0;
switch (format[formatStart + formatPointer]) {
case YEAR_CHAR:
processState = DateTimeProcessState.YEAR;
pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, YEAR_CHAR,
MAX_YEAR_CHARS);
formatPointer += pointerMove;
formatCharCopies += pointerMove;
break;
case QUARTER_CHAR:
processState = DateTimeProcessState.QUARTER;
pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, QUARTER_CHAR,
MAX_QUARTER_CHARS);
formatPointer += pointerMove;
formatCharCopies += pointerMove;
break;
case MONTH_CHAR:
processState = DateTimeProcessState.MONTH;
pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, MONTH_CHAR,
MAX_MONTH_CHARS);
formatPointer += pointerMove;
formatCharCopies += pointerMove;
break;
case DAY_CHAR:
processState = DateTimeProcessState.DAY;
pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, DAY_CHAR,
MAX_DAY_CHARS_PARSE);
formatPointer += pointerMove;
formatCharCopies += pointerMove;
break;
case WEEKDAY_CHAR:
processState = DateTimeProcessState.WEEKDAY;
pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, WEEKDAY_CHAR,
MAX_WEEKDAY_CHAR);
if (pointerMove < MIN_WEEKDAY_CHAR) {
throw new AsterixTemporalTypeParseException(
String.format("Expected at least %d '%s' characters but got %d", MIN_WEEKDAY_CHAR,
WEEKDAY_CHAR, pointerMove));
}
formatPointer += pointerMove;
formatCharCopies += pointerMove;
break;
case HOUR_CHAR:
processState = DateTimeProcessState.HOUR;
pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, HOUR_CHAR,
MAX_HOUR_CHARS);
formatPointer += pointerMove;
formatCharCopies += pointerMove;
break;
case MINUTE_CHAR:
processState = DateTimeProcessState.MINUTE;
pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, MINUTE_CHAR,
MAX_MINUTE_CHARS);
formatPointer += pointerMove;
formatCharCopies += pointerMove;
break;
case SECOND_CHAR:
processState = DateTimeProcessState.SECOND;
pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, SECOND_CHAR,
MAX_SECOND_CHARS);
formatPointer += pointerMove;
formatCharCopies += pointerMove;
break;
case MILLISECOND_CHAR:
processState = DateTimeProcessState.MILLISECOND;
pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, MILLISECOND_CHAR,
MAX_MILLISECOND_CHARS);
formatPointer += pointerMove;
formatCharCopies += pointerMove;
break;
case MILLISECOND_CHAR_ALT:
processState = DateTimeProcessState.MILLISECOND;
pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer,
MILLISECOND_CHAR_ALT, MAX_MILLISECOND_CHARS);
formatPointer += pointerMove;
formatCharCopies += pointerMove;
break;
case AMPM_CHAR:
processState = DateTimeProcessState.AMPM;
pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, AMPM_CHAR,
MAX_AMPM_CHARS);
formatPointer += pointerMove;
formatCharCopies += pointerMove;
break;
case TIMEZONE_CHAR:
processState = DateTimeProcessState.TIMEZONE;
pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, TIMEZONE_CHAR,
MAX_TIMEZONE_CHARS);
formatPointer += pointerMove;
formatCharCopies += pointerMove;
break;
case SKIPPER_CHAR:
processState = DateTimeProcessState.SKIPPER;
pointerMove = parseFormatField(format, formatStart, formatLength, formatPointer, SKIPPER_CHAR,
MAX_SKIPPER_CHAR);
formatPointer += pointerMove;
formatCharCopies += pointerMove;
break;
case ' ':
case HYPHEN_CHAR:
case COLON_CHAR:
case SOLIDUS_CHAR:
case PERIOD_CHAR:
case COMMA_CHAR:
case T_CHAR:
// separator
separatorChar = (char) format[formatStart + formatPointer];
processState = DateTimeProcessState.SEPARATOR;
formatPointer++;
formatCharCopies++;
while (formatPointer < formatLength
&& (char) (format[formatStart + formatPointer]) == separatorChar) {
formatPointer++;
formatCharCopies++;
}
break;
default:
throw new AsterixTemporalTypeParseException("Unexpected date format string at "
+ (formatStart + formatPointer) + ": " + (char) format[formatStart + formatPointer]);
}
// check whether the process state is valid for the parse mode
switch (processState) {
case YEAR:
case QUARTER:
case MONTH:
case DAY:
if (parseMode == DateTimeParseMode.TIME_ONLY) {
throw new AsterixTemporalTypeParseException(
"Unexpected date format string when parsing a time value");
}
break;
case HOUR:
case MINUTE:
case SECOND:
case MILLISECOND:
case AMPM:
case TIMEZONE:
if (parseMode == DateTimeParseMode.DATE_ONLY) {
throw new AsterixTemporalTypeParseException(
"Unexpected time format string when parsing a date value");
}
break;
default:
// do nothing
}
switch (processState) {
case YEAR:
if (dataStringPointer < dataLength && data[dataStart + dataStringPointer] == HYPHEN_CHAR) {
negativeYear = true;
dataStringPointer++;
}
case DAY:
int maxAllowedFormatCharCopies = (processState == DateTimeProcessState.YEAR) ? 4 : 2;
int parsedValue = 0;
int processedFieldsCount = 0;
for (int i = 0; i < formatCharCopies; i++) {
if (data[dataStart + dataStringPointer] < '0' || data[dataStart + dataStringPointer] > '9') {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException("Unexpected char for year field at "
+ (dataStart + dataStringPointer) + ": " + data[dataStart + dataStringPointer]);
} else {
return false;
}
}
parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
dataStringPointer++;
processedFieldsCount++;
}
// for more digits
while (processedFieldsCount < maxAllowedFormatCharCopies && dataStringPointer < dataLength
&& data[dataStart + dataStringPointer] >= '0'
&& data[dataStart + dataStringPointer] <= '9') {
parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
dataStringPointer++;
processedFieldsCount++;
}
if (processState == DateTimeProcessState.YEAR) {
year = parsedValue;
if (negativeYear) {
year *= -1;
}
// Allow month and day to be missing if we parsed year
if (month == 0) {
month = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.MONTH.ordinal()];
}
if (day == 0) {
day = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.DAY.ordinal()];
}
} else {
if (parsedValue == 0) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"Incorrect day value at " + (dataStart + dataStringPointer));
} else {
return false;
}
}
day = parsedValue;
}
break;
case QUARTER:
// the month is in the number format
parsedValue = 0;
int processedQuarterFieldsCount = 0;
for (int i = 0; i < formatCharCopies; i++) {
if (data[dataStart + dataStringPointer] < '0' || data[dataStart + dataStringPointer] > '9') {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException("Unexpected char for quarter field at "
+ (dataStart + dataStringPointer) + ": " + data[dataStart + dataStringPointer]);
} else {
return false;
}
}
parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
dataStringPointer++;
if (processedQuarterFieldsCount++ > 2) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException("Unexpected char for quarter field at "
+ (dataStart + dataStringPointer) + ": " + data[dataStart + dataStringPointer]);
} else {
return false;
}
}
}
// if there are more than 2 digits for the quarter string
while (processedQuarterFieldsCount < 2 && dataStringPointer < dataLength
&& data[dataStart + dataStringPointer] >= '0'
&& data[dataStart + dataStringPointer] <= '9') {
parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
dataStringPointer++;
processedQuarterFieldsCount++;
}
if (parsedValue == 0) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"Incorrect quarter value at " + (dataStart + dataStringPointer));
} else {
return false;
}
}
month = (parsedValue - 1) * 3 + 1;
// Allow day to be missing if we parsed quarter
if (day == 0) {
day = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.DAY.ordinal()];
}
break;
case MONTH:
if (formatCharCopies >= 3) {
// the month is in the text format
int processedMonthFieldsCount = 0;
while (((dataStringPointer + processedMonthFieldsCount < dataLength)) && ((data[dataStart
+ dataStringPointer + processedMonthFieldsCount] >= 'a'
&& data[dataStart + dataStringPointer + processedMonthFieldsCount] <= 'z')
|| (data[dataStart + dataStringPointer + processedMonthFieldsCount] >= 'A'
&& data[dataStart + dataStringPointer + processedMonthFieldsCount] <= 'Z'))) {
processedMonthFieldsCount++;
}
boolean useShortNames = formatCharCopies == 3;
int monthNameMatch = monthIDSearch(data, dataStart + dataStringPointer,
processedMonthFieldsCount, useShortNames);
if (monthNameMatch >= 0) {
month = monthNameMatch + 1;
dataStringPointer += processedMonthFieldsCount;
} else {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"Unrecognizable month string " + (char) data[dataStart + dataStringPointer]
+ " " + (char) data[dataStart + dataStringPointer + 1] + " "
+ (char) data[dataStart + dataStringPointer + 2]);
} else {
return false;
}
}
} else {
// the month is in the number format
parsedValue = 0;
int processedMonthFieldsCount = 0;
for (int i = 0; i < formatCharCopies; i++) {
if (data[dataStart + dataStringPointer] < '0'
|| data[dataStart + dataStringPointer] > '9') {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"Unexpected char for month field at " + (dataStart + dataStringPointer)
+ ": " + data[dataStart + dataStringPointer]);
} else {
return false;
}
}
parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
dataStringPointer++;
if (processedMonthFieldsCount++ > 2) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"Unexpected char for month field at " + (dataStart + dataStringPointer)
+ ": " + data[dataStart + dataStringPointer]);
} else {
return false;
}
}
}
// if there are more than 2 digits for the month string
while (processedMonthFieldsCount < 2 && dataStringPointer < dataLength
&& data[dataStart + dataStringPointer] >= '0'
&& data[dataStart + dataStringPointer] <= '9') {
parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
dataStringPointer++;
processedMonthFieldsCount++;
}
if (parsedValue == 0) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"Incorrect month value at " + (dataStart + dataStringPointer));
} else {
return false;
}
}
month = parsedValue;
}
// Allow day to be missing if we parsed month
if (day == 0) {
day = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.DAY.ordinal()];
}
break;
case WEEKDAY:
int processedWeekdayFieldsCount = 0;
while ((dataStringPointer + processedWeekdayFieldsCount < dataLength) && ((data[dataStart
+ dataStringPointer + processedWeekdayFieldsCount] >= 'a'
&& data[dataStart + dataStringPointer + processedWeekdayFieldsCount] <= 'z')
|| (data[dataStart + dataStringPointer + processedWeekdayFieldsCount] >= 'A'
&& data[dataStart + dataStringPointer + processedWeekdayFieldsCount] <= 'Z'))) {
processedWeekdayFieldsCount++;
}
// match the weekday name
boolean useShortNames = formatCharCopies == 3;
int weekdayNameMatch = weekdayIDSearch(data, dataStart + dataStringPointer,
processedWeekdayFieldsCount, useShortNames);
if (weekdayNameMatch < 0) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException("Unexpected string for day-of-week: "
+ new String(data, dataStart + dataStringPointer,
dataStart + dataStringPointer + processedWeekdayFieldsCount, ENCODING));
} else {
return false;
}
}
dataStringPointer += processedWeekdayFieldsCount;
break;
case HOUR:
dateTimeSeparatorChar = lastSeparatorChar;
case MINUTE:
case SECOND:
case MILLISECOND:
int processFieldsCount = 0;
int expectedMaxCount = (processState == DateTimeProcessState.MILLISECOND) ? 3 : 2;
parsedValue = 0;
for (int i = 0; i < formatCharCopies; i++) {
if (data[dataStart + dataStringPointer] < '0' || data[dataStart + dataStringPointer] > '9') {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException("Unexpected char for " + processState.name()
+ " field at " + (dataStart + dataStringPointer) + ": "
+ data[dataStart + dataStringPointer]);
} else {
return false;
}
}
parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
dataStringPointer++;
if (processFieldsCount++ > expectedMaxCount) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"Unexpected char for " + processState.name() + " field at " + dataStringPointer
+ ": " + data[dataStart + dataStringPointer]);
} else {
return false;
}
}
}
// if there are more than formatCharCopies digits for the hour string
while (processFieldsCount < expectedMaxCount && dataStringPointer < dataLength
&& data[dataStart + dataStringPointer] >= '0'
&& data[dataStart + dataStringPointer] <= '9') {
parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
dataStringPointer++;
processFieldsCount++;
}
if (processState == DateTimeProcessState.HOUR) {
hour = parsedValue;
} else if (processState == DateTimeProcessState.MINUTE) {
min = parsedValue;
} else if (processState == DateTimeProcessState.SECOND) {
sec = parsedValue;
} else if (processState == DateTimeProcessState.MILLISECOND) {
//read remaining millis values
while (dataStringPointer < dataLength && data[dataStart + dataStringPointer] >= '0'
&& data[dataStart + dataStringPointer] <= '9') {
//parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
dataStringPointer++;
processFieldsCount++;
}
ms = parsedValue;
for (int i = processFieldsCount; i < 3; i++) {
ms *= 10;
}
}
break;
case TIMEZONE:
if (data[dataStart + dataStringPointer] == 'Z'
&& ((dataStringPointer + 1 >= dataLength) || (data[dataStart + dataStringPointer + 1] < 'A'
&& data[dataStart + dataStringPointer + 1] > 'Z'
&& data[dataStart + dataStringPointer + 1] < 'a'
&& data[dataStart + dataStringPointer + 1] > 'z'))) {
// UTC as Z
timezone = 0;
dataStringPointer++;
} else if ((data[dataStart + dataStringPointer] == '+'
|| data[dataStart + dataStringPointer] == '-')
|| (dataStringPointer + 3 < dataLength && (data[dataStart + dataStringPointer + 3] == '+'
|| data[dataStart + dataStringPointer + 3] == '-'))) {
// UTC+ or GMT+ format
if (dataStringPointer + 3 < dataLength && (byteArrayEqualToString(data,
dataStart + dataStringPointer, 3, UTC_BYTEARRAY)
|| byteArrayEqualToString(data, dataStart + dataStringPointer, 3, GMT_BYTEARRAY))) {
dataStringPointer += 3;
}
// parse timezone as +zz:zz or +zzzz
boolean negativeTimeZone = false;
if (data[dataStart + dataStringPointer] == '-') {
negativeTimeZone = true;
dataStringPointer++;
} else if (data[dataStart + dataStringPointer] == '+') {
dataStringPointer++;
} else {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"Incorrect timezone hour field: expecting sign + or - but got: "
+ data[dataStart + dataStringPointer]);
} else {
return false;
}
}
parsedValue = 0;
// timezone hours
for (int i = 0; i < 2; i++) {
if (data[dataStart + dataStringPointer + i] >= '0'
&& data[dataStart + dataStringPointer + i] <= '9') {
parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer + i] - '0');
} else {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"Unexpected character for timezone hour field at "
+ (dataStart + dataStringPointer) + ": "
+ data[dataStart + dataStringPointer]);
} else {
return false;
}
}
}
dataStringPointer += 2;
// skip the ":" separator
if (data[dataStart + dataStringPointer] == ':') {
dataStringPointer++;
}
timezone = (int) (parsedValue * GregorianCalendarSystem.CHRONON_OF_HOUR);
parsedValue = 0;
// timezone minutes
for (int i = 0; i < 2; i++) {
if (data[dataStart + dataStringPointer + i] >= '0'
&& data[dataStart + dataStringPointer + i] <= '9') {
parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer + i] - '0');
} else {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"Unexpected character for timezone minute field at "
+ (dataStart + dataStringPointer) + ": "
+ data[dataStart + dataStringPointer]);
} else {
return false;
}
}
}
timezone += (int) (parsedValue * GregorianCalendarSystem.CHRONON_OF_MINUTE);
dataStringPointer += 2;
if (!negativeTimeZone) {
timezone *= -1;
}
} else {
// do lookup from the zoneinfor database
int timezoneEndField = dataStringPointer;
while (timezoneEndField < dataLength && ((data[dataStart + timezoneEndField] >= '0'
&& data[dataStart + timezoneEndField] <= '9')
|| (data[dataStart + timezoneEndField] >= 'a'
&& data[dataStart + timezoneEndField] <= 'z')
|| (data[dataStart + timezoneEndField] >= 'A'
&& data[dataStart + timezoneEndField] <= 'Z')
|| data[dataStart + timezoneEndField] == '/'
|| data[dataStart + timezoneEndField] == '_')) {
timezoneEndField++;
}
TimeZone tz =
findTimeZone(data, dataStart + dataStringPointer, timezoneEndField - dataStringPointer);
if (tz != null) {
timezone = tz.getRawOffset();
} else {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException("Unexpected timezone string: " + new String(
data, dataStart + dataStringPointer, dataStart + timezoneEndField, ENCODING));
} else {
return false;
}
}
dataStringPointer = timezoneEndField;
}
timezoneExists = true;
break;
case AMPM:
if (dataStringPointer + 1 < dataLength) {
if (hour > 12 || hour <= 0) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"Hour " + hour + " cannot be a time for AM/PM.");
} else {
return false;
}
}
if (byteArrayEqualToString(data, dataStart + dataStringPointer, 2, AM_BYTEARRAY)) {
// do nothing
} else if (byteArrayEqualToString(data, dataStart + dataStringPointer, 2, PM_BYTEARRAY)) {
hour += 12;
if (hour == 24) {
hour = 0;
}
} else {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException("Unexpected string for AM/PM marker "
+ new String(data, dataStart + dataStringPointer,
dataStart + dataStringPointer + 2, ENCODING));
} else {
return false;
}
}
dataStringPointer += 2;
} else {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException("Cannot find valid AM/PM marker.");
} else {
return false;
}
}
break;
case SKIPPER:
// just skip all continuous character and numbers
while ((data[dataStart + dataStringPointer] >= 'a' && data[dataStart + dataStringPointer] <= 'z')
|| (data[dataStart + dataStringPointer] >= 'A'
&& data[dataStart + dataStringPointer] <= 'Z')
|| (data[dataStart + dataStringPointer] >= '0'
&& data[dataStart + dataStringPointer] <= '9')) {
dataStringPointer++;
}
break;
case SEPARATOR:
for (int i = 0; i < formatCharCopies; i++) {
byte b = data[dataStart + dataStringPointer];
boolean match =
(char) b == separatorChar || (altSeparatorChar != '\0' && (char) b == altSeparatorChar);
if (!match) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"Expecting separator " + separatorChar + " but got " + b);
} else {
return false;
}
}
lastSeparatorChar = (char) b;
dataStringPointer++;
}
break;
default:
throw new AsterixTemporalTypeParseException(
"Unexpected time format information when parsing a date value");
}
}
if (dataStringPointer < dataLength) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"The given data string is not fully parsed by the given format string");
} else {
return false;
}
}
if (formatPointer < formatLength) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException(
"The given format string is not fully used for the given data string");
} else {
return false;
}
}
long chronon;
if (parseMode == DateTimeParseMode.TIME_ONLY) {
int minYear = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.YEAR.ordinal()];
int minMonth = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.MONTH.ordinal()];
int minDay = GregorianCalendarSystem.FIELD_MINS[GregorianCalendarSystem.Fields.DAY.ordinal()];
if (!CAL.validate(minYear, minMonth, minDay, hour, min, sec, ms)) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException("Invalid time value");
} else {
return false;
}
}
chronon = CAL.getChronon(hour, min, sec, ms);
} else {
if (!CAL.validate(year, month, day, hour, min, sec, ms)) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException("Invalid date/time value");
} else {
return false;
}
}
chronon = CAL.getChronon(year, month, day, hour, min, sec, ms);
}
if (timezoneExists && adjustChrononByTimezone) {
if (!CAL.validateTimeZone(timezone)) {
if (raiseParseDataError) {
throw new AsterixTemporalTypeParseException("Invalid time zone");
} else {
return false;
}
}
chronon += timezone;
}
outChronon.setValue(chronon);
if (dateTimeSeparatorOut != null) {
dateTimeSeparatorOut.setValue(dateTimeSeparatorChar);
}
if (outTimeZoneExists != null) {
outTimeZoneExists.setValue(timezoneExists);
}
if (outTimeZone != null) {
outTimeZone.setValue(timezone);
}
return true;
}