001 /* 002 * Copyright (C) 2008 Petr Nejedly <P.Nejedly@sh.cvut.cz> 003 * 004 * This program is free software; you can redistribute it and/or modify 005 * it under the terms of the GNU General Public License as published by 006 * the Free Software Foundation; either version 2 of the License, or 007 * (at your option) any later version. 008 * 009 * This program is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU General Public License for more details. 013 014 * You should have received a copy of the GNU General Public License along 015 * with this program; if not, write to the Free Software Foundation, Inc., 016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 017 */ 018 019 package org.openstreetmap.josm.tools; 020 021 import java.text.ParsePosition; 022 import java.text.SimpleDateFormat; 023 import java.util.Calendar; 024 import java.util.Date; 025 import java.util.GregorianCalendar; 026 import java.util.TimeZone; 027 028 import javax.xml.datatype.DatatypeConfigurationException; 029 import javax.xml.datatype.DatatypeFactory; 030 import javax.xml.datatype.XMLGregorianCalendar; 031 032 /** 033 * A static utility class dealing with parsing XML date quickly and formatting 034 * a date to the XML UTC format regardless of current locale. 035 * 036 * @author nenik 037 */ 038 public final class DateUtils { 039 private DateUtils() {} 040 /** 041 * A shared instance used for conversion between individual date fields 042 * and long millis time. It is guarded against conflict by the class lock. 043 * The shared instance is used because the construction, together 044 * with the timezone lookup, is very expensive. 045 */ 046 private static GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); 047 private static final DatatypeFactory XML_DATE; 048 049 static { 050 calendar.setTimeInMillis(0); 051 052 DatatypeFactory fact = null; 053 try { 054 fact = DatatypeFactory.newInstance(); 055 } catch(DatatypeConfigurationException ce) { 056 ce.printStackTrace(); 057 } 058 XML_DATE = fact; 059 } 060 061 public static synchronized Date fromString(String str) { 062 // "2007-07-25T09:26:24{Z|{+|-}01:00}" 063 if (checkLayout(str, "xxxx-xx-xxTxx:xx:xxZ") || 064 checkLayout(str, "xxxx-xx-xxTxx:xx:xx") || 065 checkLayout(str, "xxxx-xx-xxTxx:xx:xx+xx:00") || 066 checkLayout(str, "xxxx-xx-xxTxx:xx:xx-xx:00")) { 067 calendar.set( 068 parsePart(str, 0, 4), 069 parsePart(str, 5, 2)-1, 070 parsePart(str, 8, 2), 071 parsePart(str, 11, 2), 072 parsePart(str, 14,2), 073 parsePart(str, 17, 2)); 074 075 if (str.length() == 25) { 076 int plusHr = parsePart(str, 20, 2); 077 int mul = str.charAt(19) == '+' ? -3600000 : 3600000; 078 calendar.setTimeInMillis(calendar.getTimeInMillis()+plusHr*mul); 079 } 080 081 return calendar.getTime(); 082 } 083 else if(checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxxZ") || 084 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx") || 085 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx+xx:00") || 086 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx-xx:00")) { 087 calendar.set( 088 parsePart(str, 0, 4), 089 parsePart(str, 5, 2)-1, 090 parsePart(str, 8, 2), 091 parsePart(str, 11, 2), 092 parsePart(str, 14,2), 093 parsePart(str, 17, 2)); 094 long millis = parsePart(str, 20, 3); 095 if (str.length() == 29) 096 millis += parsePart(str, 24, 2) * (str.charAt(23) == '+' ? -3600000 : 3600000); 097 calendar.setTimeInMillis(calendar.getTimeInMillis()+millis); 098 099 return calendar.getTime(); 100 } 101 else 102 { 103 // example date format "18-AUG-08 13:33:03" 104 SimpleDateFormat f = new SimpleDateFormat("dd-MMM-yy HH:mm:ss"); 105 Date d = f.parse(str, new ParsePosition(0)); 106 if(d != null) 107 return d; 108 } 109 110 try { 111 return XML_DATE.newXMLGregorianCalendar(str).toGregorianCalendar().getTime(); 112 } catch (Exception ex) { 113 return new Date(); 114 } 115 } 116 117 public static synchronized String fromDate(Date date) { 118 calendar.setTime(date); 119 XMLGregorianCalendar xgc = XML_DATE.newXMLGregorianCalendar(calendar); 120 if (calendar.get(Calendar.MILLISECOND) == 0) xgc.setFractionalSecond(null); 121 return xgc.toXMLFormat(); 122 } 123 124 private static boolean checkLayout(String text, String pattern) { 125 if (text.length() != pattern.length()) return false; 126 for (int i=0; i<pattern.length(); i++) { 127 char pc = pattern.charAt(i); 128 char tc = text.charAt(i); 129 if(pc == 'x' && tc >= '0' && tc <= '9') continue; 130 else if(pc == 'x' || pc != tc) return false; 131 } 132 return true; 133 } 134 135 private static int parsePart(String str, int off, int len) { 136 return Integer.valueOf(str.substring(off, off+len)); 137 } 138 139 }