Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <connectivity/dbconversion.hxx>
21 : #include <connectivity/dbcharset.hxx>
22 : #include <osl/diagnose.h>
23 : #include <com/sun/star/sdbc/SQLException.hpp>
24 : #include <com/sun/star/util/Date.hpp>
25 : #include <com/sun/star/util/Time.hpp>
26 : #include <com/sun/star/util/DateTime.hpp>
27 : #include <rtl/ustrbuf.hxx>
28 : #include <rtl/math.hxx>
29 : #include <unotools/datetime.hxx>
30 : #include <sstream>
31 : #include <iomanip>
32 :
33 : #define MAX_DAYS 3636532
34 :
35 : namespace
36 : {
37 : const sal_Int64 nanoSecInSec = 1000000000;
38 : const sal_Int16 secInMin = 60;
39 : const sal_Int16 minInHour = 60;
40 :
41 : const sal_Int64 secMask = 1000000000;
42 : const sal_Int64 minMask = 100000000000LL;
43 : const sal_Int64 hourMask = 10000000000000LL;
44 :
45 : const double fNanoSecondsPerDay = nanoSecInSec * secInMin * minInHour * 24.0;
46 : }
47 :
48 :
49 : namespace dbtools
50 : {
51 :
52 :
53 : using namespace ::com::sun::star::uno;
54 : using namespace ::com::sun::star::util;
55 : using namespace ::com::sun::star::sdb;
56 : using namespace ::com::sun::star::sdbc;
57 : using namespace ::com::sun::star::lang;
58 : using namespace ::com::sun::star::beans;
59 :
60 :
61 :
62 163 : css::util::Date DBTypeConversion::getStandardDate()
63 : {
64 163 : static css::util::Date STANDARD_DB_DATE(1,1,1900);
65 163 : return STANDARD_DB_DATE;
66 : }
67 :
68 0 : OUString DBTypeConversion::toDateString(const css::util::Date& rDate)
69 : {
70 : sal_Char s[11];
71 : snprintf(s,
72 : sizeof(s),
73 : "%04d-%02d-%02d",
74 : (int)rDate.Year,
75 : (int)rDate.Month,
76 0 : (int)rDate.Day);
77 0 : s[10] = 0;
78 0 : return OUString::createFromAscii(s);
79 : }
80 :
81 0 : OUString DBTypeConversion::toTimeStringS(const css::util::Time& rTime)
82 : {
83 0 : std::ostringstream ostr;
84 : using std::setw;
85 0 : ostr.fill('0');
86 0 : ostr << setw(2) << rTime.Hours << ":"
87 0 : << setw(2) << rTime.Minutes << ":"
88 0 : << setw(2) << rTime.Seconds;
89 0 : return OUString::createFromAscii(ostr.str().c_str());
90 : }
91 :
92 0 : OUString DBTypeConversion::toTimeString(const css::util::Time& rTime)
93 : {
94 0 : std::ostringstream ostr;
95 : using std::setw;
96 0 : ostr.fill('0');
97 0 : ostr << setw(2) << rTime.Hours << ":"
98 0 : << setw(2) << rTime.Minutes << ":"
99 0 : << setw(2) << rTime.Seconds << "."
100 0 : << setw(9) << rTime.NanoSeconds;
101 0 : return OUString::createFromAscii(ostr.str().c_str());
102 : }
103 :
104 0 : OUString DBTypeConversion::toDateTimeString(const css::util::DateTime& _rDateTime)
105 : {
106 0 : css::util::Date aDate(_rDateTime.Day,_rDateTime.Month,_rDateTime.Year);
107 0 : OUStringBuffer aTemp(toDateString(aDate));
108 0 : aTemp.appendAscii(" ");
109 : css::util::Time const aTime(_rDateTime.NanoSeconds, _rDateTime.Seconds,
110 0 : _rDateTime.Minutes, _rDateTime.Hours, _rDateTime.IsUTC);
111 0 : aTemp.append( toTimeString(aTime) );
112 0 : return aTemp.makeStringAndClear();
113 : }
114 :
115 0 : css::util::Date DBTypeConversion::toDate(sal_Int32 _nVal)
116 : {
117 0 : css::util::Date aReturn;
118 0 : aReturn.Day = (sal_uInt16)(_nVal % 100);
119 0 : aReturn.Month = (sal_uInt16)((_nVal / 100) % 100);
120 0 : aReturn.Year = (sal_uInt16)(_nVal / 10000);
121 0 : return aReturn;
122 : }
123 :
124 :
125 0 : css::util::Time DBTypeConversion::toTime(sal_Int64 _nVal)
126 : {
127 0 : css::util::Time aReturn;
128 0 : sal_uInt64 unVal = static_cast<sal_uInt64>(_nVal >= 0 ? _nVal : -_nVal);
129 0 : aReturn.Hours = unVal / hourMask;
130 0 : aReturn.Minutes = (unVal / minMask) % 100;
131 0 : aReturn.Seconds = (unVal / secMask) % 100;
132 0 : aReturn.NanoSeconds = unVal % secMask;
133 0 : return aReturn;
134 : }
135 :
136 0 : sal_Int64 DBTypeConversion::getNsFromTime(const css::util::Time& rVal)
137 : {
138 0 : sal_Int32 nHour = rVal.Hours;
139 0 : sal_Int32 nMin = rVal.Minutes;
140 0 : sal_Int32 nSec = rVal.Seconds;
141 0 : sal_Int32 nNanoSec = rVal.NanoSeconds;
142 :
143 0 : return nNanoSec +
144 0 : nSec * nanoSecInSec +
145 0 : nMin * (secInMin * nanoSecInSec) +
146 0 : nHour * (minInHour * secInMin * nanoSecInSec);
147 : }
148 :
149 :
150 : static const sal_Int32 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
151 : 31, 31, 30, 31, 30, 31 };
152 :
153 :
154 0 : static bool implIsLeapYear(sal_Int32 _nYear)
155 : {
156 0 : return ( ( ((_nYear % 4) == 0)
157 0 : && ((_nYear % 100) != 0)
158 : )
159 : )
160 0 : || ((_nYear % 400) == 0)
161 : ;
162 : }
163 :
164 :
165 0 : static sal_Int32 implDaysInMonth(sal_Int32 _nMonth, sal_Int32 _nYear)
166 : {
167 : OSL_ENSURE(_nMonth > 0 && _nMonth < 13,"Month as invalid value!");
168 0 : if (_nMonth != 2)
169 0 : return aDaysInMonth[_nMonth-1];
170 : else
171 : {
172 0 : if (implIsLeapYear(_nYear))
173 0 : return aDaysInMonth[_nMonth-1] + 1;
174 : else
175 0 : return aDaysInMonth[_nMonth-1];
176 : }
177 : }
178 :
179 :
180 0 : static sal_Int32 implRelativeToAbsoluteNull(const css::util::Date& _rDate)
181 : {
182 0 : sal_Int32 nDays = 0;
183 :
184 : // ripped this code from the implementation of tools::Date
185 0 : sal_Int32 nNormalizedYear = _rDate.Year - 1;
186 0 : nDays = nNormalizedYear * 365;
187 : // leap years
188 0 : nDays += (nNormalizedYear / 4) - (nNormalizedYear / 100) + (nNormalizedYear / 400);
189 :
190 0 : for (sal_Int32 i = 1; i < _rDate.Month; ++i)
191 0 : nDays += implDaysInMonth(i, _rDate.Year);
192 :
193 0 : nDays += _rDate.Day;
194 0 : return nDays;
195 : }
196 :
197 0 : static void implBuildFromRelative( sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_Int16& rYear)
198 : {
199 : sal_Int32 nTempDays;
200 0 : sal_Int32 i = 0;
201 : bool bCalc;
202 :
203 0 : do
204 : {
205 0 : nTempDays = nDays;
206 0 : rYear = (sal_uInt16)((nTempDays / 365) - i);
207 0 : nTempDays -= (rYear-1) * 365;
208 0 : nTempDays -= ((rYear-1) / 4) - ((rYear-1) / 100) + ((rYear-1) / 400);
209 0 : bCalc = false;
210 0 : if ( nTempDays < 1 )
211 : {
212 0 : i++;
213 0 : bCalc = true;
214 : }
215 : else
216 : {
217 0 : if ( nTempDays > 365 )
218 : {
219 0 : if ( (nTempDays != 366) || !implIsLeapYear( rYear ) )
220 : {
221 0 : i--;
222 0 : bCalc = true;
223 : }
224 : }
225 : }
226 : }
227 : while ( bCalc );
228 :
229 0 : rMonth = 1;
230 0 : while ( nTempDays > implDaysInMonth( rMonth, rYear ) )
231 : {
232 0 : nTempDays -= implDaysInMonth( rMonth, rYear );
233 0 : rMonth++;
234 : }
235 0 : rDay = (sal_uInt16)nTempDays;
236 0 : }
237 :
238 0 : sal_Int32 DBTypeConversion::toDays(const css::util::Date& _rVal, const css::util::Date& _rNullDate)
239 : {
240 0 : return implRelativeToAbsoluteNull(_rVal) - implRelativeToAbsoluteNull(_rNullDate);
241 : }
242 :
243 :
244 0 : double DBTypeConversion::toDouble(const css::util::Date& rVal, const css::util::Date& _rNullDate)
245 : {
246 0 : return (double)toDays(rVal, _rNullDate);
247 : }
248 :
249 :
250 0 : double DBTypeConversion::toDouble(const css::util::Time& rVal)
251 : {
252 0 : return (double)getNsFromTime(rVal) / fNanoSecondsPerDay;
253 : }
254 :
255 :
256 0 : double DBTypeConversion::toDouble(const css::util::DateTime& _rVal, const css::util::Date& _rNullDate)
257 : {
258 0 : sal_Int64 nTime = toDays(css::util::Date(_rVal.Day, _rVal.Month, _rVal.Year), _rNullDate);
259 0 : css::util::Time aTimePart;
260 :
261 0 : aTimePart.Hours = _rVal.Hours;
262 0 : aTimePart.Minutes = _rVal.Minutes;
263 0 : aTimePart.Seconds = _rVal.Seconds;
264 0 : aTimePart.NanoSeconds = _rVal.NanoSeconds;
265 :
266 0 : return ((double)nTime) + toDouble(aTimePart);
267 : }
268 :
269 0 : static void addDays(sal_Int32 nDays, css::util::Date& _rDate)
270 : {
271 0 : sal_Int32 nTempDays = implRelativeToAbsoluteNull( _rDate );
272 :
273 0 : nTempDays += nDays;
274 0 : if ( nTempDays > MAX_DAYS )
275 : {
276 0 : _rDate.Day = 31;
277 0 : _rDate.Month = 12;
278 0 : _rDate.Year = 9999;
279 : }
280 0 : else if ( nTempDays <= 0 )
281 : {
282 0 : _rDate.Day = 1;
283 0 : _rDate.Month = 1;
284 0 : _rDate.Year = 00;
285 : }
286 : else
287 0 : implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year );
288 0 : }
289 :
290 0 : static void subDays( sal_Int32 nDays, css::util::Date& _rDate )
291 : {
292 0 : sal_Int32 nTempDays = implRelativeToAbsoluteNull( _rDate );
293 :
294 0 : nTempDays -= nDays;
295 0 : if ( nTempDays > MAX_DAYS )
296 : {
297 0 : _rDate.Day = 31;
298 0 : _rDate.Month = 12;
299 0 : _rDate.Year = 9999;
300 : }
301 0 : else if ( nTempDays <= 0 )
302 : {
303 0 : _rDate.Day = 1;
304 0 : _rDate.Month = 1;
305 0 : _rDate.Year = 00;
306 : }
307 : else
308 0 : implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year );
309 0 : }
310 :
311 0 : css::util::Date DBTypeConversion::toDate(double dVal, const css::util::Date& _rNullDate)
312 : {
313 0 : css::util::Date aRet = _rNullDate;
314 :
315 0 : if (dVal >= 0)
316 0 : addDays((sal_Int32)dVal,aRet);
317 : else
318 0 : subDays((sal_uInt32)(-dVal),aRet);
319 : // x -= (sal_uInt32)(-nDays);
320 :
321 0 : return aRet;
322 : }
323 :
324 0 : css::util::Time DBTypeConversion::toTime(double dVal, short nDigits)
325 : {
326 0 : sal_Int32 nDays = (sal_Int32)dVal;
327 : sal_Int64 nNS;
328 : {
329 0 : double fSeconds((dVal - (double)nDays) * (fNanoSecondsPerDay / nanoSecInSec));
330 0 : fSeconds = ::rtl::math::round( fSeconds, nDigits );
331 0 : nNS = fSeconds * nanoSecInSec;
332 : }
333 :
334 : sal_Int16 nSign;
335 0 : if ( nNS < 0 )
336 : {
337 0 : nNS *= -1;
338 0 : nSign = -1;
339 : }
340 : else
341 0 : nSign = 1;
342 :
343 0 : css::util::Time xRet;
344 : // normalize time
345 : // we have to sal_Int32 here because otherwise we get an overflow
346 0 : sal_Int64 nNanoSeconds = nNS;
347 0 : sal_Int32 nSeconds = nNanoSeconds / nanoSecInSec;
348 0 : sal_Int32 nMinutes = nSeconds / secInMin;
349 :
350 0 : xRet.NanoSeconds = nNanoSeconds % nanoSecInSec;
351 0 : xRet.Seconds = nSeconds % secInMin;
352 0 : xRet.Hours = nMinutes / minInHour;
353 0 : xRet.Minutes = nMinutes % minInHour;
354 :
355 : // assemble time
356 0 : sal_Int64 nTime = nSign *
357 0 : (xRet.NanoSeconds +
358 0 : xRet.Seconds * secMask +
359 0 : xRet.Minutes * minMask +
360 0 : xRet.Hours * hourMask);
361 :
362 0 : if(nTime < 0)
363 : {
364 0 : xRet.NanoSeconds = nanoSecInSec-1;
365 0 : xRet.Seconds = secInMin-1;
366 0 : xRet.Minutes = minInHour-1;
367 0 : xRet.Hours = 23;
368 : }
369 0 : return xRet;
370 : }
371 :
372 0 : css::util::DateTime DBTypeConversion::toDateTime(double dVal, const css::util::Date& _rNullDate)
373 : {
374 0 : css::util::Date aDate = toDate(dVal, _rNullDate);
375 : // there is not enough precision in a double to have both a date
376 : // and a time up to nanoseconds -> limit to microseconds to have
377 : // correct rounding, that is e.g. 13:00:00.000000000 instead of
378 : // 12:59:59.999999790
379 0 : css::util::Time aTime = toTime(dVal, 6);
380 :
381 0 : css::util::DateTime xRet;
382 :
383 0 : xRet.Day = aDate.Day;
384 0 : xRet.Month = aDate.Month;
385 0 : xRet.Year = aDate.Year;
386 :
387 0 : xRet.NanoSeconds = aTime.NanoSeconds;
388 0 : xRet.Minutes = aTime.Minutes;
389 0 : xRet.Seconds = aTime.Seconds;
390 0 : xRet.Hours = aTime.Hours;
391 :
392 :
393 0 : return xRet;
394 : }
395 :
396 0 : css::util::Date DBTypeConversion::toDate(const OUString& _sSQLString)
397 : {
398 : // get the token out of a string
399 : static sal_Unicode sDateSep = '-';
400 :
401 0 : sal_Int32 nIndex = 0;
402 0 : sal_uInt16 nYear = 0,
403 0 : nMonth = 0,
404 0 : nDay = 0;
405 0 : nYear = (sal_uInt16)_sSQLString.getToken(0,sDateSep,nIndex).toInt32();
406 0 : if(nIndex != -1)
407 : {
408 0 : nMonth = (sal_uInt16)_sSQLString.getToken(0,sDateSep,nIndex).toInt32();
409 0 : if(nIndex != -1)
410 0 : nDay = (sal_uInt16)_sSQLString.getToken(0,sDateSep,nIndex).toInt32();
411 : }
412 :
413 0 : return css::util::Date(nDay,nMonth,nYear);
414 : }
415 :
416 :
417 0 : css::util::DateTime DBTypeConversion::toDateTime(const OUString& _sSQLString)
418 : {
419 : //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Timestamp.html#valueOf(java.lang.String)
420 : //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Date.html#valueOf(java.lang.String)
421 : //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Time.html#valueOf(java.lang.String)
422 :
423 : // the date part
424 0 : css::util::Date aDate = toDate(_sSQLString);
425 0 : css::util::Time aTime;
426 0 : sal_Int32 nSeparation = _sSQLString.indexOf( ' ' );
427 0 : if ( -1 != nSeparation )
428 : {
429 0 : const sal_Unicode *p = _sSQLString.getStr() + nSeparation;
430 0 : const sal_Unicode *const begin = p;
431 0 : while (isspace(*p)) { ++p; }
432 0 : nSeparation += p - begin;
433 0 : aTime = toTime( _sSQLString.copy( nSeparation ) );
434 : }
435 :
436 : return css::util::DateTime(aTime.NanoSeconds, aTime.Seconds, aTime.Minutes, aTime.Hours,
437 0 : aDate.Day, aDate.Month, aDate.Year, false);
438 : }
439 :
440 :
441 0 : css::util::Time DBTypeConversion::toTime(const OUString& _sSQLString)
442 : {
443 0 : css::util::Time aTime;
444 0 : ::utl::ISO8601parseTime(_sSQLString, aTime);
445 0 : return aTime;
446 : }
447 :
448 :
449 : } // namespace dbtools
450 :
451 :
452 :
453 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|