1 /*
2 *
3 * The DbUnit Database Testing Framework
4 * Copyright (C)2002-2019, DbUnit.org
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21 package org.dbunit.ext.mssql;
22
23 import java.sql.PreparedStatement;
24 import java.sql.ResultSet;
25 import java.sql.SQLException;
26 import java.time.DateTimeException;
27 import java.time.OffsetDateTime;
28 import java.time.format.DateTimeFormatter;
29 import java.time.format.DateTimeParseException;
30 import java.time.temporal.TemporalAccessor;
31
32 import org.dbunit.dataset.datatype.AbstractDataType;
33 import org.dbunit.dataset.datatype.TypeCastException;
34
35 /**
36 * @author Richard DiCroce
37 * @since 2.7.0
38 */
39 public class DateTimeOffsetType extends AbstractDataType
40 {
41 public static final int TYPE = -155;
42
43 /** @see https://docs.microsoft.com/en-us/sql/t-sql/data-types/datetimeoffset-transact-sql?view=sql-server-2017 */
44 private static final DateTimeFormatter SQL_SERVER_FORMAT =
45 DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.n] xxx");
46
47 public DateTimeOffsetType()
48 {
49 super("datetimeoffset", TYPE, OffsetDateTime.class, false);
50 }
51
52 @Override
53 public Object typeCast(final Object value) throws TypeCastException
54 {
55 if (value == null || value instanceof OffsetDateTime)
56 {
57 return value;
58 }
59
60 // if a java.time type, attempt a direct conversion
61 // if that fails, there's not enough info to do the conversion, so don't
62 // bother trying string parse
63 if (value instanceof TemporalAccessor)
64 {
65 try
66 {
67 return OffsetDateTime.from((TemporalAccessor) value);
68 } catch (final DateTimeException e)
69 {
70 throw new TypeCastException(e);
71 }
72 }
73
74 final String valueAsString = value.toString();
75
76 // attempt to parse using ISO 8601 format
77 DateTimeParseException isoParseException;
78 try
79 {
80 return OffsetDateTime.parse(valueAsString);
81 } catch (final DateTimeParseException e)
82 {
83 isoParseException = e;
84 }
85
86 // attempt to parse using SQL Server's ISO-like format
87 try
88 {
89 return OffsetDateTime.parse(valueAsString, SQL_SERVER_FORMAT);
90 } catch (final DateTimeParseException e)
91 {
92 final TypeCastException toThrow = new TypeCastException(
93 "Could not parse value using ISO 8601 or SQL Server's format",
94 e);
95 toThrow.addSuppressed(isoParseException);
96 throw toThrow;
97 }
98 }
99
100 @Override
101 public Object getSqlValue(final int column, final ResultSet resultSet)
102 throws SQLException, TypeCastException
103 {
104 return resultSet.getObject(column, OffsetDateTime.class);
105 }
106
107 @Override
108 public void setSqlValue(final Object value, final int column,
109 final PreparedStatement statement)
110 throws SQLException, TypeCastException
111 {
112 statement.setObject(column, typeCast(value));
113 }
114
115 @Override
116 public boolean isDateTime()
117 {
118 return true;
119 }
120 }