1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.bluetooth.mapclient;
18 
19 import java.util.Calendar;
20 import java.util.Date;
21 import java.util.Locale;
22 import java.util.TimeZone;
23 import java.util.regex.Matcher;
24 import java.util.regex.Pattern;
25 
26 public final class ObexTime {
27 
28     private Date mDate;
29 
ObexTime(String time)30     public ObexTime(String time) {
31         /*
32          * Match OBEX time string: YYYYMMDDTHHMMSS with optional UTF offset +/-hhmm
33          *
34          * Matched groups are numberes as follows:
35          *
36          *     YYYY MM DD T HH MM SS + hh mm
37          *     ^^^^ ^^ ^^   ^^ ^^ ^^ ^ ^^ ^^
38          *     1    2  3    4  5  6  8 9  10
39          *                          |---7---|
40          *
41          * All groups are guaranteed to be numeric so conversion will always succeed (except group 8
42          * which is either + or -)
43          */
44         Pattern p = Pattern.compile(
45                 "(\\d{4})(\\d{2})(\\d{2})T(\\d{2})(\\d{2})(\\d{2})(([+-])(\\d{2})(\\d{2})" + ")?");
46         Matcher m = p.matcher(time);
47 
48         if (m.matches()) {
49 
50             /*
51              * MAP spec says to default to "Local Time basis" for a message listing timestamp. We'll
52              * use the system default timezone and assume it knows best what our local timezone is.
53              * The builder defaults to the default locale and timezone if none is provided.
54              */
55             Calendar.Builder builder = new Calendar.Builder();
56 
57             /* Note that Calendar months are zero-based */
58             builder.setDate(Integer.parseInt(m.group(1)), /* year */
59                     Integer.parseInt(m.group(2)) - 1,     /* month */
60                     Integer.parseInt(m.group(3)));        /* day of month */
61 
62             /* Note the MAP timestamp doesn't have milliseconds and we're explicitly setting to 0 */
63             builder.setTimeOfDay(Integer.parseInt(m.group(4)), /* hours */
64                     Integer.parseInt(m.group(5)),              /* minutes */
65                     Integer.parseInt(m.group(6)),              /* seconds */
66                     0);                                        /* milliseconds */
67 
68             /*
69              * If 7th group is matched then we're no longer using "Local Time basis" and instead
70              * have a UTC based timestamp and offset information included
71              */
72             if (m.group(7) != null) {
73                 int ohh = Integer.parseInt(m.group(9));
74                 int omm = Integer.parseInt(m.group(10));
75 
76                 /* time zone offset is specified in miliseconds */
77                 int offset = (ohh * 60 + omm) * 60 * 1000;
78 
79                 if (m.group(8).equals("-")) {
80                     offset = -offset;
81                 }
82 
83                 TimeZone tz = TimeZone.getTimeZone("UTC");
84                 tz.setRawOffset(offset);
85 
86                 builder.setTimeZone(tz);
87             }
88 
89             mDate = builder.build().getTime();
90         }
91     }
92 
ObexTime(Date date)93     public ObexTime(Date date) {
94         mDate = date;
95     }
96 
getTime()97     public Date getTime() {
98         return mDate;
99     }
100 
101     @Override
toString()102     public String toString() {
103         if (mDate == null) {
104             return null;
105         }
106 
107         Calendar cal = Calendar.getInstance();
108         cal.setTime(mDate);
109 
110         /* note that months are numbered stating from 0 */
111         return String.format(Locale.US, "%04d%02d%02dT%02d%02d%02d", cal.get(Calendar.YEAR),
112                 cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DATE), cal.get(Calendar.HOUR_OF_DAY),
113                 cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND));
114     }
115 }
116