View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shardingsphere.db.protocol.firebird.packet.command.query.statement.execute.protocol.util;
19  
20  import lombok.Getter;
21  import lombok.Setter;
22  
23  import java.sql.Timestamp;
24  import java.time.LocalDateTime;
25  
26  /**
27   * Firebird date and time utility class.
28   */
29  @Getter
30  @Setter
31  public final class FirebirdDateTimeUtil {
32      
33      static final int NANOSECONDS_PER_FRACTION = 100 * 1000;
34      
35      static final int FRACTIONS_PER_MILLISECOND = 10;
36      
37      static final int FRACTIONS_PER_SECOND = 1000 * FRACTIONS_PER_MILLISECOND;
38      
39      static final int FRACTIONS_PER_MINUTE = 60 * FRACTIONS_PER_SECOND;
40      
41      static final int FRACTIONS_PER_HOUR = 60 * FRACTIONS_PER_MINUTE;
42      
43      private int year;
44      
45      private int month;
46      
47      private int day;
48      
49      private int hour;
50      
51      private int minute;
52      
53      private int second;
54      
55      private int fractions;
56      
57      public FirebirdDateTimeUtil(final LocalDateTime localDateTime) {
58          year = localDateTime.getYear();
59          month = localDateTime.getMonthValue();
60          day = localDateTime.getDayOfMonth();
61          hour = localDateTime.getHour();
62          minute = localDateTime.getMinute();
63          second = localDateTime.getSecond();
64          fractions = (localDateTime.getNano() / NANOSECONDS_PER_FRACTION) % FRACTIONS_PER_SECOND;
65      }
66      
67      public FirebirdDateTimeUtil() {
68          year = 0;
69          month = 1;
70          day = 1;
71          hour = 0;
72          minute = 0;
73          second = 0;
74          fractions = 0;
75      }
76      
77      /**
78       * Get encoded date value.
79       *
80       * @return encoded date as integer
81       */
82      public int getEncodedDate() {
83          int cpMonth = month;
84          int cpYear = year;
85          if (cpMonth > 2) {
86              cpMonth -= 3;
87          } else {
88              cpMonth += 9;
89              cpYear -= 1;
90          }
91          int c = cpYear / 100;
92          int ya = cpYear - 100 * c;
93          return convertDate(c, ya, cpMonth);
94      }
95      
96      /**
97       * Encode {@link LocalDateTime} to an integer date representation.
98       *
99       * @param localDateTime the local date-time to encode
100      * @return encoded date as integer
101      */
102     public static int getEncodedDate(final LocalDateTime localDateTime) {
103         return new FirebirdDateTimeUtil(localDateTime).getEncodedDate();
104     }
105     
106     private int convertDate(final int c, final int ya, final int cpMonth) {
107         return (146097 * c) / 4
108                 + (1461 * ya) / 4
109                 + (153 * cpMonth + 2) / 5
110                 + day + 1721119 - 2400001;
111     }
112     
113     /**
114      * Decode encoded date and set internal year, month, and day fields.
115      *
116      * @param encodedDate encoded date as integer
117      * @return this instance with updated date fields
118      */
119     public FirebirdDateTimeUtil setDate(final int encodedDate) {
120         int sqldate = encodedDate - 1721119 + 2400001;
121         int century = (4 * sqldate - 1) / 146097;
122         sqldate = 4 * sqldate - 1 - 146097 * century;
123         day = sqldate / 4;
124         sqldate = (4 * day + 3) / 1461;
125         day = 4 * day + 3 - 1461 * sqldate;
126         day = (day + 5) / 5;
127         month = (5 * day - 3) / 153;
128         day = 5 * day - 3 - 153 * month;
129         day = (day + 5) / 5;
130         year = 100 * century + sqldate;
131         if (month < 10) {
132             month += 3;
133         } else {
134             month -= 9;
135             year += 1;
136         }
137         return this;
138     }
139     
140     public int getEncodedTime() {
141         return hour * FRACTIONS_PER_HOUR
142                 + minute * FRACTIONS_PER_MINUTE
143                 + second * FRACTIONS_PER_SECOND
144                 + fractions;
145     }
146     
147     /**
148      * Decode encoded time and set internal hour, minute, second, and fraction fields.
149      *
150      * @param encodedTime encoded time as integer
151      * @return this instance with updated time fields
152      */
153     public FirebirdDateTimeUtil setTime(final int encodedTime) {
154         int fractionsInDay = encodedTime;
155         hour = fractionsInDay / FRACTIONS_PER_HOUR;
156         fractionsInDay -= hour * FRACTIONS_PER_HOUR;
157         minute = fractionsInDay / FRACTIONS_PER_MINUTE;
158         fractionsInDay -= minute * FRACTIONS_PER_MINUTE;
159         second = fractionsInDay / FRACTIONS_PER_SECOND;
160         fractions = fractionsInDay - second * FRACTIONS_PER_SECOND;
161         return this;
162     }
163     
164     /**
165      * Convert the internal date-time fields to a {@link Timestamp}.
166      *
167      * @return timestamp representation of the current date-time fields
168      */
169     public Timestamp asTimestamp() {
170         return Timestamp.valueOf(LocalDateTime.of(year, month, day, hour, minute, second, fractions));
171     }
172     
173     /**
174      * Convert encoded date value to {@link Timestamp}.
175      *
176      * @param encodedDate encoded date as integer
177      * @return timestamp representation of the encoded date
178      */
179     public static Timestamp getDate(final int encodedDate) {
180         return new FirebirdDateTimeUtil().setDate(encodedDate).asTimestamp();
181     }
182     
183     /**
184      * Convert encoded time value to {@link Timestamp}.
185      *
186      * @param encodedTime encoded time as integer
187      * @return timestamp representation of the encoded time
188      */
189     public static Timestamp getTime(final int encodedTime) {
190         return new FirebirdDateTimeUtil().setTime(encodedTime).asTimestamp();
191     }
192     
193     /**
194      * Convert encoded date and time values to {@link Timestamp}.
195      *
196      * @param encodedDate encoded date as integer
197      * @param encodedTime encoded time as integer
198      * @return timestamp representation of the encoded date and time
199      */
200     public static Timestamp getDateTime(final int encodedDate, final int encodedTime) {
201         return new FirebirdDateTimeUtil().setDate(encodedDate).setTime(encodedTime).asTimestamp();
202     }
203     
204     /**
205      * Convert encoded date and time values with offset to {@link Timestamp}.
206      *
207      * @param encodedDate encoded date as integer
208      * @param encodedTime encoded time as integer
209      * @param offset offset value in minutes or seconds (pending implementation details)
210      * @return timestamp representation of the encoded date and time with offset
211      */
212     public static Timestamp getDateTimeWithOffset(final int encodedDate, final int encodedTime, final int offset) {
213         // TODO add time zone support
214         return new FirebirdDateTimeUtil().setDate(encodedDate).setTime(encodedTime).asTimestamp();
215     }
216 }