View Javadoc
1   /*
2    * DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
3    * Copyright (C) 2010  Mickael Guessant
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU General Public License
7    * as published by the Free Software Foundation; either version 2
8    * of the License, or (at your option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18   */
19  
20  package davmail.util;
21  
22  import davmail.exception.DavMailException;
23  import org.apache.log4j.Logger;
24  
25  import java.text.ParseException;
26  import java.text.SimpleDateFormat;
27  import java.time.LocalDate;
28  import java.time.LocalDateTime;
29  import java.time.ZoneId;
30  import java.time.ZonedDateTime;
31  import java.time.format.DateTimeFormatter;
32  import java.time.format.DateTimeParseException;
33  import java.time.format.TextStyle;
34  import java.util.Locale;
35  import java.util.ResourceBundle;
36  import java.util.TimeZone;
37  
38  /**
39   * Date conversion methods
40   */
41  public class DateUtil {
42  
43      protected static final Logger LOGGER = Logger.getLogger(DateUtil.class);
44  
45      public static final String GRAPH_DATE_TIME = "yyyy-MM-dd'T'HH:mm:ss";
46      public static final String GRAPH_ZULU_DATE_TIME = "yyyy-MM-dd'T'HH:mm:ss'Z'";
47  
48      public static final String CALDAV_DATE_TIME = "yyyyMMdd'T'HHmmss";
49      public static final String ISO8601_DATE_TIME = "yyyy-MM-dd'T'HH:mm:ssXXX";
50  
51      public static final String YYYY_MM_DDTHH_MM_SS_SSSSSSS = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS";
52  
53      public static final TimeZone UTC = TimeZone.getTimeZone("UTC");
54  
55  
56      /**
57       * Standard to Exchange timezone mapping
58       */
59      public static final ResourceBundle STD_TO_EXCHANGE_TZ = ResourceBundle.getBundle("exchtimezones");
60      /**
61       * Standard to Exchange timezone mapping
62       */
63      public static final ResourceBundle EXCHANGE_TO_STD_TZ = ResourceBundle.getBundle("stdtimezones");
64  
65      public static final ResourceBundle VTIMEZONES = ResourceBundle.getBundle("vtimezones");
66  
67  
68      /**
69       * Convert timezone to Exchange timezone.
70       * @param timezoneId exchange or standard timezone id
71       * @return exchange timezone or null if unknown
72       */
73      public static String getExchangeTimeZone(String timezoneId) {
74          if (timezoneId == null) {
75              return null;
76          } else if (EXCHANGE_TO_STD_TZ.containsKey(timezoneId)) {
77              return timezoneId;
78          } else if (STD_TO_EXCHANGE_TZ.containsKey(timezoneId)) {
79              return STD_TO_EXCHANGE_TZ.getString(timezoneId);
80          } else if ("tzone://Microsoft/Utc".equals(timezoneId)) {
81              return "UTC";
82          } else if ("tzone://Microsoft/Custom".equals(timezoneId)) {
83              return null;
84          } else {
85              LOGGER.warn("Unknown timezone: " + timezoneId);
86              return null;
87          }
88      }
89  
90      /**
91       * Convert timezone id to standard timezone id.
92       * @param timezoneId exchange or standard timezone id
93       * @return standard timezone or null if unknown
94       */
95      public static String getStandardTimeZone(String timezoneId) {
96          if (timezoneId == null) {
97              return null;
98          } else if (STD_TO_EXCHANGE_TZ.containsKey(timezoneId)) {
99              return timezoneId;
100         } else if (EXCHANGE_TO_STD_TZ.containsKey(timezoneId)) {
101             return EXCHANGE_TO_STD_TZ.getString(timezoneId);
102         } else if ("tzone://Microsoft/Utc".equals(timezoneId)) {
103             return "UTC";
104         } else if ("tzone://Microsoft/Custom".equals(timezoneId)) {
105             return null;
106         } else {
107             LOGGER.warn("Unknown timezone: " + timezoneId);
108             return null;
109         }
110     }
111 
112     public static TimeZone getTimeZone(String timezoneId) {
113         String standardTimeZoneId = getStandardTimeZone(timezoneId);
114         if (standardTimeZoneId != null) {
115             return TimeZone.getTimeZone(standardTimeZoneId);
116         }
117         return TimeZone.getTimeZone("UTC");
118     }
119 
120     public static String getVTimeZone(String timezoneId) {
121         String exchangeTimeZone = getExchangeTimeZone(timezoneId);
122         if (exchangeTimeZone != null && VTIMEZONES.containsKey(exchangeTimeZone)) {
123             return VTIMEZONES.getString(exchangeTimeZone);
124         } else {
125             LOGGER.warn("VTimezone not available for timezone: " + timezoneId);
126             return null;
127         }
128     }
129 
130     public static String convertDate(String sourceDate, String sourceFormat, String sourceTimezone,
131                                      String targetFormat, String targetTimezone) throws DavMailException {
132         return convertDate(sourceDate, sourceFormat, getTimeZone(sourceTimezone), targetFormat, getTimeZone(targetTimezone));
133     }
134 
135     public static String convertDate(String sourceDate, String sourceFormat, TimeZone sourceTimezone,
136                                      String targetFormat, TimeZone targetTimezone) throws DavMailException {
137         String targetDate;
138         SimpleDateFormat parser = new SimpleDateFormat(sourceFormat);
139         parser.setTimeZone(sourceTimezone);
140         SimpleDateFormat formatter = new SimpleDateFormat(targetFormat);
141         formatter.setTimeZone(targetTimezone);
142         try {
143             targetDate = formatter.format(parser.parse(sourceDate));
144         } catch (ParseException e) {
145             LOGGER.error("Error converting date: " + sourceDate + " from " + sourceFormat + " to " + targetFormat, e);
146             throw new DavMailException("EXCEPTION_INVALID_DATE", sourceDate);
147         }
148         return targetDate;
149     }
150 
151     public static String convertISO8601ToZulu(String sourceDate) throws DavMailException {
152 
153         String targetDate;
154         // timezone included in source format
155         SimpleDateFormat parser = new SimpleDateFormat(ISO8601_DATE_TIME);
156         SimpleDateFormat formatter = new SimpleDateFormat(GRAPH_ZULU_DATE_TIME);
157         formatter.setTimeZone(UTC);
158         try {
159             targetDate = formatter.format(parser.parse(sourceDate));
160         } catch (ParseException e) {
161             LOGGER.error("Error converting date: " + sourceDate + " from " + ISO8601_DATE_TIME + " to " + GRAPH_ZULU_DATE_TIME, e);
162             throw new DavMailException("EXCEPTION_INVALID_DATE", sourceDate);
163         }
164         return targetDate;
165     }
166 
167     public static String getDayOfWeek(String date) throws DavMailException {
168         if (date != null) {
169             try {
170                 LocalDate localDate = LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE);
171                 return localDate.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.ENGLISH).toLowerCase();
172             } catch (DateTimeParseException e) {
173                 throw new DavMailException("EXCEPTION_INVALID_DATE", date);
174             }
175         }
176         return null;
177     }
178 
179     public static String convertDateFormat(String sourceDate, String sourceFormat, String targetFormat) throws DavMailException {
180         String targetDate = null;
181         if (sourceDate != null) {
182             try {
183                 DateTimeFormatter parser = DateTimeFormatter.ofPattern(sourceFormat);
184                 DateTimeFormatter formatter = DateTimeFormatter.ofPattern(targetFormat);
185                 LocalDateTime localDateTime = LocalDateTime.parse(sourceDate, parser);
186 
187                 targetDate = localDateTime.format(formatter);
188             } catch (DateTimeParseException e) {
189                 throw new DavMailException("EXCEPTION_INVALID_DATE", sourceDate);
190             }
191         }
192         return targetDate;
193     }
194 
195     public static String convertToUTCDateFormat(String sourceDate, String sourceTimezone, String sourceFormat, String targetFormat) throws DavMailException {
196         String targetDate = null;
197         if (sourceDate != null && sourceTimezone != null) {
198             try {
199                 DateTimeFormatter parser = DateTimeFormatter.ofPattern(sourceFormat);
200                 DateTimeFormatter formatter = DateTimeFormatter.ofPattern(targetFormat);
201                 LocalDateTime localDateTime = LocalDateTime.parse(sourceDate, parser);
202 
203                 // Convert to UTC
204                 ZonedDateTime zonedStart = localDateTime.atZone(ZoneId.of(sourceTimezone));
205                 ZonedDateTime utcStartDate = zonedStart.withZoneSameInstant(ZoneId.of("UTC"));
206                 targetDate = utcStartDate.format(formatter);
207             } catch (DateTimeParseException e) {
208                 throw new DavMailException("EXCEPTION_INVALID_DATE", sourceDate);
209             }
210         }
211         return targetDate;
212     }
213 }