| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF 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 org.apache.chemistry.opencmis.commons.impl; |
| |
| import java.math.BigDecimal; |
| import java.util.Calendar; |
| import java.util.Date; |
| import java.util.GregorianCalendar; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.TimeZone; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| public final class DateTimeHelper { |
| |
| private static final TimeZone GMT = TimeZone.getTimeZone("GMT"); |
| |
| private static final Pattern XML_DATETIME = Pattern |
| .compile("(\\d{4,9})-([01]\\d)-([0-3]\\d)T([0-2]\\d):([0-5]\\d):([0-5]\\d)(\\.(\\d+))?(([+-][0-2]\\d:[0-5]\\d)|Z)?"); |
| private static final BigDecimal BD1000 = new BigDecimal(1000); |
| |
| private static final String[] WDAYS = new String[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; |
| |
| private static final String[] MONTHS = new String[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", |
| "Sep", "Oct", "Nov", "Dec" }; |
| |
| private static final Map<String, Integer> MONTHS_MAP = new HashMap<String, Integer>(); |
| static { |
| for (int i = 0; i < MONTHS.length; i++) { |
| MONTHS_MAP.put(MONTHS[i], i); |
| } |
| } |
| |
| private static final Pattern HTTP_DATETIME1 = Pattern |
| .compile("\\w{3}, ([0-3]\\d) (\\w{3}) (\\d{4}) ([0-2]\\d):([0-5]\\d):([0-5]\\d) GMT"); |
| |
| private static final Pattern HTTP_DATETIME2 = Pattern |
| .compile("\\w{6,9}, ([0-3]\\d)-(\\w{3})-(\\d{2}) ([0-2]\\d):([0-5]\\d):([0-5]\\d) GMT"); |
| |
| private static final Pattern HTTP_DATETIME3 = Pattern |
| .compile("\\w{3} (\\w{3}) ([0-3 ]\\d) ([0-2]\\d):([0-5]\\d):([0-5]\\d) (\\d{4})"); |
| |
| private DateTimeHelper() { |
| } |
| |
| /** |
| * Parses a xsd:dateTime string. |
| */ |
| public static GregorianCalendar parseXmlDateTime(String s) { |
| if (s == null) { |
| return null; |
| } |
| |
| final Matcher m = XML_DATETIME.matcher(s); |
| |
| if (!m.matches()) { |
| return null; |
| } |
| |
| try { |
| int year = Integer.parseInt(m.group(1)); |
| int month = Integer.parseInt(m.group(2)); |
| int day = Integer.parseInt(m.group(3)); |
| int hour = Integer.parseInt(m.group(4)); |
| int minute = Integer.parseInt(m.group(5)); |
| int second = Integer.parseInt(m.group(6)); |
| int millisecond = 0; |
| |
| if (m.group(8) != null) { |
| millisecond = (new BigDecimal("0." + m.group(8))).multiply(BD1000).intValue(); |
| } |
| |
| TimeZone tz = GMT; |
| |
| if (m.group(10) != null) { |
| tz = TimeZone.getTimeZone("GMT" + m.group(10)); |
| } |
| |
| final GregorianCalendar result = new GregorianCalendar(); |
| result.clear(); |
| |
| result.setTimeZone(tz); |
| result.set(year, month - 1, day, hour, minute, second); |
| result.set(Calendar.MILLISECOND, millisecond); |
| |
| return result; |
| } catch (NumberFormatException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns a xsd:dateTime string. |
| */ |
| public static String formatXmlDateTime(long millis) { |
| final GregorianCalendar cal = new GregorianCalendar(GMT); |
| cal.setTimeInMillis(millis); |
| |
| return formatXmlDateTime(cal); |
| } |
| |
| /** |
| * Returns a xsd:dateTime string. |
| */ |
| public static String formatXmlDateTime(GregorianCalendar cal) { |
| if (cal == null) { |
| throw new IllegalArgumentException(); |
| } |
| |
| final StringBuilder sb = new StringBuilder(); |
| add4d(sb, cal.get(Calendar.YEAR)); |
| sb.append('-'); |
| add2d(sb, cal.get(Calendar.MONTH) + 1); |
| sb.append('-'); |
| add2d(sb, cal.get(Calendar.DAY_OF_MONTH)); |
| sb.append('T'); |
| add2d(sb, cal.get(Calendar.HOUR_OF_DAY)); |
| sb.append(':'); |
| add2d(sb, cal.get(Calendar.MINUTE)); |
| sb.append(':'); |
| add2d(sb, cal.get(Calendar.SECOND)); |
| |
| int ms = cal.get(Calendar.MILLISECOND); |
| if (ms > 0) { |
| sb.append('.'); |
| add3d(sb, ms); |
| while (sb.charAt(sb.length() - 1) == '0') { |
| sb.deleteCharAt(sb.length() - 1); |
| } |
| } |
| |
| int tz = cal.getTimeZone().getOffset(cal.getTimeInMillis()); |
| if (tz == 0) { |
| sb.append('Z'); |
| } else { |
| if (tz > 0) { |
| sb.append('+'); |
| } else { |
| sb.append('-'); |
| tz *= -1; |
| } |
| add2d(sb, tz / 3600000); |
| sb.append(':'); |
| int tzm = tz % 3600000; |
| add2d(sb, tzm == 0 ? 0 : tzm / 60000); |
| } |
| |
| return sb.toString(); |
| } |
| |
| /** |
| * Parses a HTTP date. |
| */ |
| public static Date parseHttpDateTime(String s) { |
| if (s == null) { |
| return null; |
| } |
| |
| s = s.trim(); |
| if (s.length() > 1 && s.charAt(0) == '\'' && s.endsWith("'")) { |
| s = s.substring(1, s.length() - 1); |
| } |
| |
| final GregorianCalendar cal = new GregorianCalendar(GMT); |
| cal.set(Calendar.MILLISECOND, 0); |
| |
| Matcher m = null; |
| |
| m = HTTP_DATETIME1.matcher(s); |
| if (m.matches()) { |
| final Integer month = MONTHS_MAP.get(m.group(2)); |
| if (month == null) { |
| return null; |
| } |
| |
| cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(m.group(1))); |
| cal.set(Calendar.MONTH, month); |
| cal.set(Calendar.YEAR, Integer.parseInt(m.group(3))); |
| cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(m.group(4))); |
| cal.set(Calendar.MINUTE, Integer.parseInt(m.group(5))); |
| cal.set(Calendar.SECOND, Integer.parseInt(m.group(6))); |
| |
| return cal.getTime(); |
| } |
| |
| m = HTTP_DATETIME2.matcher(s); |
| if (m.matches()) { |
| final Integer month = MONTHS_MAP.get(m.group(2)); |
| if (month == null) { |
| return null; |
| } |
| |
| cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(m.group(1))); |
| cal.set(Calendar.MONTH, month); |
| int year = Integer.parseInt(m.group(3)); |
| if (year < 100) { |
| final int thisYear = (new GregorianCalendar(GMT)).get(Calendar.YEAR); |
| final int testYear = year + thisYear - thisYear % 100; |
| year = (testYear < thisYear + 20 ? testYear : testYear - 100); |
| } |
| cal.set(Calendar.YEAR, year); |
| cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(m.group(4))); |
| cal.set(Calendar.MINUTE, Integer.parseInt(m.group(5))); |
| cal.set(Calendar.SECOND, Integer.parseInt(m.group(6))); |
| |
| return cal.getTime(); |
| } |
| |
| m = HTTP_DATETIME3.matcher(s); |
| if (m.matches()) { |
| final Integer month = MONTHS_MAP.get(m.group(1)); |
| if (month == null) { |
| return null; |
| } |
| |
| cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(m.group(2).trim())); |
| cal.set(Calendar.MONTH, month); |
| cal.set(Calendar.YEAR, Integer.parseInt(m.group(6))); |
| cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(m.group(3))); |
| cal.set(Calendar.MINUTE, Integer.parseInt(m.group(4))); |
| cal.set(Calendar.SECOND, Integer.parseInt(m.group(5))); |
| |
| return cal.getTime(); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns a HTTP date. |
| */ |
| public static String formatHttpDateTime(long millis) { |
| final GregorianCalendar cal = new GregorianCalendar(GMT); |
| cal.setTimeInMillis(millis); |
| |
| final StringBuilder sb = new StringBuilder(); |
| sb.append(WDAYS[cal.get(Calendar.DAY_OF_WEEK) - 1]); |
| sb.append(", "); |
| add2d(sb, cal.get(Calendar.DAY_OF_MONTH)); |
| sb.append(' '); |
| sb.append(MONTHS[cal.get(Calendar.MONTH)]); |
| sb.append(' '); |
| add4d(sb, cal.get(Calendar.YEAR)); |
| sb.append(' '); |
| add2d(sb, cal.get(Calendar.HOUR_OF_DAY)); |
| sb.append(':'); |
| add2d(sb, cal.get(Calendar.MINUTE)); |
| sb.append(':'); |
| add2d(sb, cal.get(Calendar.SECOND)); |
| sb.append(" GMT"); |
| |
| return sb.toString(); |
| } |
| |
| /** |
| * Returns a HTTP date. |
| */ |
| public static String formatHttpDateTime(final Date date) { |
| return formatHttpDateTime(date.getTime()); |
| } |
| |
| /** |
| * Returns a HTTP date. |
| */ |
| public static String formatHttpDateTime(final GregorianCalendar cal) { |
| return formatHttpDateTime(cal.getTimeInMillis()); |
| } |
| |
| private static void add2d(final StringBuilder sb, int value) { |
| assert sb != null; |
| assert value >= 0; |
| |
| if (value < 10) { |
| sb.append('0'); |
| } |
| sb.append(value); |
| } |
| |
| private static void add3d(final StringBuilder sb, int value) { |
| assert sb != null; |
| assert value >= 0; |
| |
| if (value < 10) { |
| sb.append('0'); |
| } |
| if (value < 100) { |
| sb.append('0'); |
| } |
| sb.append(value); |
| } |
| |
| private static void add4d(final StringBuilder sb, int value) { |
| assert sb != null; |
| assert value >= 0; |
| |
| if (value < 10) { |
| sb.append('0'); |
| } |
| if (value < 100) { |
| sb.append('0'); |
| } |
| if (value < 1000) { |
| sb.append('0'); |
| } |
| sb.append(value); |
| } |
| |
| } |