/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2008, Open Source Geospatial Foundation (OSGeo)
* (C) 2009-2010, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.temporal.object;
import java.util.Map;
import java.util.List;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.measure.Unit;
import org.apache.sis.measure.Units;
import org.apache.sis.util.iso.SimpleInternationalString;
import org.geotoolkit.temporal.reference.DefaultTemporalCoordinateSystem;
import org.geotoolkit.util.StringUtilities;
import org.geotoolkit.util.collection.UnSynchronizedCache;
import org.apache.sis.util.logging.Logging;
import org.opengis.temporal.CalendarDate;
import org.opengis.temporal.DateAndTime;
import org.opengis.temporal.Duration;
import org.opengis.temporal.JulianDate;
import org.opengis.temporal.OrdinalEra;
import org.opengis.temporal.OrdinalPosition;
import org.opengis.temporal.TemporalCoordinate;
import org.opengis.temporal.TemporalReferenceSystem;
import static org.geotoolkit.temporal.object.TemporalConstants.*;
/**
* This is a tool class to convert DateTime from ISO8601 to Date object.
*
* @author Mehdi Sidhoum (Geomatys)
* @module
*/
public final class TemporalUtilities {
private static final Logger LOGGER = Logging
.getLogger("org.geotoolkit.temporal.object");
private static final String DEFAULT_TIMEZONE = TimeZone.getDefault()
.getID();
/**
* The units for months.
*
* @todo <a href="http://kenai.com/jira/browse/JSR_275-41">JSR-275 bug</a>
*/
public static final Unit<javax.measure.quantity.Time> MONTH_UNIT = Units.DAY
.multiply(MONTH_MS / DAY_MS);
/**
* The units for years.
*
* @todo <a href="http://kenai.com/jira/browse/JSR_275-41">JSR-275 bug</a>
*/
public static final Unit<javax.measure.quantity.Time> YEAR_UNIT = Units.DAY
.multiply(YEAR_MS / DAY_MS);
/**
* Hack for french datas, must find another way to do so. handle all local ?
* impossible handle the current local ? If the server has a different local
* then the client ? won't work
*/
private static final List<String> FR_POOL = new ArrayList<String>() {
@Override
public int indexOf(Object o) {
final String candidate = (String) o;
for (int i = 0, n = FR_POOL.size(); i < n; i++) {
if (FR_POOL.get(i).equalsIgnoreCase(candidate)) {
return i;
}
}
return -1;
}
};
/**
* Caution : those objects are not thread safe, take care to synchronize
* when you use them.
*/
private static final SimpleDateFormat sdf1 = new java.text.SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZ");
private static final SimpleDateFormat sdf2 = new java.text.SimpleDateFormat(
"yyyy-MM-dd");
static {
// we don't hour here so we put the timeZone to GMT+0
// 02/04/2012 why GMT+0 ? adding additional dateFormat sdf6
sdf2.setTimeZone(TimeZone.getTimeZone("GMT+0"));
}
private static final SimpleDateFormat sdf3 = new java.text.SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss.SSSZ");
private static final SimpleDateFormat sdf4 = new java.text.SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss");
private static final SimpleDateFormat sdf5 = new java.text.SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZ");
private static final SimpleDateFormat sdf6 = new java.text.SimpleDateFormat(
"yyyy-MM-dd");
private static final SimpleDateFormat sdf7 = new java.text.SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss'Z'");
static {
sdf6.setTimeZone(TimeZone.getDefault());
}
private static final Map<String, TimeZone> TIME_ZONES = new UnSynchronizedCache<String, TimeZone>(
50) {
@Override
public TimeZone get(Object o) {
@SuppressWarnings("element-type-mismatch")
TimeZone tz = super.get(o);
if (tz == null) {
tz = TimeZone.getTimeZone((String) o);
put((String) o, tz);
}
return tz;
}
};
static {
FR_POOL.add("janvier");
FR_POOL.add("février");
FR_POOL.add("mars");
FR_POOL.add("avril");
FR_POOL.add("mai");
FR_POOL.add("juin");
FR_POOL.add("juillet");
FR_POOL.add("août");
FR_POOL.add("septembre");
FR_POOL.add("octobre");
FR_POOL.add("novembre");
FR_POOL.add("décembre");
}
private TemporalUtilities() {
}
/**
* Returns a Date object from an ISO-8601 representation string. (String
* defined with pattern yyyy-MM-dd'T'HH:mm:ss.SSSZ or yyyy-MM-dd).
*
* @param dateString
*
* @return Date result of parsing the given string
* @throws ParseException
*/
public static Date getDateFromString(final String dateString) throws ParseException {
return getDateFromString(dateString, false);
}
/**
* Returns a Date object from an ISO-8601 representation string. (String
* defined with pattern yyyy-MM-dd'T'HH:mm:ss.SSSZ or yyyy-MM-dd).
*
* @param dateString
* @param noGMTO
* : will use date parser with default timezone for input with no time
* (dd-MM-yyyy) instead of GMT+0.
* @return Date result of parsing the given string
* @throws ParseException
*/
public static Date getDateFromString(String dateString, final boolean noGMTO)
throws ParseException {
boolean defaultTimezone = false;
final int indexT = dateString.indexOf('T');
if (indexT > 0) {
int tzIndex = dateString.lastIndexOf('+');
if (tzIndex == -1) {
tzIndex = dateString.lastIndexOf('-');
}
if (tzIndex > indexT) {
String timezoneStr = dateString.substring(tzIndex + 1);
if (timezoneStr.indexOf(':') > 0) {
// e.g : 1985-04-12T10:15:30+04:00
timezoneStr = timezoneStr.replace(":", "");
dateString = dateString.substring(0, tzIndex + 1).concat(
timezoneStr);
} else if (timezoneStr.length() == 2) {
// e.g : 1985-04-12T10:15:30-04
dateString = dateString.concat("00");
}
} else if (dateString.charAt(dateString.length() - 1) == 'Z') {
// e.g : 1985-04-12T10:15:30Z
dateString = dateString.substring(0, dateString.length() - 1)
.concat("+0000");
} else {
// e.g : 1985-04-12T10:15:30
defaultTimezone = true;
}
if (dateString.indexOf('.') > 0) {
// simple date format is not thread safe
synchronized (sdf3) {
return sdf3.parse(dateString);
}
}
if (defaultTimezone) {
// applying default timezone
// simple date format is not thread safe
synchronized (sdf4) {
return sdf4.parse(dateString);
}
} else {
final String timezone = getTimeZone(dateString);
// simple date format is not thread safe
synchronized (sdf1) {
sdf1.setTimeZone(TIME_ZONES.get(timezone));
return sdf1.parse(dateString);
}
}
} else if (dateString.indexOf('-') > 0) {
// simple date format is not thread safe
if (noGMTO) {
synchronized (sdf6) {
return sdf6.parse(dateString);
}
} else {
synchronized (sdf2) {
return sdf2.parse(dateString);
}
}
}
throw new ParseException("Unable to parse given string as a date with regular date formats", 0);
}
public static String getTimeZone(final String dateString) {
if (dateString.charAt(dateString.length() - 1) == 'Z') {
return "GMT+0";
}
int index = dateString.lastIndexOf('+');
if (index == -1) {
index = dateString.lastIndexOf('-');
}
if (index > dateString.indexOf('T')) {
return "GMT" + dateString.substring(index);
}
return DEFAULT_TIMEZONE;
}
/**
* Return a Date (long time) from a String description
*
* @param periodDuration
* @return duration in millisenconds represented by this string duration.
*/
public static long getTimeInMillis(String periodDuration) {
long time = 0;
if(periodDuration.startsWith("P")){
// we remove the 'P'
periodDuration = periodDuration.substring(1);
// we look if the period contains years (31536000000 ms)
if (periodDuration.indexOf('Y') != -1) {
final int nbYear = Integer.parseInt(periodDuration.substring(0,
periodDuration.indexOf('Y')));
time += nbYear * YEAR_MS;
periodDuration = periodDuration.substring(periodDuration
.indexOf('Y') + 1);
}
// we look if the period contains months (2628000000 ms)
if (periodDuration.indexOf('M') != -1
&& (periodDuration.indexOf('T') == -1 || periodDuration
.indexOf('T') > periodDuration.indexOf('M'))) {
final int nbMonth = Integer.parseInt(periodDuration.substring(0,
periodDuration.indexOf('M')));
time += nbMonth * MONTH_MS;
periodDuration = periodDuration.substring(periodDuration
.indexOf('M') + 1);
}
// we look if the period contains weeks (604800000 ms)
if (periodDuration.indexOf('W') != -1) {
final int nbWeek = Integer.parseInt(periodDuration.substring(0,
periodDuration.indexOf('W')));
time += nbWeek * WEEK_MS;
periodDuration = periodDuration.substring(periodDuration
.indexOf('W') + 1);
}
// we look if the period contains days (86400000 ms)
if (periodDuration.indexOf('D') != -1) {
final int nbDay = Integer.parseInt(periodDuration.substring(0,
periodDuration.indexOf('D')));
time += nbDay * DAY_MS;
periodDuration = periodDuration.substring(periodDuration
.indexOf('D') + 1);
}
// if the periodDuration is not over we pass to the hours by removing
// 'T'
if (periodDuration.indexOf('T') != -1) {
periodDuration = periodDuration.substring(1);
}
// we look if the period contains hours (3600000 ms)
if (periodDuration.indexOf('H') != -1) {
final int nbHour = Integer.parseInt(periodDuration.substring(0,
periodDuration.indexOf('H')));
time += nbHour * HOUR_MS;
periodDuration = periodDuration.substring(periodDuration
.indexOf('H') + 1);
}
// we look if the period contains minutes (60000 ms)
if (periodDuration.indexOf('M') != -1) {
final int nbMin = Integer.parseInt(periodDuration.substring(0,
periodDuration.indexOf('M')));
time += nbMin * MINUTE_MS;
periodDuration = periodDuration.substring(periodDuration
.indexOf('M') + 1);
}
// we look if the period contains seconds (1000 ms)
if (periodDuration.indexOf('S') != -1) {
final int nbSec = Integer.parseInt(periodDuration.substring(0,
periodDuration.indexOf('S')));
time += nbSec * SECOND_MS;
periodDuration = periodDuration.substring(periodDuration
.indexOf('S') + 1);
}
if (periodDuration.length() != 0) {
throw new IllegalArgumentException(
"The period descritpion is malformed");
}
}else if(periodDuration.startsWith("T")){
// we remove the 'T'
periodDuration = periodDuration.substring(1);
// we look if the period contains hours (3600000 ms)
if (periodDuration.indexOf('H') != -1) {
final int nbHour = Integer.parseInt(periodDuration.substring(0,
periodDuration.indexOf('H')));
time += nbHour * HOUR_MS;
periodDuration = periodDuration.substring(periodDuration
.indexOf('H') + 1);
}
// we look if the period contains minutes (60000 ms)
if (periodDuration.indexOf('M') != -1) {
final int nbMin = Integer.parseInt(periodDuration.substring(0,
periodDuration.indexOf('M')));
time += nbMin * MINUTE_MS;
periodDuration = periodDuration.substring(periodDuration
.indexOf('M') + 1);
}
// we look if the period contains seconds (1000 ms)
if (periodDuration.indexOf('S') != -1) {
final int nbSec = Integer.parseInt(periodDuration.substring(0,
periodDuration.indexOf('S')));
time += nbSec * SECOND_MS;
periodDuration = periodDuration.substring(periodDuration
.indexOf('S') + 1);
}
if (periodDuration.length() != 0) {
throw new IllegalArgumentException(
"The period descritpion is malformed");
}
}
return time;
}
/**
* Returns a DefaultPeriodDuration instance parsed from a string that
* respect ISO8601 format ie: PnYnMnDTnHnMnS where n is an integer
*
* @TODO maybe should check by Pattern of string before and should throw an
* exception when it is bad format
*
* @param periodDuration
* @return duration in millisenconds represented by this string duration.
*/
public static Duration getDurationFromString(String periodDuration) {
if (periodDuration == null) {
return null;
}
String nbYear = null, nbMonth = null, nbWeek = null, nbDay = null, nbHour = null, nbMin = null, nbSec = null;
// remove first char 'P'
periodDuration = periodDuration.substring(1);
// looking for the period years
if (periodDuration.indexOf('Y') != -1) {
nbYear = periodDuration.substring(0, periodDuration.indexOf('Y'));
periodDuration = periodDuration.substring(periodDuration
.indexOf('Y') + 1);
}
// looking for the period months
if (periodDuration.indexOf('M') != -1
&& (periodDuration.indexOf('T') == -1 || periodDuration
.indexOf('T') > periodDuration.indexOf('M'))) {
nbMonth = periodDuration.substring(0, periodDuration.indexOf('M'));
periodDuration = periodDuration.substring(periodDuration
.indexOf('M') + 1);
}
// looking for the period weeks
if (periodDuration.indexOf('W') != -1) {
nbWeek = periodDuration.substring(0, periodDuration.indexOf('W'));
periodDuration = periodDuration.substring(periodDuration
.indexOf('W') + 1);
}
// looking for the period days
if (periodDuration.indexOf('D') != -1) {
nbDay = periodDuration.substring(0, periodDuration.indexOf('D'));
periodDuration = periodDuration.substring(periodDuration
.indexOf('D') + 1);
}
// if the periodDuration is not over we pass to the hours by removing
// 'T'
if (periodDuration.indexOf('T') != -1) {
periodDuration = periodDuration.substring(1);
}
// looking for the period hours
if (periodDuration.indexOf('H') != -1) {
nbHour = periodDuration.substring(0, periodDuration.indexOf('H'));
periodDuration = periodDuration.substring(periodDuration
.indexOf('H') + 1);
}
// looking for the period minutes
if (periodDuration.indexOf('M') != -1) {
nbMin = periodDuration.substring(0, periodDuration.indexOf('M'));
periodDuration = periodDuration.substring(periodDuration
.indexOf('M') + 1);
}
// looking for the period seconds
if (periodDuration.indexOf('S') != -1) {
nbSec = periodDuration.substring(0, periodDuration.indexOf('S'));
periodDuration = periodDuration.substring(periodDuration
.indexOf('S') + 1);
}
if (periodDuration.length() != 0) {
throw new IllegalArgumentException(
"The period descritpion is malformed, should not respect ISO8601 : "
+ periodDuration);
}
return new DefaultPeriodDuration(
nbYear!=null?new SimpleInternationalString(nbYear):null,
nbMonth!=null?new SimpleInternationalString(nbMonth):null,
nbWeek!=null?new SimpleInternationalString(nbWeek):null,
nbDay!=null?new SimpleInternationalString(nbDay):null,
nbHour!=null?new SimpleInternationalString(nbHour):null,
nbMin!=null?new SimpleInternationalString(nbMin):null,
nbSec!=null?new SimpleInternationalString(nbSec):null);
}
/**
* Convert a JulianDate to Date
*/
public static Date julianToDate(final JulianDate jdt) {
if (jdt == null) {
return null;
}
final int gregDays = 15 + 31 * (10 + 12 * 1582);
int jalpha, ja, jb, jc, jd, je, year, month, day;
ja = jdt.getCoordinateValue().intValue();
if (ja >= gregDays) {
jalpha = (int) (((ja - 1867216) - 0.25) / 36524.25);
ja = ja + 1 + jalpha - jalpha / 4;
}
jb = ja + 1524;
jc = (int) (6680.0 + ((jb - 2439870) - 122.1) / 365.25);
jd = 365 * jc + jc / 4;
je = (int) ((jb - jd) / 30.6001);
day = jb - jd - (int) (30.6001 * je);
month = je - 1;
if (month > 12) {
month = month - 12;
}
year = jc - 4715;
if (month > 2) {
year--;
}
if (year <= 0) {
year--;
}
return new Date(year * YEAR_MS + month * MONTH_MS + day * DAY_MS);
}
/**
* Convert a CalendarDate object to java.util.Date.
*
* @param calDate
*/
public static Date calendarDateToDate(final CalendarDate calDate) {
if (calDate == null) {
return null;
}
final int[] cal = calDate.getCalendarDate();
if (cal.length > 3)
throw new IllegalArgumentException(
"The CalendarDate integer array is malformed ! see ISO 8601 format.");
return new Date((cal.length > 0 ? cal[0] : 0) * YEAR_MS
+ (cal.length > 1 ? cal[1] : 0) * MONTH_MS
+ (cal.length > 2 ? cal[2] : 0) * DAY_MS);
}
/**
* Convert a DateAndTime object to Date.
*
* @param dateAndTime
* @return converted DateAndTime in Date
*/
public static Date dateAndTimeToDate(final DateAndTime dateAndTime) {
if (dateAndTime == null && !(dateAndTime instanceof DefaultDateAndTime)) {
return null;
}
final DefaultDateAndTime dateTime = (DefaultDateAndTime) dateAndTime;
final int[] cal = dateTime.getCalendarDate();
final Number[] clock = dateTime.getClockTime();
if (cal.length > 3)
throw new IllegalArgumentException(
"The CalendarDate integer array is malformed ! see ISO 8601 format.");
if (clock.length > 3)
throw new IllegalArgumentException(
"The ClockTime Number array is malformed ! see ISO 8601 format.");
return new Date((cal.length > 0 ? cal[0] : 0) * YEAR_MS
+ (cal.length > 1 ? cal[1] : 0) * MONTH_MS
+ (cal.length > 2 ? cal[2] : 0) * DAY_MS
+ (clock.length > 0 ? clock[0].intValue() : 0) * HOUR_MS
+ (clock.length > 1 ? clock[1].intValue() : 0) * MINUTE_MS
+ (clock.length > 2 ? clock[2].intValue() : 0) * SECOND_MS);
}
/**
* Convert a TemporalCoordinate object to Date.
*
* @param temporalCoord
* @return Date
*/
public static Date temporalCoordToDate(
final TemporalCoordinate temporalCoord) {
if (temporalCoord == null) {
return null;
}
final DefaultTemporalCoordinate timeCoord;
if (temporalCoord instanceof DefaultTemporalCoordinate) {
timeCoord = (DefaultTemporalCoordinate) temporalCoord;
} else {
throw new IllegalArgumentException(
"Can not convert a temporal coordinate which is not a DefaultTemporalCoordinate.");
}
final long value = timeCoord.getCoordinateValue().longValue();
final TemporalReferenceSystem frame = timeCoord.getFrame();
if (frame instanceof DefaultTemporalCoordinateSystem) {
final DefaultTemporalCoordinateSystem coordSystem = (DefaultTemporalCoordinateSystem) frame;
final Date origin = coordSystem.getOrigin();
final String interval = coordSystem.getInterval().toString();
long timeInMS = 0L;
if (YEAR_STR.equals(interval)) {
timeInMS = value * YEAR_MS;
} else if (MONTH_STR.equals(interval)) {
timeInMS = value * MONTH_MS;
} else if (WEEK_STR.equals(interval)) {
timeInMS = value * WEEK_MS;
} else if (DAY_STR.equals(interval)) {
timeInMS = value * DAY_MS;
} else if (HOUR_STR.equals(interval)) {
timeInMS = value * HOUR_MS;
} else if (MINUTE_STR.equals(interval)) {
timeInMS = value * MINUTE_MS;
} else if (SECOND_STR.equals(interval)) {
timeInMS = value * SECOND_MS;
} else {
throw new IllegalArgumentException(
" The interval of TemporalCoordinateSystem for this TemporalCoordinate object is unknown ! ");
}
timeInMS = timeInMS + origin.getTime();
return new Date(timeInMS);
} else {
throw new IllegalArgumentException(
"The frame of this TemporalCoordinate object must be an instance of DefaultTemporalCoordinateSystem");
}
}
public static Date ordinalToDate(final OrdinalPosition ordinalPosition) {
if (ordinalPosition == null) {
return null;
}
final OrdinalEra era = ordinalPosition.getOrdinalPosition();
if (era != null) {
final Date beginEra = era.getBegin();
final Date endEra = era.getEnd();
final long middle = (endEra.getTime() + beginEra.getTime()) / 2;
return new Date(middle);
} else {
return null;
}
}
/**
* @param duration
* to evaluate
* @return the nearest Unit of a Duration.
*/
public static Unit getUnitFromDuration(final Duration duration) {
if (duration == null) {
return null;
}
final DefaultDuration dduration;
if (duration instanceof DefaultDuration) {
dduration = (DefaultDuration) duration;
} else {
throw new IllegalArgumentException(
"Can not evaluate best unit for Duration which is not a DefaultDuration.");
}
final long mills = dduration.getTimeInMillis();
long temp = mills / YEAR_MS;
if (temp > 0) {
return YEAR_UNIT;
}
temp = mills / MONTH_MS;
if (temp > 0) {
return MONTH_UNIT;
}
temp = mills / WEEK_MS;
if (temp > 0) {
return Units.WEEK;
}
temp = mills / DAY_MS;
if (temp > 0) {
return Units.DAY;
}
temp = mills / HOUR_MS;
if (temp > 0) {
return Units.HOUR;
}
temp = mills / MINUTE_MS;
if (temp > 0) {
return Units.MINUTE;
}
temp = mills / SECOND_MS;
if (temp > 0) {
return Units.SECOND;
}
return null;
}
/**
* Try to parse a date from different well knowed writing types.
* CAUTION : time zone will be local TimeZone unless the date string specify it.
*
* @param date
* String to parse
* @return resulting parsed Date.
* @throws ParseException
* if String is not valid.
* @throws NullPointerException
* if String is null.
* @deprecated use parseDateCal
*/
@Deprecated
public static Date parseDate(final String date) throws ParseException,
NullPointerException {
return parseDate(date, false);
}
/**
* Try to parse a date from different well knowed writing types.
* CAUTION : time zone will be local TimeZone unless the date string specify it.
*
* @param date
* String to parse
* @param noGMTO
* : will use date parser with default timezone for input with no time
* (dd-MM-yyyy) instead of GMT+0.
* @return resulting parsed Date.
* @throws ParseException
* if String is not valid.
* @throws NullPointerException
* if String is null.
* @deprecated use parseDateCal
*/
@Deprecated
public static Date parseDate(final String date, final boolean noGMTO) throws ParseException,
NullPointerException {
final Calendar cal = parseDateCal(date);
return cal.getTime();
}
/**
* Try to parse a date from different well knowed writing types.
* Calendar time zone will be local TimeZone unless the date string specify it.
*
* @param date
* String to parse
* @return Calendar
* @throws ParseException
* @throws NullPointerException
*/
public static Calendar parseDateCal(final String date) throws ParseException,
NullPointerException {
if (date.endsWith("BC")) {
throw new ParseException(
"Date is marked as Before Christ, not possible to parse it",
date.length());
}
final int[] slashOccurences = StringUtilities.getIndexes(date, '/');
if (slashOccurences.length == 1) {
// date is like : 11/2050
final int month = parseInt(date.substring(0, slashOccurences[0])) - 1;
final int year = parseInt(date.substring(slashOccurences[0] + 1,
date.length()));
final Calendar cal = Calendar.getInstance();
cal.set(year, month, 1, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
} else if (slashOccurences.length == 2) {
// date is like : 23/11/2050
final int day = parseInt(date.substring(0, slashOccurences[0]));
final int month = parseInt(date.substring(slashOccurences[0] + 1,
slashOccurences[1])) - 1;
final int year = parseInt(date.substring(slashOccurences[1] + 1));
final Calendar cal = Calendar.getInstance();
cal.set(year, month, day, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
}
final int[] spaceOccurences = StringUtilities.getIndexes(date, ' ');
final int[] dashOccurences = StringUtilities.getIndexes(date, '-');
final int[] dotsOccurences = StringUtilities.getIndexes(date, ':');
if(dotsOccurences.length==4 && spaceOccurences.length==1){
// date is like 2011:08:11 11:22:22
// this form has been found in geotiff datatime fields
final int year = parseInt(date.substring(0, dotsOccurences[0]));
final int month = parseInt(date.substring(dotsOccurences[0] + 1, dotsOccurences[1])) - 1;
final int day = parseInt(date.substring(dotsOccurences[1] + 1, spaceOccurences[0]));
final int hour = parseInt(date.substring(spaceOccurences[0] + 1, dotsOccurences[2]));
final int min = parseInt(date.substring(dotsOccurences[2] + 1, dotsOccurences[3]));
final int sec = parseInt(date.substring(dotsOccurences[3] + 1));
final Calendar cal = Calendar.getInstance();
cal.set(year, month, day, hour, min, sec);
cal.set(Calendar.MILLISECOND, 0);
return cal;
}else if (spaceOccurences.length == 2) {
// date is like : 18 janvier 2050
final int day = parseInt(date.substring(0, spaceOccurences[0]));
final int month = FR_POOL.indexOf(date.substring(
spaceOccurences[0] + 1, spaceOccurences[1]));
final int year = parseInt(date.substring(spaceOccurences[1] + 1));
final Calendar cal = Calendar.getInstance();
cal.set(year, month, day, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
} else if (spaceOccurences.length == 1 && dashOccurences.length < 3) {
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
df.parse(date);
return df.getCalendar();
} catch (ParseException ex) {
LOGGER.log(Level.FINE, "Could not parse date : " + date
+ " with dateFormat : " + df);
}
// date is like : Janvier 2050
final int month = FR_POOL.indexOf(date.substring(0,
spaceOccurences[0]));
final int year = parseInt(date.substring(spaceOccurences[0] + 1));
final Calendar cal = Calendar.getInstance();
cal.set(year, month, 1, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
} else if (dashOccurences.length == 1) {
if (dashOccurences[0] == 2) {
// date is like : 05-2050
final int month = parseInt(date.substring(0, dashOccurences[0])) - 1;
final int year = parseInt(date.substring(dashOccurences[0] + 1));
final Calendar cal = Calendar.getInstance();
cal.set(year, month, 1, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
} else {
// date is like : 2050-05
final int year = parseInt(date.substring(0, dashOccurences[0]));
final int month = parseInt(date
.substring(dashOccurences[0] + 1)) - 1;
final Calendar cal = Calendar.getInstance();
cal.set(year, month, 1, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
}
} else if (dashOccurences.length >= 2) {
// if date is in format yyyy-mm-ddTHH:mm:ss
try {
final ISODateParser fp = new ISODateParser();
final Calendar resultDate = fp.getCalendar(date);
if (resultDate != null) {
return resultDate;
}
} catch (NumberFormatException e) {
LOGGER.log(Level.FINE, "Could not parse date : " + date
+ " with getDateFromString method.");
}
if (dashOccurences[0] == 4) {
// date is like 2010-11-23Z
final int year = parseInt(date.substring(0, dashOccurences[0]));
final int month = parseInt(date.substring(
dashOccurences[0] + 1, dashOccurences[1])) - 1;
final int day;
if (date.endsWith("Z")) {
day = parseInt(date.substring(dashOccurences[1] + 1,
date.length() - 1));
} else {
day = parseInt(date.substring(dashOccurences[1] + 1));
}
final Calendar cal = Calendar.getInstance();
cal.set(year, month, day, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
} else {
// date is like 23-11-2010
final int day = parseInt(date.substring(0, dashOccurences[0]));
final int month = parseInt(date.substring(
dashOccurences[0] + 1, dashOccurences[1])) - 1;
final int year = parseInt(date.substring(dashOccurences[1] + 1));
final Calendar cal = Calendar.getInstance();
cal.set(year, month, day, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
}
} else if (dashOccurences.length == 0) {
// date is like 2010
final int year = parseInt(date);
final Calendar cal = Calendar.getInstance();
cal.set(year, 0, 1, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
}
throw new ParseException("Invalid date format : " + date, 0);
}
/**
* @see TemporalUtilities#parseDate(java.lang.String)
* CAUTION : time zone will be local TimeZone unless the date string specify it.
*
* @param date
* : string to parse.
* @param neverNull
* : will return today's date if parsing fail, otherwise return
* null if parsing fails.
* @return result of the parsed string or today's date or null if neverNull
* is false.
*/
public static Date parseDateSafe(final String date, final boolean neverNull) {
return parseDateSafe(date, neverNull, false);
}
/**
* @see TemporalUtilities#parseDate(java.lang.String)
* CAUTION : time zone will be local TimeZone unless the date string specify it.
*
* @param date
* : string to parse.
* @param neverNull
* : will return today's date if parsing fail, otherwise return
* null if parsing fails.
* @param noGMTO
* : will use date parser with default timezone for input with no time
* (dd-MM-yyyy) instead of GMT+0.
* @return result of the parsed string or today's date or null if neverNull
* is false.
*/
public static Date parseDateSafe(final String date, final boolean neverNull, final boolean noGMTO) {
if (date != null) {
try {
return parseDate(date, noGMTO);
} catch (ParseException ex) {
// do nothing
}
}
return (neverNull) ? new Date() : null;
}
private static int parseInt(final String candidate) throws ParseException {
try {
return Integer.parseInt(candidate);
} catch (NumberFormatException ex) {
ParseException pex = new ParseException(ex.getLocalizedMessage(), 0);
pex.initCause(ex);
throw pex;
}
}
/**
* Return a time description on the form "Ny Nm Nd Nh Nmin Ns Nms" from a
* millisecond time.
*
* @param time
* A time value in millisecond
* @return A string on the form "Xmin Ys Zms".
*/
public static String durationToString(long time) {
if (time == 0) {
return "0ms";
}
final long years = time / YEAR_MS;
time = time % YEAR_MS;
final long months = time / MONTH_MS;
time = time % MONTH_MS;
final long days = time / DAY_MS;
time = time % DAY_MS;
final long hours = time / HOUR_MS;
time = time % HOUR_MS;
final long minuts = time / MINUTE_MS;
time = time % MINUTE_MS;
final long seconds = time / SECOND_MS;
time = time % SECOND_MS;
final long millis = time;
final StringBuilder sb = new StringBuilder();
if (years > 0)
sb.append(years).append("y ");
if (months > 0)
sb.append(months).append("m ");
if (days > 0)
sb.append(days).append("d ");
if (hours > 0)
sb.append(hours).append("h ");
if (minuts > 0)
sb.append(minuts).append("min ");
if (seconds > 0)
sb.append(seconds).append("s ");
if (millis > 0)
sb.append(millis).append("ms");
final int size = sb.length();
if (sb.charAt(size - 1) == ' ') {
return sb.substring(0, size - 1);
} else {
return sb.toString();
}
}
/**
* Format date using pattern yyyy-MM-dd'T'HH:mm:ss
*
* @param date
* : date to format
* @return ISO 8601 string or empty string if date is null
*/
public static String toISO8601(final Date date) {
if (date != null) {
synchronized (sdf4) {
return sdf4.format(date);
}
}
LOGGER.log(Level.INFO,
"ISO 8601 format can not proceed because date is null.");
return "";
}
/**
* Format date with TimeZone using pattern yyyy-MM-dd'T'HH:mm:ss
*
* @param date
* : date to format
* @param timezone
* : timezone for date
* @return ISO 8601 string or empty string if date is null
*/
public static String toISO8601(final Date date, TimeZone timezone) {
if (date != null) {
synchronized (sdf5) {
if (timezone != null) {
sdf5.setTimeZone(timezone);
} else {
SimpleTimeZone tz = new SimpleTimeZone(0, "Out Timezone");
sdf5.setTimeZone(tz);
}
return sdf5.format(date);
}
}
LOGGER.log(Level.INFO,
"ISO 8601 format can not proceed because date is null.");
return "";
}
/**
* Format date with TimeZone using pattern yyyy-MM-dd'T'HH:mm:ssZ
*
* @param date
* : date to format
* @param timezone
* : timezone for date
* @return ISO 8601 string or empty string if date is null
*/
public static String toISO8601Z(final Date date, TimeZone timezone) {
if (date != null) {
synchronized (sdf7) {
if (timezone != null) {
sdf7.setTimeZone(timezone);
} else {
SimpleTimeZone tz = new SimpleTimeZone(0, "Out Timezone");
sdf7.setTimeZone(tz);
}
return sdf7.format(date);
}
}
LOGGER.log(Level.INFO,
"ISO 8601 format can not proceed because date is null.");
return "";
}
}