/* * Copyright 2003 Federal Chancellery Austria * MOA-ID has been developed in a cooperation between BRZ, the Federal * Chancellery Austria - ICT staff unit, and Graz University of Technology. * * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * http://www.osor.eu/eupl/ * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. */ package at.gv.egovernment.moaspss.util; import java.io.StringWriter; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; /** * Utility for parsing and building XML type dateTime, * according to ISO 8601. * * @author Patrick Peck * @version $Id$ * @see http://www.w3.org/2001/XMLSchema-datatypes" */ public class DateTimeUtils { /** Error messages. */ private static MessageProvider msg = MessageProvider.getInstance(); // /** // * Builds a dateTime value from a Calendar value. // * @param cal the Calendar value // * @return the dateTime value // */ // public static String buildDateTime(Calendar cal, boolean useUTC) { // // if (useUTC) // return buildDateTimeUTC(cal); // else { // StringWriter out = new StringWriter(); // out.write("" + cal.get(Calendar.YEAR)); // out.write("-"); // out.write(to2DigitString(cal.get(Calendar.MONTH) + 1)); // out.write("-"); // out.write(to2DigitString(cal.get(Calendar.DAY_OF_MONTH))); // out.write("T"); // out.write(to2DigitString(cal.get(Calendar.HOUR_OF_DAY))); // out.write(":"); // out.write(to2DigitString(cal.get(Calendar.MINUTE))); // out.write(":"); // out.write(to2DigitString(cal.get(Calendar.SECOND))); // int tzOffsetMilliseconds = // cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET); // if (tzOffsetMilliseconds != 0) { // int tzOffsetMinutes = tzOffsetMilliseconds / (1000 * 60); // int tzOffsetHours = tzOffsetMinutes / 60; // tzOffsetMinutes -= tzOffsetHours * 60; // if (tzOffsetMilliseconds > 0) { // out.write("+"); // out.write(to2DigitString(tzOffsetHours)); // out.write(":"); // out.write(to2DigitString(tzOffsetMinutes)); // } else { // out.write("-"); // out.write(to2DigitString(-tzOffsetHours)); // out.write(":"); // out.write(to2DigitString(-tzOffsetMinutes)); // } // } // return out.toString(); // } // } /** * Builds a dateTime value in UTC from a Calendar value. * @param cal the Calendar value * @return the dateTime value */ public static String buildDateTimeUTC(Calendar cal) { SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); f.setTimeZone(TimeZone.getTimeZone("UTC")); return f.format(cal.getTime()); } /** * Builds a dateTime value in UTC from a Calendar value. * @param cal the Calendar value * @return the dateTime value */ public static String buildDateTimeUTC(Date cal) { SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); f.setTimeZone(TimeZone.getTimeZone("UTC")); return f.format(cal); } /** * Builds a dateTime value from a Calendar value. * @param cal the Calendar value * @return the dateTime value */ public static String buildDate(Calendar cal) { StringWriter out = new StringWriter(); out.write("" + cal.get(Calendar.YEAR)); out.write("-"); out.write(to2DigitString(cal.get(Calendar.MONTH) + 1)); out.write("-"); out.write(to2DigitString(cal.get(Calendar.DAY_OF_MONTH))); return out.toString(); } /** * Builds a dateTime value from a Calendar value. * @param cal the Calendar value * @return the dateTime value */ public static String buildTime(Calendar cal) { StringWriter out = new StringWriter(); out.write(to2DigitString(cal.get(Calendar.HOUR_OF_DAY))); out.write(":"); out.write(to2DigitString(cal.get(Calendar.MINUTE))); out.write(":"); out.write(to2DigitString(cal.get(Calendar.SECOND))); return out.toString(); } /** * Converts month, day, hour, minute, or second value * to a 2 digit String. * @param number the month, day, hour, minute, or second value * @return 2 digit String */ private static String to2DigitString(int number) { if (number < 10) return "0" + number; else return "" + number; } /** * Parse a String containing a date and time instant, given in * ISO 8601 format. * * @param dateTime The String to parse. * @return The Date representation of the contents of * dateTime. * @throws ParseException Parsing the dateTime failed. */ public static Date parseDateTime(String dateTime) throws ParseException { GregorianCalendar calendar; long time; int yearSign = 1, year, month, day; int hour, minute, second; double fraction = 0.0; int tzSign = 1, tzHour = 0, tzMinute = 0; int curPos = 0; String fractStr; boolean localTime = false; char c; // parse year sign ensureChars(dateTime, curPos, 1); c = dateTime.charAt(curPos); if (c == '+' || c == '-') { yearSign = c == '+' ? 1 : -1; curPos++; } // parse year year = parseInt(dateTime, curPos, 4); curPos += 4; // parse '-' ensureChar(dateTime, curPos, '-'); curPos++; // parse month month = parseInt(dateTime, curPos, 2); ensureValue(month, 1, 12, curPos); curPos += 2; // parse '-' ensureChar(dateTime, curPos, '-'); curPos++; // parse day day = parseInt(dateTime, curPos, 2); ensureValue(day, 1, 31, curPos); curPos += 2; // parse 'T' ensureChar(dateTime, curPos, 'T'); curPos++; // parse hour hour = parseInt(dateTime, curPos, 2); ensureValue(hour, 0, 23, curPos); curPos += 2; // parse ':' ensureChar(dateTime, curPos, ':'); curPos++; // parse minute minute = parseInt(dateTime, curPos, 2); ensureValue(minute, 0, 59, curPos); curPos += 2; // parse ':' ensureChar(dateTime, curPos, ':'); curPos++; // parse second second = parseInt(dateTime, curPos, 2); ensureValue(second, 0, 59, curPos); curPos += 2; // parse a fraction if (dateTime.length() > curPos && dateTime.charAt(curPos) == '.') { curPos++; ensureDigits(dateTime, curPos, 1); fractStr = "0."; fractStr += dateTime.substring(curPos, curPos + countDigits(dateTime, curPos)); fraction = Double.parseDouble(fractStr); curPos += countDigits(dateTime, curPos); } // parse a time zone if (dateTime.length() > curPos) { c = dateTime.charAt(curPos); if (c == 'Z') { curPos++; } else if (c == '+' || c == '-') { // parse time zone sign tzSign = c == '+' ? 1 : -1; curPos++; // parse time zone hour tzHour = parseInt(dateTime, curPos, 2); ensureValue(tzHour, 0, 14, curPos); curPos += 2; // parse ':' ensureChar(dateTime, curPos, ':'); curPos++; // parse time zone minute tzMinute = parseInt(dateTime, curPos, 2); ensureValue(tzMinute, 0, 59, curPos); curPos += 2; } } else { localTime = true; } // if we have characters left, it's an error if (dateTime.length() != curPos) { throw new ParseException(msg.getMessage("datetime.00", null), curPos); } // build the Date object year = year * yearSign; try { calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT")); calendar.set(year, month - 1, day, hour, minute, second); calendar.set(Calendar.MILLISECOND, 0); time = calendar.getTime().getTime(); time += (long) (fraction * 1000.0); time -= tzSign * ((tzHour * 60) + tzMinute) * 60 * 1000; if (localTime) { time -= TimeZone.getDefault().getRawOffset(); } return new Date(time); } catch (IllegalArgumentException e) { throw new ParseException(msg.getMessage("datetime.00", null), curPos); } } /** * Parse an integer value. * * @param str The String containing the digits. * @param curPos The starting position. * @param digits The number of digist making up the integer value. * @return int The integer representation of the digits contained in * str. * @throws ParseException Parsing the integer value failed. */ private static int parseInt(String str, int curPos, int digits) throws ParseException { ensureDigits(str, curPos, digits); return Integer.parseInt(str.substring(curPos, curPos + digits)); } /** * Count the number of digits following curPos. * * @param str The String in which to count digits. * @param curPos The starting position. * @return int The number of digits. */ private static int countDigits(String str, int curPos) { int i; for (i = curPos; i < str.length() && Character.isDigit(str.charAt(i)); i++); return i - curPos; } /** * Ensure that a value falls in a given min/max range. * * @param value The value to check. * @param min The minimum allowed value. * @param max The maximum allowed value. * @param curPos To indicate the parsing position in the * ParseException. * @throws ParseException Thrown, if value < min || value > * max */ private static void ensureValue(int value, int min, int max, int curPos) throws ParseException { if (value < min || value > max) { throw new ParseException(msg.getMessage("datetime.00", null), curPos); } } /** * Ensure that the given String has a number of characters left. * * @param str The String to check for its length. * @param curPos The starting position. * @param count The minimum number of characters that str must * contain, starting at from curPos. * @throws ParseException Thrown, if * curPos + count > str.length(). */ private static void ensureChars(String str, int curPos, int count) throws ParseException { if (curPos + count > str.length()) { throw new ParseException(msg.getMessage("datetime.00", null), curPos); } } /** * Ensure that a given String contains a certain character at a * certain position. * * @param str The String in which to look up the character. * @param curPos The position in str that must contain the * character. * @param c The character value that must be contained at position * curPos. * @throws ParseException Thrown, if the characters do not match or * curPos is out of range. */ private static void ensureChar(String str, int curPos, char c) throws ParseException { ensureChars(str, curPos, 1); if (str.charAt(curPos) != c) { throw new ParseException(msg.getMessage("datetime.00", null), curPos); } } /** * Ensure that a given String contains a number of digits, * starting at a given position. * * @param str The String to scan for digits. * @param curPos The starting postion. * @param count The number of digits that must be contained in * str, starting at curPos. * @throws ParseException Thrown, if str is not long enough, or * one of the characters following curPos in str is * not a digit. */ private static void ensureDigits(String str, int curPos, int count) throws ParseException { ensureChars(str, curPos, count); for (int i = curPos; i < curPos + count; i++) { if (!Character.isDigit(str.charAt(i))) { throw new ParseException(msg.getMessage("datetime.00", null), curPos); } } } /** * Calculates the age if date of birth is given (for a calendar time stamp) * @param dateOfBirth Date of Birth * @param now Calendar time stamp at which the age needs to be calculated for * @return Age of a person */ public static int calcAge(Calendar dateOfBirth, Calendar now) { int age = now.get(Calendar.YEAR) - dateOfBirth.get(Calendar.YEAR); int nowM = now.get(Calendar.MONTH); int dobM = dateOfBirth.get(Calendar.MONTH); int nowDOM = now.get(Calendar.DAY_OF_MONTH); int dobDOM = dateOfBirth.get(Calendar.DAY_OF_MONTH); if ((nowM < dobM) || ((nowM == dobM) && (nowDOM < dobDOM))) { age--; } if (age < 0) { throw new IllegalArgumentException("Calculated age results in negative value."); } return age; } /** * Calculates the age if date of birth is given as Calendar object * @param dateOfBirth Date of Birth as Calendar object * @return Age of a person */ public static int calcAge(Calendar dateOfBirth) { return calcAge(dateOfBirth, Calendar.getInstance()); } /** * Calculates the age if date of birth is given (for a date time stamp) * @param dateOfBirth Date of Birth * @param now Date time stamp at which the age needs to be calculated for * @return Age of a person */ public static int calcAge(Date dateOfBirth, Date now) { Calendar dob = Calendar.getInstance(); dob.setTime(dateOfBirth); Calendar nowCal = Calendar.getInstance(); nowCal.setTime(now); return calcAge(dob, nowCal); } /** * Calculates the age if date of birth is given as Date object * @param dateOfBirth Date of Birth as Date object * @return Age of a person */ public static int calcAge(Date dateOfBirth) { return calcAge(dateOfBirth, new Date()); } public static String formatPEPSDateToMOADate(String pepsDate) { if (StringUtils.isEmpty(pepsDate)) { return null; } DateTimeFormatter fmt = null; switch (pepsDate.length()) { case 4: fmt = DateTimeFormat.forPattern("yyyy"); break; case 6: fmt = DateTimeFormat.forPattern("yyyyMM"); break; case 8: fmt = DateTimeFormat.forPattern("yyyyMMdd"); break; default: fmt = DateTimeFormat.forPattern("yyyy-MM-dd"); break; } DateTime dt = fmt.parseDateTime(pepsDate); DateTimeFormatter fmt2 = DateTimeFormat.forPattern("yyyy-MM-dd"); return fmt2.print(dt); } /** * Returns a date as String using a provided format * @param format Format the date/time should be returned * @return Date/Time as String formatted according the provided format */ public static String getDateTimeWithFormat(String format) { DateFormat dateFormat = new SimpleDateFormat(format); Date date = new Date(); return dateFormat.format(date); } }