package com.revolsys.util; import java.math.BigDecimal; import java.math.RoundingMode; import java.sql.Timestamp; 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 java.util.regex.Matcher; import java.util.regex.Pattern; import com.revolsys.datatype.DataTypes; public interface Dates { String DATE_TIME_NANOS_PATTERN = "\\s*(\\d{4})-(\\d{2})-(\\d{2})(?:[\\sT]+(\\d{2})\\:(\\d{2})\\:(\\d{2})(?:\\.(\\d{1,9}))?)?\\s*"; static boolean equalsNotNull(final Object date1, final Object date2) { return ((Date)date1).compareTo((Date)date2) == 0; } static String format(final DateFormat format, final Date date) { return format.format(date); } static String format(final int dateStyle, final int timeStyle, final Timestamp timestamp) { final DateFormat format = DateFormat.getDateTimeInstance(dateStyle, timeStyle); return format(format, timestamp); } static String format(final String pattern) { return format(pattern, new Date(System.currentTimeMillis())); } static String format(final String pattern, final Calendar calendar) { if (calendar == null) { return null; } else { final Date date = calendar.getTime(); return format(pattern, date); } } static String format(final String pattern, final Date date) { if (date == null) { return null; } else { final DateFormat format = new SimpleDateFormat(pattern); return format(format, date); } } static Calendar getCalendar(final String dateString) { if (Property.hasValue(dateString)) { final Pattern pattern = Pattern.compile(DATE_TIME_NANOS_PATTERN); final Matcher matcher = pattern.matcher(dateString); if (matcher.find()) { final int year = getInteger(matcher, 1, 0); final int month = getInteger(matcher, 2, 0) - 1; final int day = getInteger(matcher, 3, 0); final int hour = getInteger(matcher, 4, 0); final int minute = getInteger(matcher, 5, 0); final int second = getInteger(matcher, 6, 0); int millisecond = getInteger(matcher, 7, 0); final Calendar calendar = new GregorianCalendar(year, month, day, hour, minute, second); if (millisecond != 0) { BigDecimal number = new BigDecimal("0." + millisecond); number = number.multiply(BigDecimal.valueOf(100)).setScale(0, RoundingMode.HALF_DOWN); millisecond = number.intValue(); calendar.set(Calendar.MILLISECOND, millisecond); } return calendar; } return null; } else { return null; } } static Date getDate() { return new Date(System.currentTimeMillis()); } static Date getDate(final DateFormat format, final String dateString) { if (!Property.hasValue(dateString)) { return null; } else { try { return format.parse(dateString); } catch (final ParseException e) { if (format instanceof SimpleDateFormat) { final SimpleDateFormat simpleFormat = (SimpleDateFormat)format; throw new IllegalArgumentException("Invalid date '" + dateString + "'. Must match pattern '" + simpleFormat.toPattern() + "'.", e); } else { throw new IllegalArgumentException("Invalid date '" + dateString + "'.", e); } } } } static java.util.Date getDate(final Object value) { if (value == null) { return null; } else if (value instanceof java.util.Date) { final java.util.Date date = (java.util.Date)value; return date; } else { final String string = DataTypes.toString(value); return getDate(string); } } static Date getDate(final String dateString) { if (Property.hasValue(dateString)) { final Pattern pattern = Pattern.compile(DATE_TIME_NANOS_PATTERN); final Matcher matcher = pattern.matcher(dateString); if (matcher.find()) { final int year = getInteger(matcher, 1, 0); final int month = getInteger(matcher, 2, 0) - 1; final int day = getInteger(matcher, 3, 0); final int hour = getInteger(matcher, 4, 0); final int minute = getInteger(matcher, 5, 0); final int second = getInteger(matcher, 6, 0); int millisecond = getInteger(matcher, 7, 0); final Calendar calendar = new GregorianCalendar(year, month, day, hour, minute, second); if (millisecond != 0) { BigDecimal number = new BigDecimal("0." + millisecond); number = number.multiply(BigDecimal.valueOf(1000)).setScale(0, RoundingMode.HALF_DOWN); millisecond = number.intValue(); calendar.set(Calendar.MILLISECOND, millisecond); } return calendar.getTime(); } throw new IllegalArgumentException("Value '" + dateString + "' is not a valid date-time, expecting 'yyyy-MM-dd HH:mm:ss.SSS'."); } else { return null; } } static Date getDate(final String pattern, final String dateString) { final DateFormat format = new SimpleDateFormat(pattern); return getDate(format, dateString); } static int getInteger(final Matcher matcher, final int groupIndex, final int defaultValue) { final String group = matcher.group(groupIndex); if (Property.hasValue(group)) { return Integer.parseInt(group); } else { return defaultValue; } } static Calendar getIsoCalendar(String dateString) { if (Property.hasValue(dateString)) { dateString = dateString.trim(); final int length = dateString.length(); if (length < 4) { throw new IllegalArgumentException(dateString + " is not a valid ISO 8601 date"); } else { TimeZone timeZone = TimeZone.getTimeZone("UTC"); final int year = Integer.valueOf(dateString.substring(0, 4)); int month = 0; int day = 1; int hour = 1; int minute = 1; int second = 0; int millis = 0; if (length >= 7) { month = Integer.valueOf(dateString.substring(5, 7)) - 1; if (length >= 10) { day = Integer.valueOf(dateString.substring(8, 10)); if (length >= 13) { hour = Integer.valueOf(dateString.substring(11, 13)); if (length >= 16) { minute = Integer.valueOf(dateString.substring(14, 16)); if (length >= 19) { second = Integer.valueOf(dateString.substring(17, 19)); } } if (length > 19) { int tzIndex = 19; if (dateString.charAt(tzIndex) == '.') { final int millisIndex = 20; tzIndex = 20; while (tzIndex < length && Character.isDigit(dateString.charAt(tzIndex))) { tzIndex++; } if (millisIndex != tzIndex) { final String millisString = dateString.substring(millisIndex, tzIndex); millis = Integer.valueOf(millisString); if (millisString.length() == 1) { millis = millis * 100; } else if (millisString.length() == 2) { millis = millis * 10; } } } if (tzIndex < length) { final char tzChar = dateString.charAt(tzIndex); if (tzChar == 'Z') { } else if (tzChar == '+' || tzChar == '-') { if (tzIndex + 5 < length) { final String tzString = dateString.substring(tzIndex, tzIndex + 6); timeZone = TimeZone.getTimeZone("GMT" + tzString); } } } } } } } final Calendar calendar = new GregorianCalendar(timeZone); calendar.clear(); calendar.set(Calendar.YEAR, year); calendar.set(Calendar.MONTH, month); calendar.set(Calendar.DAY_OF_MONTH, day); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minute); calendar.set(Calendar.SECOND, second); calendar.set(Calendar.MILLISECOND, millis); return calendar; } } else { return null; } } static Date getIsoDate(final String dateString) { final Calendar calendar = getIsoCalendar(dateString); return calendar.getTime(); } static java.sql.Date getIsoSqlDate(final String dateString) { final Calendar calendar = getIsoCalendar(dateString); final long time = calendar.getTimeInMillis(); return new java.sql.Date(time); } static Timestamp getIsoTimestamp(final String dateString) { final Calendar calendar = getIsoCalendar(dateString); final long time = calendar.getTimeInMillis(); return new Timestamp(time); } static java.sql.Date getSqlDate() { return new java.sql.Date(System.currentTimeMillis()); } static java.sql.Date getSqlDate(final Object value) { if (value == null) { return null; } else if (value instanceof java.sql.Date) { final java.sql.Date date = (java.sql.Date)value; return date; } else if (value instanceof Date) { final Date date = (Date)value; return new java.sql.Date(date.getTime()); } else { return getSqlDate(value.toString()); } } static java.sql.Date getSqlDate(final String dateString) { if (Property.hasValue(dateString)) { final Pattern pattern = Pattern.compile(DATE_TIME_NANOS_PATTERN); final Matcher matcher = pattern.matcher(dateString); if (matcher.find()) { final int year = getInteger(matcher, 1, 0); final int month = getInteger(matcher, 2, 0) - 1; final int day = getInteger(matcher, 3, 0); int millisecond = getInteger(matcher, 7, 0); final Calendar calendar = new GregorianCalendar(year, month, day); if (millisecond != 0) { BigDecimal number = new BigDecimal("0." + millisecond); number = number.multiply(BigDecimal.valueOf(1000)).setScale(0, RoundingMode.HALF_DOWN); millisecond = number.intValue(); calendar.set(Calendar.MILLISECOND, millisecond); } final long timeInMillis = calendar.getTimeInMillis(); return new java.sql.Date(timeInMillis); } throw new IllegalArgumentException("Value '" + dateString + "' is not a valid date-time, expecting 'yyyy-MM-dd HH:mm:ss.SSS'."); } else { return null; } } static java.sql.Date getSqlDate(final String pattern, final String dateString) { final Date date = getDate(pattern, dateString); if (date == null) { return null; } else { final long time = date.getTime(); return new java.sql.Date(time); } } static Timestamp getTimestamp() { return new Timestamp(System.currentTimeMillis()); } static Timestamp getTimestamp(final Object value) { if (value == null) { return null; } else if (value instanceof Timestamp) { final Timestamp date = (Timestamp)value; return date; } else if (value instanceof Date) { final Date date = (Date)value; return new Timestamp(date.getTime()); } else { return getTimestamp(value.toString()); } } static Timestamp getTimestamp(final String dateString) { if (Property.hasValue(dateString)) { final Pattern pattern = Pattern.compile(DATE_TIME_NANOS_PATTERN); final Matcher matcher = pattern.matcher(dateString); if (matcher.find()) { final int year = getInteger(matcher, 1, 0); final int month = getInteger(matcher, 2, 0) - 1; final int day = getInteger(matcher, 3, 0); final int hour = getInteger(matcher, 4, 0); final int minute = getInteger(matcher, 5, 0); final int second = getInteger(matcher, 6, 0); int nanoSecond = getInteger(matcher, 7, 0); final Calendar calendar = new GregorianCalendar(year, month, day, hour, minute, second); final long timeInMillis = calendar.getTimeInMillis(); final Timestamp time = new Timestamp(timeInMillis); if (nanoSecond != 0) { BigDecimal number = new BigDecimal("0." + nanoSecond); number = number.multiply(BigDecimal.valueOf(1000000000)).setScale(0, RoundingMode.HALF_DOWN); nanoSecond = number.intValue(); time.setNanos(nanoSecond); } return time; } throw new IllegalArgumentException("Value '" + dateString + "' is not a valid timestamp, expecting 'yyyy-MM-dd HH:mm:ss.SSS'."); } else { return null; } } static Timestamp getTimestamp(final String pattern, final String dateString) { final Date date = getDate(pattern, dateString); if (date == null) { return null; } else { final long time = date.getTime(); return new Timestamp(time); } } static int getYear() { final Calendar calendar = Calendar.getInstance(); return calendar.get(Calendar.YEAR); } static long printEllapsedTime(final long startTime) { final long endTime = System.currentTimeMillis(); System.out.println(toEllapsedTime(startTime, endTime)); return endTime; } static long printEllapsedTime(final String message, final long startTime) { final long endTime = System.currentTimeMillis(); System.out.println(message + "\t" + toEllapsedTime(startTime, endTime)); return endTime; } static String toDateTimeString(final Date date) { if (date == null) { return null; } else { final StringBuilder string = new StringBuilder(23); int year = date.getYear() + 1900; if (year < 0) { string.append('-'); year = -year; } if (year < 1000) { string.append('0'); if (year < 100) { string.append('0'); } if (year < 10) { string.append('0'); } } string.append(year); string.append('-'); final int month = date.getMonth() + 1; if (month < 10) { string.append('0'); } string.append(month); string.append('-'); final int day = date.getDate(); if (day < 10) { string.append('0'); } string.append(day); if (date instanceof java.sql.Date) { string.append(" 00:00:00"); } else { string.append(' '); final int hour = date.getHours(); if (hour < 10) { string.append('0'); } string.append(hour); string.append(':'); final int minutes = date.getMinutes(); if (minutes < 10) { string.append('0'); } string.append(minutes); string.append(':'); final int seconds = date.getSeconds(); if (seconds < 10) { string.append('0'); } string.append(seconds); string.append('.'); final int milliseconds = (int)(date.getTime() % 1000); if (milliseconds == 0) { string.append('0'); } else { String millisecondsString = Integer.toString(milliseconds); // Add leading zeros millisecondsString = "000".substring(0, 3 - millisecondsString.length()) + millisecondsString; // Truncate trailing zeros final char[] nanosChar = new char[millisecondsString.length()]; millisecondsString.getChars(0, millisecondsString.length(), nanosChar, 0); int truncIndex = 2; while (nanosChar[truncIndex] == '0') { truncIndex--; } string.append(millisecondsString, 0, truncIndex + 1); } } return string.toString(); } } static String toDateTimeString(final Object value) { if (value == null) { return null; } else { final Date date = getDate(value); return toDateTimeString(date); } } static String toEllapsedTime(final long time) { final StringBuilder string = new StringBuilder(); final long totalSeconds = Math.floorDiv(time, 1000); final long days = Math.floorDiv(totalSeconds, 24 * 60 * 60); if (days > 0) { string.append(days); string.append(' '); } final long hours = Math.floorDiv(totalSeconds, 60 * 60); if (hours > 0) { if (hours < 10 && string.length() > 0) { string.append('0'); } string.append(hours); string.append(':'); } final long minutes = Math.floorDiv(totalSeconds, 60) % 60; if (minutes > 0) { if (minutes < 10 && string.length() > 0) { string.append('0'); } string.append(minutes); string.append(':'); } final long seconds = totalSeconds % 60; if (seconds < 10 && string.length() > 0) { string.append('0'); } string.append(seconds); final long milliSeconds = time % 1000; if (milliSeconds > 0) { string.append('.'); if (milliSeconds < 10) { string.append('0'); } if (milliSeconds < 100) { string.append('0'); } string.append(milliSeconds); } return string.toString(); } static String toEllapsedTime(final long startTime, final long endTime) { return toEllapsedTime(endTime - startTime); } static String toSqlDateString(final Date date) { if (date == null) { return null; } else { final StringBuilder string = new StringBuilder(10); int year = date.getYear() + 1900; if (year < 0) { string.append('-'); year = -year; } if (year < 1000) { string.append('0'); if (year < 100) { string.append('0'); } if (year < 10) { string.append('0'); } } string.append(year); string.append('-'); final int month = date.getMonth() + 1; if (month < 10) { string.append('0'); } string.append(month); string.append('-'); final int day = date.getDate(); if (day < 10) { string.append('0'); } string.append(day); return string.toString(); } } static String toSqlDateString(final Object value) { if (value == null) { return null; } else { final java.sql.Date date = getSqlDate(value); return toSqlDateString(date); } } static String toTimestampString(final Object value) { if (value == null) { return null; } else { final Timestamp timestamp = getTimestamp(value); return toTimestampString(timestamp); } } static String toTimestampString(final Timestamp date) { if (date == null) { return null; } else { int year = date.getYear() + 1900; final StringBuilder string = new StringBuilder(26); if (year < 0) { string.append('-'); year = -year; } if (year < 1000) { string.append('0'); if (year < 100) { string.append('0'); } if (year < 10) { string.append('0'); } } string.append(year); string.append('-'); final int month = date.getMonth() + 1; if (month < 10) { string.append('0'); } string.append(month); string.append('-'); final int day = date.getDate(); if (day < 10) { string.append('0'); } string.append(day); string.append(' '); final int hour = date.getHours(); if (hour < 10) { string.append('0'); } string.append(hour); string.append(':'); final int minutes = date.getMinutes(); if (minutes < 10) { string.append('0'); } string.append(minutes); string.append(':'); final int seconds = date.getSeconds(); if (seconds < 10) { string.append('0'); } string.append(seconds); string.append('.'); final int nanos = date.getNanos(); if (nanos == 0) { string.append('0'); } else { String nanosString = Integer.toString(nanos); // Add leading zeros nanosString = "000000000".substring(0, 9 - nanosString.length()) + nanosString; // Truncate trailing zeros final char[] nanosChar = new char[nanosString.length()]; nanosString.getChars(0, nanosString.length(), nanosChar, 0); int truncIndex = 8; while (nanosChar[truncIndex] == '0') { truncIndex--; } string.append(nanosString, 0, truncIndex + 1); } return string.toString(); } } }