/* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Esri Inc. licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.esri.gpt.framework.isodate;
import com.esri.gpt.framework.util.*;
import java.io.IOException;
import java.text.ParseException;
import java.util.Calendar;
import java.util.TimeZone;
/**
* ISO Date and Time parser.
*/
class IsoDateTimeParser {
private IsoDateContext isoDateContext = new IsoDateContext();
public int getIndex() {
return isoDateContext.getIndex();
}
/**
* Parses date and time.
* @param strDateTime date and time to parse
* @return calendar
* @throws ParseException if unable to parse given date and time
*/
public Calendar parse(String strDateTime) throws ParseException {
isoDateContext = new IsoDateContext();
strDateTime = Val.chkStr(strDateTime);
Calendar cal = Calendar.getInstance();
cal.clear();
IsoDateInputStream input = new IsoDateInputStream(strDateTime, isoDateContext);
IsoDateReader r = new IsoDateReader(input);
try {
// read year
String year = "";
int nSign = 1;
if (r.peek(1).matches("[+-]")) {
nSign = r.read(1).equals("+")? 1: -1;
year = r.read(5);
if (year.length()!=5) throw new ParseException(strDateTime,getIndex());
} else {
year = r.read(2);
if (year.length()!=2) throw new ParseException(strDateTime,getIndex());
if (r.peek(2).length()==2 && !r.peek(1).toUpperCase().equals("T")) {
year += r.read(2);
}
}
if (year.length()==2) {
// if length is exactly 2, the date is a century
cal.set(Calendar.YEAR, 100*Integer.parseInt(year));
} else if (year.length()==4) {
// year has exactly 4 characters
cal.set(Calendar.YEAR, Integer.parseInt(year));
} else if (year.length()==5) {
// year has exactly 5 characters; use sign also
cal.set(Calendar.YEAR, nSign*Integer.parseInt(year));
} else {
throw new ParseException(strDateTime,getIndex());
}
// read month, week, day
String month = "";
String week = "";
String day = "";
if (r.hasMore()) {
if (r.peek(1).toUpperCase().equals("W")) {
r.read(1);
week = r.read(2);
cal.set(Calendar.WEEK_OF_YEAR, Integer.parseInt(week));
if (!r.peek(1).toUpperCase().equals("T") && r.peek(1).length()==1) {
day = r.read(1);
cal.set(Calendar.DAY_OF_WEEK_IN_MONTH, Integer.parseInt(day));
}
} else if (!r.peek(1).toUpperCase().equals("T")) {
if (r.peek(4).length()==4 && !r.peek(4).toUpperCase().contains("T")) {
month = r.read(2);
day = r.read(2);
cal.set(Calendar.MONTH, Integer.parseInt(month)-1);
cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day));
} else if (r.peek(3).length()==3 && !r.peek(3).toUpperCase().contains("T")) {
week = r.read(3);
cal.set(Calendar.DAY_OF_YEAR, Integer.parseInt(week));
} else if (r.peek(2).length()==2 && !r.peek(2).toUpperCase().contains("T")) {
month = r.read(2);
cal.set(Calendar.MONTH, Integer.parseInt(month)-1);
} else {
throw new ParseException(strDateTime,getIndex());
}
}
}
if (r.peek(1).toUpperCase().equals("T")) {
r.read(1);
TimeZoneFlag timeZoneFlag = new TimeZoneFlag();
// parse time
if (r.peek(2).length()==2) {
cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(r.read(2)));
parseTimeZone(cal, timeZoneFlag, strDateTime, r);
}
if (r.peek(2).length()==2) {
cal.set(Calendar.MINUTE, Integer.parseInt(r.read(2)));
parseTimeZone(cal, timeZoneFlag, strDateTime, r);
}
if (r.peek(2).length()==2) {
cal.set(Calendar.SECOND, Integer.parseInt(r.read(2)));
parseTimeZone(cal, timeZoneFlag, strDateTime, r);
}
}
if (r.hasMore()) {
throw new ParseException(strDateTime,getIndex());
}
} catch (NumberFormatException ex) {
throw new ParseException(strDateTime, Math.max(0, getIndex()));
} catch (IOException ex) {
throw new ParseException(strDateTime, Math.max(0, getIndex()));
} finally {
try { r.close(); } catch (IOException ex) {}
try { input.close(); } catch (IOException ex) {}
}
return cal;
}
private void parseTimeZone(Calendar cal, TimeZoneFlag timeZoneFlag, String strDateTime, IsoDateReader r) throws ParseException, IOException {
r.filterOff();
if (r.peek(1).toUpperCase().equals("Z")) {
r.filterOn();
r.read(1);
if (timeZoneFlag.flag) throw new ParseException(strDateTime, Math.max(0, getIndex()));
TimeZone tz = TimeZone.getTimeZone("GMT 00:00");
cal.setTimeZone(tz);
timeZoneFlag.flag = true;
} else if (r.peek(1).matches("[+-]")) {
r.filterOn();
if (r.peek(4).length()==4) {
String strTimeShift = r.read(4);
if (timeZoneFlag.flag) throw new ParseException(strDateTime, Math.max(0, getIndex()));
TimeZone tz = TimeZone.getTimeZone("GMT "+strTimeShift.substring(0, 2)+":"+strTimeShift.substring(2,4));
cal.setTimeZone(tz);
timeZoneFlag.flag = true;
} else if (r.peek(2).length()==2) {
String strTimeShift = r.read(2);
if (timeZoneFlag.flag) throw new ParseException(strDateTime, Math.max(0, getIndex()));
TimeZone tz = TimeZone.getTimeZone("GMT "+strTimeShift+":00");
cal.setTimeZone(tz);
timeZoneFlag.flag = true;
}
}
r.filterOn();
}
private static class TimeZoneFlag {
public boolean flag;
}
}