View Javadoc
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 }