OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 80 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 80 Rev 180
1
/*
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 * 
3
 * 
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 * 
5
 * 
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
9
 * language governing permissions and limitations under the License.
10
 * 
10
 * 
11
 * When distributing the software, include this License Header Notice in each file.
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
12
 */
13
 
13
 
14
 package org.openconcerto.openoffice;
14
 package org.openconcerto.openoffice;
15
 
15
 
16
import org.openconcerto.utils.FormatGroup;
16
import org.openconcerto.utils.FormatGroup;
17
import org.openconcerto.utils.TimeUtils;
17
import org.openconcerto.utils.TimeUtils;
18
import org.openconcerto.utils.XMLCalendarFormat;
18
import org.openconcerto.utils.XMLCalendarFormat;
19
import org.openconcerto.utils.XMLDateFormat;
19
import org.openconcerto.utils.XMLDateFormat;
20
 
20
 
21
import java.math.BigDecimal;
21
import java.math.BigDecimal;
22
import java.text.Format;
22
import java.text.Format;
23
import java.text.ParseException;
23
import java.text.ParseException;
24
import java.text.SimpleDateFormat;
24
import java.text.SimpleDateFormat;
25
import java.util.Arrays;
25
import java.util.Arrays;
26
import java.util.Calendar;
26
import java.util.Calendar;
27
import java.util.Date;
27
import java.util.Date;
28
import java.util.List;
28
import java.util.List;
29
import java.util.Locale;
29
import java.util.Locale;
30
import java.util.TimeZone;
30
import java.util.TimeZone;
31
 
31
 
32
import javax.xml.datatype.Duration;
32
import javax.xml.datatype.Duration;
33
 
33
 
34
import net.jcip.annotations.GuardedBy;
34
import net.jcip.annotations.GuardedBy;
35
import net.jcip.annotations.Immutable;
35
import net.jcip.annotations.Immutable;
36
 
36
 
37
/**
37
/**
38
 * A type of value, as per 16.1 "Data Types" and 6.7.1 "Variable Value Types and Values"
38
 * A type of value, as per 16.1 "Data Types" and 6.7.1 "Variable Value Types and Values"
39
 */
39
 */
40
@Immutable
40
@Immutable
41
public enum ODValueType {
41
public enum ODValueType {
42
 
42
 
43
    /**
43
    /**
44
     * Parses to {@link BigDecimal} to return the exact number.
44
     * Parses to {@link BigDecimal} to return the exact number.
45
     */
45
     */
46
    FLOAT("value", Number.class) {
46
    FLOAT("value", Number.class) {
47
 
47
 
48
        @Override
48
        @Override
49
        public String format(Object o) {
49
        public String format(Object o) {
50
            // avoid 1.23E+3
50
            // avoid 1.23E+3
51
            if (o instanceof BigDecimal)
51
            if (o instanceof BigDecimal)
52
                return ((BigDecimal) o).toPlainString();
52
                return ((BigDecimal) o).toPlainString();
53
            else
53
            else
54
                return ((Number) o).toString();
54
                return ((Number) o).toString();
55
        }
55
        }
56
 
56
 
57
        @Override
57
        @Override
58
        public BigDecimal parse(String s) {
58
        public BigDecimal parse(String s) {
59
            return new BigDecimal(s);
59
            return new BigDecimal(s);
60
        }
60
        }
61
 
61
 
62
    },
62
    },
63
    PERCENTAGE("value", Number.class) {
63
    PERCENTAGE("value", Number.class) {
64
 
64
 
65
        @Override
65
        @Override
66
        public String format(Object o) {
66
        public String format(Object o) {
67
            return FLOAT.format(o);
67
            return FLOAT.format(o);
68
        }
68
        }
69
 
69
 
70
        @Override
70
        @Override
71
        public Object parse(String s) {
71
        public Object parse(String s) {
72
            return FLOAT.parse(s);
72
            return FLOAT.parse(s);
73
        }
73
        }
74
 
74
 
75
    },
75
    },
76
    CURRENCY("value", Number.class) {
76
    CURRENCY("value", Number.class) {
77
 
77
 
78
        @Override
78
        @Override
79
        public String format(Object o) {
79
        public String format(Object o) {
80
            return FLOAT.format(o);
80
            return FLOAT.format(o);
81
        }
81
        }
82
 
82
 
83
        @Override
83
        @Override
84
        public Object parse(String s) {
84
        public Object parse(String s) {
85
            return FLOAT.parse(s);
85
            return FLOAT.parse(s);
86
        }
86
        }
87
    },
87
    },
-
 
88
    // TODO support LocalDateTime
88
    DATE("date-value", Date.class, Calendar.class) {
89
    DATE("date-value", Date.class, Calendar.class) {
89
 
90
 
90
        @Override
91
        @Override
91
        public String format(Object o) {
92
        public String format(Object o) {
92
            return formatDate(o);
93
            return formatDate(o);
93
        }
94
        }
94
 
95
 
95
        @Override
96
        @Override
96
        public Date parse(String date) {
97
        public Date parse(String date) {
97
            if (date.length() == 0)
98
            if (date.length() == 0)
98
                return null;
99
                return null;
99
            else {
100
            else {
100
                try {
101
                try {
101
                    return parseDateValue(date).getTime();
102
                    return parseDateValue(date).getTime();
102
                } catch (ParseException e) {
103
                } catch (ParseException e) {
103
                    throw new IllegalStateException("wrong date: " + date, e);
104
                    throw new IllegalStateException("wrong date: " + date, e);
104
                }
105
                }
105
            }
106
            }
106
        }
107
        }
107
 
108
 
108
    },
109
    },
109
    TIME("time-value", Duration.class, Calendar.class) {
110
    TIME("time-value", Duration.class, java.time.Duration.class, Calendar.class) {
110
 
111
 
111
        @Override
112
        @Override
112
        public String format(Object o) {
113
        public String format(Object o) {
113
            if (o instanceof Duration) {
114
            if (o instanceof Duration) {
114
                return o.toString();
115
                return o.toString();
-
 
116
            } else if (o instanceof java.time.Duration) {
-
 
117
                // w/o days or larger : PTnHnMnS
-
 
118
                return o.toString();
115
            } else {
119
            } else {
116
                final Calendar cal = (Calendar) o;
120
                final Calendar cal = (Calendar) o;
117
                return TimeUtils.timePartToDuration(cal).toString();
121
                return TimeUtils.timePartToDuration(cal).toString();
118
            }
122
            }
119
        }
123
        }
120
 
124
 
121
        @Override
125
        @Override
122
        public Duration parse(String date) {
126
        public Duration parse(String date) {
123
            if (date.length() == 0)
127
            if (date.length() == 0)
124
                return null;
128
                return null;
125
            else {
129
            else {
126
                return TimeUtils.getTypeFactory().newDuration(date);
130
                return TimeUtils.getTypeFactory().newDuration(date);
127
            }
131
            }
128
        }
132
        }
129
 
133
 
130
    },
134
    },
131
    BOOLEAN("boolean-value", Boolean.class) {
135
    BOOLEAN("boolean-value", Boolean.class) {
132
 
136
 
133
        @Override
137
        @Override
134
        public String format(Object o) {
138
        public String format(Object o) {
135
            return ((Boolean) o).toString().toLowerCase();
139
            return ((Boolean) o).toString().toLowerCase();
136
        }
140
        }
137
 
141
 
138
        @Override
142
        @Override
139
        public Boolean parse(String s) {
143
        public Boolean parse(String s) {
140
            return Boolean.valueOf(s);
144
            return Boolean.valueOf(s);
141
        }
145
        }
142
 
146
 
143
    },
147
    },
144
    STRING("string-value", String.class) {
148
    STRING("string-value", String.class) {
145
 
149
 
146
        @Override
150
        @Override
147
        public String format(Object o) {
151
        public String format(Object o) {
148
            return o.toString();
152
            return o.toString();
149
        }
153
        }
150
 
154
 
151
        @Override
155
        @Override
152
        public String parse(String s) {
156
        public String parse(String s) {
153
            return s;
157
            return s;
154
        }
158
        }
155
    };
159
    };
156
 
160
 
157
    private final String attr;
161
    private final String attr;
158
    private final List<Class<?>> acceptedClasses;
162
    private final List<Class<?>> acceptedClasses;
159
 
163
 
160
    private ODValueType(String attr, Class<?>... classes) {
164
    private ODValueType(String attr, Class<?>... classes) {
161
        this.attr = attr;
165
        this.attr = attr;
162
        this.acceptedClasses = Arrays.asList(classes);
166
        this.acceptedClasses = Arrays.asList(classes);
163
    }
167
    }
164
 
168
 
165
    /**
169
    /**
166
     * The name of the value attribute for this value type.
170
     * The name of the value attribute for this value type.
167
     * 
171
     * 
168
     * @return the value attribute, e.g. "boolean-value".
172
     * @return the value attribute, e.g. "boolean-value".
169
     */
173
     */
170
    public final String getValueAttribute() {
174
    public final String getValueAttribute() {
171
        return this.attr;
175
        return this.attr;
172
    }
176
    }
173
 
177
 
174
    public boolean canFormat(Class<?> toFormat) {
178
    public boolean canFormat(Class<?> toFormat) {
175
        for (final Class<?> c : this.acceptedClasses)
179
        for (final Class<?> c : this.acceptedClasses)
176
            if (c.isAssignableFrom(toFormat))
180
            if (c.isAssignableFrom(toFormat))
177
                return true;
181
                return true;
178
        return false;
182
        return false;
179
    }
183
    }
180
 
184
 
181
    public abstract String format(Object o);
185
    public abstract String format(Object o);
182
 
186
 
183
    public abstract Object parse(String s);
187
    public abstract Object parse(String s);
184
 
188
 
185
    /**
189
    /**
186
     * The value for the value-type attribute.
190
     * The value for the value-type attribute.
187
     * 
191
     * 
188
     * @return the value for the value-type attribute, e.g. "float".
192
     * @return the value for the value-type attribute, e.g. "float".
189
     */
193
     */
190
    public final String getName() {
194
    public final String getName() {
191
        return this.name().toLowerCase();
195
        return this.name().toLowerCase();
192
    }
196
    }
193
 
197
 
194
    /**
198
    /**
195
     * The instance for the passed value type.
199
     * The instance for the passed value type.
196
     * 
200
     * 
197
     * @param name the value of the value-type attribute, e.g. "date".
201
     * @param name the value of the value-type attribute, e.g. "date".
198
     * @return the corresponding instance, never <code>null</code>, e.g. {@link #DATE}.
202
     * @return the corresponding instance, never <code>null</code>, e.g. {@link #DATE}.
199
     * @throws IllegalArgumentException if <code>name</code> isn't a valid type.
203
     * @throws IllegalArgumentException if <code>name</code> isn't a valid type.
200
     */
204
     */
201
    public static ODValueType get(String name) {
205
    public static ODValueType get(String name) {
202
        return ODValueType.valueOf(name.toUpperCase());
206
        return ODValueType.valueOf(name.toUpperCase());
203
    }
207
    }
204
 
208
 
205
    /**
209
    /**
206
     * Try to guess the value type for the passed object.
210
     * Try to guess the value type for the passed object.
207
     * 
211
     * 
208
     * @param o the object.
212
     * @param o the object.
209
     * @return a value type capable of formatting <code>o</code> or <code>null</code>.
213
     * @return a value type capable of formatting <code>o</code> or <code>null</code>.
210
     * @throws NullPointerException if <code>o</code> is <code>null</code>.
214
     * @throws NullPointerException if <code>o</code> is <code>null</code>.
211
     */
215
     */
212
    public static ODValueType forObject(Object o) throws NullPointerException {
216
    public static ODValueType forObject(Object o) throws NullPointerException {
213
        if (o == null)
217
        if (o == null)
214
            throw new NullPointerException();
218
            throw new NullPointerException();
215
        if (o instanceof Number)
219
        if (o instanceof Number)
216
            return FLOAT;
220
            return FLOAT;
217
        else if (o instanceof Boolean)
221
        else if (o instanceof Boolean)
218
            return BOOLEAN;
222
            return BOOLEAN;
219
        else if (o instanceof String)
223
        else if (o instanceof String)
220
            return STRING;
224
            return STRING;
221
        else if (o instanceof Duration)
225
        else if (o instanceof Duration || o instanceof java.time.Duration)
222
            return TIME;
226
            return TIME;
223
        else if (DATE.canFormat(o.getClass()))
227
        else if (DATE.canFormat(o.getClass()))
224
            return DATE;
228
            return DATE;
225
        else
229
        else
226
            return null;
230
            return null;
227
    }
231
    }
228
 
232
 
229
    static private final TimeZone UTC_TZ = TimeZone.getTimeZone("UTC");
233
    static private final TimeZone UTC_TZ = TimeZone.getTimeZone("UTC");
230
    // use nulls and not (TimeZone|Locale).getDefault() so as to not need to listen to changes
234
    // use nulls and not (TimeZone|Locale).getDefault() so as to not need to listen to changes
231
    // LibreOffice behavior as of 4.1 is to no longer ignore explicit time zone when reading dates.
235
    // LibreOffice behavior as of 4.1 is to no longer ignore explicit time zone when reading dates.
232
    @GuardedBy("ODValueType")
236
    @GuardedBy("ODValueType")
233
    static private DateConfig DATE_CONFIG = new DateConfig(null, null, null, Boolean.FALSE);
237
    static private DateConfig DATE_CONFIG = new DateConfig(null, null, null, Boolean.FALSE);
234
 
238
 
235
    // see http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#isoformats
239
    // see http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#isoformats
236
 
240
 
237
    @GuardedBy("ODValueType")
241
    @GuardedBy("ODValueType")
238
    static private Format DATE_FORMAT, DATE_PARSER;
242
    static private Format DATE_FORMAT, DATE_PARSER;
239
    static {
243
    static {
240
        updateFormat();
244
        updateFormat();
241
    }
245
    }
242
 
246
 
243
    static private synchronized String formatDate(Object obj) {
247
    static private synchronized String formatDate(Object obj) {
244
        return DATE_FORMAT.format(obj);
248
        return DATE_FORMAT.format(obj);
245
    }
249
    }
246
 
250
 
247
    static private synchronized void updateFormat() {
251
    static private synchronized void updateFormat() {
248
        // always remove time zone on write
252
        // always remove time zone on write
249
        DATE_FORMAT = new XMLCalendarFormat(getTimeZone(false), getLocale(false));
253
        DATE_FORMAT = new XMLCalendarFormat(getTimeZone(false), getLocale(false));
250
        DATE_PARSER = getFormatParser(DATE_CONFIG, true);
254
        DATE_PARSER = getFormatParser(DATE_CONFIG, true);
251
    }
255
    }
252
 
256
 
253
    static private synchronized SimpleDateFormat createDateFormat(final String pattern, final DateConfig dateConf) {
257
    static private synchronized SimpleDateFormat createDateFormat(final String pattern, final DateConfig dateConf) {
254
        final SimpleDateFormat res = new SimpleDateFormat(pattern, dateConf.getLocale(true));
258
        final SimpleDateFormat res = new SimpleDateFormat(pattern, dateConf.getLocale(true));
255
        res.setTimeZone(!dateConf.isTimeZoneIgnored() ? UTC_TZ : dateConf.getTimeZone(true));
259
        res.setTimeZone(!dateConf.isTimeZoneIgnored() ? UTC_TZ : dateConf.getTimeZone(true));
256
        return res;
260
        return res;
257
    }
261
    }
258
 
262
 
259
    static private synchronized Format getFormatParser(final DateConfig dateConf, final boolean forceCreate) {
263
    static private synchronized Format getFormatParser(final DateConfig dateConf, final boolean forceCreate) {
260
        if (!forceCreate && dateConf.equals(DATE_CONFIG)) {
264
        if (!forceCreate && dateConf.equals(DATE_CONFIG)) {
261
            return DATE_PARSER;
265
            return DATE_PARSER;
262
        } else {
266
        } else {
263
            final Format xmlDF;
267
            final Format xmlDF;
264
            if (dateConf.isTimeZoneIgnored()) {
268
            if (dateConf.isTimeZoneIgnored()) {
265
                xmlDF = new XMLCalendarFormat(dateConf.getTimeZone(false), dateConf.getLocale(false));
269
                xmlDF = new XMLCalendarFormat(dateConf.getTimeZone(false), dateConf.getLocale(false));
266
            } else {
270
            } else {
267
                xmlDF = new XMLDateFormat(UTC_TZ, null);
271
                xmlDF = new XMLDateFormat(UTC_TZ, null);
268
            }
272
            }
269
            // first date and time so we don't loose time information on format() or parse()
273
            // first date and time so we don't loose time information on format() or parse()
270
            // MAYBE add HH':'mm':'ss,SSS for OOo 1
274
            // MAYBE add HH':'mm':'ss,SSS for OOo 1
271
            return new FormatGroup(xmlDF, createDateFormat("yyyy-MM-dd'T'HH':'mm':'ss", dateConf), createDateFormat("yyyy-MM-dd", dateConf));
275
            return new FormatGroup(xmlDF, createDateFormat("yyyy-MM-dd'T'HH':'mm':'ss", dateConf), createDateFormat("yyyy-MM-dd", dateConf));
272
        }
276
        }
273
    }
277
    }
274
 
278
 
275
    static private synchronized final void setDateConfig(final DateConfig newVal) {
279
    static private synchronized final void setDateConfig(final DateConfig newVal) {
276
        if (!newVal.equals(DATE_CONFIG)) {
280
        if (!newVal.equals(DATE_CONFIG)) {
277
            DATE_CONFIG = newVal;
281
            DATE_CONFIG = newVal;
278
            updateFormat();
282
            updateFormat();
279
        }
283
        }
280
    }
284
    }
281
 
285
 
282
    /**
286
    /**
283
     * Set the framework default time zone. Pass <code>null</code> to always use the VM default
287
     * Set the framework default time zone. Pass <code>null</code> to always use the VM default
284
     * (passing {@link TimeZone#getDefault()} would set the value once and for all and wouldn't be
288
     * (passing {@link TimeZone#getDefault()} would set the value once and for all and wouldn't be
285
     * changed by {@link TimeZone#setDefault(TimeZone)}).
289
     * changed by {@link TimeZone#setDefault(TimeZone)}).
286
     * 
290
     * 
287
     * @param tz the new default time zone, <code>null</code> to use the VM default.
291
     * @param tz the new default time zone, <code>null</code> to use the VM default.
288
     */
292
     */
289
    static public synchronized final void setTimeZone(final TimeZone tz) {
293
    static public synchronized final void setTimeZone(final TimeZone tz) {
290
        setDateConfig(DATE_CONFIG.setTimeZone(tz));
294
        setDateConfig(DATE_CONFIG.setTimeZone(tz));
291
    }
295
    }
292
 
296
 
293
    /**
297
    /**
294
     * The framework default time zone.
298
     * The framework default time zone.
295
     * 
299
     * 
296
     * @param notNull <code>true</code> if <code>null</code> should be replaced by
300
     * @param notNull <code>true</code> if <code>null</code> should be replaced by
297
     *        {@link TimeZone#getDefault()}.
301
     *        {@link TimeZone#getDefault()}.
298
     * @return the default time zone, can only be <code>null</code> if <code>notNull</code> is
302
     * @return the default time zone, can only be <code>null</code> if <code>notNull</code> is
299
     *         <code>false</code>.
303
     *         <code>false</code>.
300
     */
304
     */
301
    static public synchronized final TimeZone getTimeZone(final boolean notNull) {
305
    static public synchronized final TimeZone getTimeZone(final boolean notNull) {
302
        return DATE_CONFIG.getTimeZone(notNull);
306
        return DATE_CONFIG.getTimeZone(notNull);
303
    }
307
    }
304
 
308
 
305
    /**
309
    /**
306
     * Set the framework default locale. Pass <code>null</code> to always use the VM default
310
     * Set the framework default locale. Pass <code>null</code> to always use the VM default
307
     * (passing {@link Locale#getDefault()} would set the value once and for all and wouldn't be
311
     * (passing {@link Locale#getDefault()} would set the value once and for all and wouldn't be
308
     * changed by {@link Locale#setDefault(Locale)}).
312
     * changed by {@link Locale#setDefault(Locale)}).
309
     * 
313
     * 
310
     * @param locale the new default locale, <code>null</code> to use the VM default.
314
     * @param locale the new default locale, <code>null</code> to use the VM default.
311
     */
315
     */
312
    static public synchronized final void setLocale(final Locale locale) {
316
    static public synchronized final void setLocale(final Locale locale) {
313
        setDateConfig(DATE_CONFIG.setLocale(locale));
317
        setDateConfig(DATE_CONFIG.setLocale(locale));
314
    }
318
    }
315
 
319
 
316
    /**
320
    /**
317
     * The framework default locale.
321
     * The framework default locale.
318
     * 
322
     * 
319
     * @param notNull <code>true</code> if <code>null</code> should be replaced by
323
     * @param notNull <code>true</code> if <code>null</code> should be replaced by
320
     *        {@link Locale#getDefault()}.
324
     *        {@link Locale#getDefault()}.
321
     * @return the default locale, can only be <code>null</code> if <code>notNull</code> is
325
     * @return the default locale, can only be <code>null</code> if <code>notNull</code> is
322
     *         <code>false</code>.
326
     *         <code>false</code>.
323
     */
327
     */
324
    static public synchronized final Locale getLocale(final boolean notNull) {
328
    static public synchronized final Locale getLocale(final boolean notNull) {
325
        return DATE_CONFIG.getLocale(notNull);
329
        return DATE_CONFIG.getLocale(notNull);
326
    }
330
    }
327
 
331
 
328
    /**
332
    /**
329
     * Get the framework default calendar.
333
     * Get the framework default calendar.
330
     * 
334
     * 
331
     * @return the default calendar.
335
     * @return the default calendar.
332
     * @see #getTimeZone(boolean)
336
     * @see #getTimeZone(boolean)
333
     * @see #getLocale(boolean)
337
     * @see #getLocale(boolean)
334
     */
338
     */
335
    static public synchronized final Calendar getCalendar() {
339
    static public synchronized final Calendar getCalendar() {
336
        return DATE_CONFIG.getCalendar();
340
        return DATE_CONFIG.getCalendar();
337
    }
341
    }
338
 
342
 
339
    static public synchronized final void setTimeZoneIgnored(final boolean b) {
343
    static public synchronized final void setTimeZoneIgnored(final boolean b) {
340
        setDateConfig(DATE_CONFIG.setTimeZoneIgnored(b));
344
        setDateConfig(DATE_CONFIG.setTimeZoneIgnored(b));
341
    }
345
    }
342
 
346
 
343
    /**
347
    /**
344
     * Whether to ignore explicit time zone in dates. Prior to 4.1 LibreOffice would ignore explicit
348
     * Whether to ignore explicit time zone in dates. Prior to 4.1 LibreOffice would ignore explicit
345
     * time zones, i.e. "2013-11-15T12:00:00.000" and "2013-11-15T12:00:00.000+01:00" would both
349
     * time zones, i.e. "2013-11-15T12:00:00.000" and "2013-11-15T12:00:00.000+01:00" would both
346
     * parse to noon. As of 4.1 the first one parse to noon, the second one to 11 AM.
350
     * parse to noon. As of 4.1 the first one parse to noon, the second one to 11 AM.
347
     * 
351
     * 
348
     * @return <code>true</code> if the time zone part should be ignored.
352
     * @return <code>true</code> if the time zone part should be ignored.
349
     */
353
     */
350
    static public synchronized final boolean isTimeZoneIgnored() {
354
    static public synchronized final boolean isTimeZoneIgnored() {
351
        return DATE_CONFIG.isTimeZoneIgnored();
355
        return DATE_CONFIG.isTimeZoneIgnored();
352
    }
356
    }
353
 
357
 
354
    /**
358
    /**
355
     * Parse an OpenDocument date value with the framework defaults.
359
     * Parse an OpenDocument date value with the framework defaults.
356
     * 
360
     * 
357
     * @param date the string formatted value.
361
     * @param date the string formatted value.
358
     * @return a calendar with the local time of the passed date.
362
     * @return a calendar with the local time of the passed date.
359
     * @throws ParseException if the value couldn't be parsed.
363
     * @throws ParseException if the value couldn't be parsed.
360
     * @see #parseDateValue(String, TimeZone, Locale, Boolean)
364
     * @see #parseDateValue(String, TimeZone, Locale, Boolean)
361
     */
365
     */
362
    static public synchronized Calendar parseDateValue(final String date) throws ParseException {
366
    static public synchronized Calendar parseDateValue(final String date) throws ParseException {
363
        return parseDateValue(date, null, null, null);
367
        return parseDateValue(date, null, null, null);
364
    }
368
    }
365
 
369
 
366
    /**
370
    /**
367
     * Parse an OpenDocument date value with the passed parameters.
371
     * Parse an OpenDocument date value with the passed parameters.
368
     * 
372
     * 
369
     * @param date the string formatted value.
373
     * @param date the string formatted value.
370
     * @param tz the time zone of the returned calendar, <code>null</code> meaning
374
     * @param tz the time zone of the returned calendar, <code>null</code> meaning
371
     *        {@link #getTimeZone(boolean)}.
375
     *        {@link #getTimeZone(boolean)}.
372
     * @param locale the locale of the returned calendar, <code>null</code> meaning
376
     * @param locale the locale of the returned calendar, <code>null</code> meaning
373
     *        {@link #getLocale(boolean)}.
377
     *        {@link #getLocale(boolean)}.
374
     * @param ignoreTZ whether to ignore the time zone part of <code>part</code>, <code>null</code>
378
     * @param ignoreTZ whether to ignore the time zone part of <code>part</code>, <code>null</code>
375
     *        meaning {@link #isTimeZoneIgnored()}.
379
     *        meaning {@link #isTimeZoneIgnored()}.
376
     * @return a calendar with the local time of the passed date.
380
     * @return a calendar with the local time of the passed date.
377
     * @throws ParseException if the value couldn't be parsed.
381
     * @throws ParseException if the value couldn't be parsed.
378
     */
382
     */
379
    static public synchronized Calendar parseDateValue(final String date, final TimeZone tz, final Locale locale, final Boolean ignoreTZ) throws ParseException {
383
    static public synchronized Calendar parseDateValue(final String date, final TimeZone tz, final Locale locale, final Boolean ignoreTZ) throws ParseException {
380
        final DateConfig conf = new DateConfig(DATE_CONFIG, tz, locale, ignoreTZ);
384
        final DateConfig conf = new DateConfig(DATE_CONFIG, tz, locale, ignoreTZ);
381
        final Object parsed = getFormatParser(conf, false).parseObject(date);
385
        final Object parsed = getFormatParser(conf, false).parseObject(date);
382
        if (parsed instanceof Calendar) {
386
        if (parsed instanceof Calendar) {
383
            // XMLCalendarFormat
387
            // XMLCalendarFormat
384
            return (Calendar) parsed;
388
            return (Calendar) parsed;
385
        } else {
389
        } else {
386
            final Calendar res = conf.getCalendar();
390
            final Calendar res = conf.getCalendar();
387
            if (conf.isTimeZoneIgnored()) {
391
            if (conf.isTimeZoneIgnored()) {
388
                // SimpleDateFormat
392
                // SimpleDateFormat
389
                res.setTime((Date) parsed);
393
                res.setTime((Date) parsed);
390
                return res;
394
                return res;
391
            } else {
395
            } else {
392
                // XMLDateFormat or SimpleDateFormat
396
                // XMLDateFormat or SimpleDateFormat
393
                final Calendar cal = Calendar.getInstance(UTC_TZ);
397
                final Calendar cal = Calendar.getInstance(UTC_TZ);
394
                cal.setTime((Date) parsed);
398
                cal.setTime((Date) parsed);
395
                return TimeUtils.copyLocalTime(cal, res);
399
                return TimeUtils.copyLocalTime(cal, res);
396
            }
400
            }
397
        }
401
        }
398
    }
402
    }
399
}
403
}