Java tutorial
//package com.java2s; //License from project: Apache License import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; public class Main { /** * ID to represent the 'GMT' string */ private static final String GMT_ID = "GMT"; /** * Parse a date from ISO-8601 formatted string. It expects a format * yyyy-MM-ddThh:mm:ss[.sss][Z|[+-]hh:mm] * * @param date ISO string to parse in the appropriate format. * @return the parsed date * @throws IllegalArgumentException if the date is not in the appropriate format */ public static Date parse(String date) { try { int offset = 0; // extract year int year = parseInt(date, offset, offset += 4); checkOffset(date, offset, '-'); // extract month int month = parseInt(date, offset += 1, offset += 2); checkOffset(date, offset, '-'); // extract day int day = parseInt(date, offset += 1, offset += 2); checkOffset(date, offset, 'T'); // extract hours, minutes, seconds and milliseconds int hour = parseInt(date, offset += 1, offset += 2); checkOffset(date, offset, ':'); int minutes = parseInt(date, offset += 1, offset += 2); checkOffset(date, offset, ':'); int seconds = parseInt(date, offset += 1, offset += 2); // milliseconds can be optional in the format // always use 0 otherwise returned date will include millis of current time int milliseconds = 0; if (date.charAt(offset) == '.') { checkOffset(date, offset, '.'); int digitCount = 1; while (offset + digitCount < date.length() && digitCount < 3 && date.charAt(offset + 1 + digitCount) != 'Z' && date.charAt(offset + 1 + digitCount) != '+' && date.charAt(offset + 1 + digitCount) != '-') { digitCount++; } String msString = date.substring(offset += 1, offset += digitCount); while (msString.length() < 3) { msString += '0'; } milliseconds = parseInt(msString, 0, 3); } // extract timezone String timezoneId = null; while (offset < date.length()) { char timezoneIndicator = date.charAt(offset); if (timezoneIndicator == '+' || timezoneIndicator == '-') { timezoneId = GMT_ID + date.substring(offset); break; } else if (timezoneIndicator == 'Z') { timezoneId = GMT_ID; break; } offset++; } if (timezoneId == null) { throw new IndexOutOfBoundsException("Invalid time zone indicator "); } TimeZone timezone = TimeZone.getTimeZone(timezoneId); if (!timezone.getID().equals(timezoneId)) { throw new IndexOutOfBoundsException(); } Calendar calendar = new GregorianCalendar(timezone); calendar.setLenient(false); calendar.set(Calendar.YEAR, year); calendar.set(Calendar.MONTH, month - 1); calendar.set(Calendar.DAY_OF_MONTH, day); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minutes); calendar.set(Calendar.SECOND, seconds); calendar.set(Calendar.MILLISECOND, milliseconds); return calendar.getTime(); } catch (IndexOutOfBoundsException | IllegalArgumentException e) { throw new IllegalArgumentException("Failed to parse date " + date, e); } } /** * Parse an integer located between 2 given offsets in a string * * @param value the string to parse * @param beginIndex the start index for the integer in the string * @param endIndex the end index for the integer in the string * @return the int * @throws NumberFormatException if the value is not a number */ private static int parseInt(String value, int beginIndex, int endIndex) throws NumberFormatException { if (beginIndex < 0 || endIndex > value.length() || beginIndex > endIndex) { throw new NumberFormatException(value); } // use same logic as in Integer.parseInt() but less generic we're not supporting negative values int i = beginIndex; int result = 0; int digit; if (i < endIndex) { digit = Character.digit(value.charAt(i++), 10); if (digit < 0) { throw new NumberFormatException("Invalid number: " + value); } result = -digit; } while (i < endIndex) { digit = Character.digit(value.charAt(i++), 10); if (digit < 0) { throw new NumberFormatException("Invalid number: " + value); } result *= 10; result -= digit; } return -result; } /** * Check if the expected character exist at the given offset of the * * @param value the string to check at the specified offset * @param offset the offset to look for the expected character * @param expected the expected character * @throws IndexOutOfBoundsException if the expected character is not found */ private static void checkOffset(String value, int offset, char expected) throws IndexOutOfBoundsException { char found = value.charAt(offset); if (found != expected) { throw new IndexOutOfBoundsException("Expected '" + expected + "' character but found '" + found + "'"); } } }