update credits
[LibreOffice.git] / connectivity / source / commontools / dbconversion.cxx
blob15276a6294d333cabfe2112117822d592e4bf1a0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <connectivity/dbconversion.hxx>
21 #include <connectivity/dbcharset.hxx>
22 #include <osl/diagnose.h>
23 #ifndef _INC_STDIO
24 #include <stdio.h>
25 #endif
26 #include <com/sun/star/sdbc/SQLException.hpp>
27 #include <com/sun/star/util/Date.hpp>
28 #include <com/sun/star/util/Time.hpp>
29 #include <com/sun/star/util/DateTime.hpp>
30 #include <rtl/ustrbuf.hxx>
31 #include <rtl/math.hxx>
32 #include <unotools/datetime.hxx>
33 #include <sstream>
34 #include <iomanip>
36 #define MAX_DAYS 3636532
38 namespace
40 const double fMilliSecondsPerDay = 86400000.0;
41 const sal_Int64 nanoSecInSec = 1000000000;
42 const sal_Int16 secInMin = 60;
43 const sal_Int16 minInHour = 60;
45 const sal_Int64 secMask = 1000000000;
46 const sal_Int64 minMask = 100000000000LL;
47 const sal_Int64 hourMask = 10000000000000LL;
49 const double fNanoSecondsPerDay = nanoSecInSec * secInMin * minInHour * 24.0;
52 //.........................................................................
53 namespace dbtools
55 //.........................................................................
58 using namespace ::comphelper;
59 using namespace ::com::sun::star::uno;
60 using namespace ::com::sun::star::util;
61 namespace utl = ::com::sun::star::util;
62 using namespace ::com::sun::star::sdb;
63 using namespace ::com::sun::star::sdbc;
64 using namespace ::com::sun::star::lang;
65 using namespace ::com::sun::star::beans;
68 //------------------------------------------------------------------------------
69 ::com::sun::star::util::Date DBTypeConversion::getStandardDate()
71 static ::com::sun::star::util::Date STANDARD_DB_DATE(1,1,1900);
72 return STANDARD_DB_DATE;
74 //------------------------------------------------------------------------------
75 OUString DBTypeConversion::toDateString(const utl::Date& rDate)
77 sal_Char s[11];
78 snprintf(s,
79 sizeof(s),
80 "%04d-%02d-%02d",
81 (int)rDate.Year,
82 (int)rDate.Month,
83 (int)rDate.Day);
84 s[10] = 0;
85 return OUString::createFromAscii(s);
87 //------------------------------------------------------------------
88 OUString DBTypeConversion::toTimeString(const utl::Time& rTime)
90 std::ostringstream ostr;
91 using std::setw;
92 ostr.fill('0');
93 ostr << setw(2) << rTime.Hours << ":"
94 << setw(2) << rTime.Minutes << ":"
95 << setw(2) << rTime.Seconds << "."
96 << setw(9) << rTime.NanoSeconds;
97 return OUString::createFromAscii(ostr.str().c_str());
100 //------------------------------------------------------------------
101 OUString DBTypeConversion::toDateTimeString(const utl::DateTime& _rDateTime)
103 utl::Date aDate(_rDateTime.Day,_rDateTime.Month,_rDateTime.Year);
104 OUStringBuffer aTemp(toDateString(aDate));
105 aTemp.appendAscii(" ");
106 utl::Time const aTime(_rDateTime.NanoSeconds, _rDateTime.Seconds,
107 _rDateTime.Minutes, _rDateTime.Hours, _rDateTime.IsUTC);
108 aTemp.append( toTimeString(aTime) );
109 return aTemp.makeStringAndClear();
111 //------------------------------------------------------------------------------
112 utl::Date DBTypeConversion::toDate(sal_Int32 _nVal)
114 utl::Date aReturn;
115 aReturn.Day = (sal_uInt16)(_nVal % 100);
116 aReturn.Month = (sal_uInt16)((_nVal / 100) % 100);
117 aReturn.Year = (sal_uInt16)(_nVal / 10000);
118 return aReturn;
121 //------------------------------------------------------------------------------
122 utl::Time DBTypeConversion::toTime(sal_Int64 _nVal)
124 utl::Time aReturn;
125 sal_uInt64 unVal = static_cast<sal_uInt64>(_nVal >= 0 ? _nVal : -_nVal);
126 aReturn.Hours = unVal / hourMask;
127 aReturn.Minutes = (unVal / minMask) % 100;
128 aReturn.Seconds = (unVal / secMask) % 100;
129 aReturn.NanoSeconds = unVal % secMask;
130 return aReturn;
133 //------------------------------------------------------------------------------
134 sal_Int32 DBTypeConversion::toINT32(const utl::Date& rVal)
136 return ((sal_Int32)(rVal.Day%100)) +
137 (((sal_Int32)(rVal.Month%100))*100) +
138 (((sal_Int32) rVal.Year%10000)*10000);
141 //------------------------------------------------------------------------------
142 sal_Int64 DBTypeConversion::toINT64(const utl::Time& rVal)
144 // normalize time
145 sal_Int32 nSeconds = rVal.Seconds + rVal.NanoSeconds / nanoSecInSec;
146 sal_Int32 nNanoSeconds = rVal.NanoSeconds % nanoSecInSec;
147 sal_Int32 nMinutes = rVal.Minutes + nSeconds / secInMin;
148 nSeconds = nSeconds % secInMin;
149 sal_Int32 nHours = rVal.Hours + nMinutes / minInHour;
150 nMinutes = nMinutes % minInHour;
152 // assemble time
153 return nNanoSeconds +
154 nSeconds * secMask +
155 nMinutes * minMask +
156 nHours * hourMask;
159 //------------------------------------------------------------------------------
160 sal_Int32 DBTypeConversion::getMsFromTime(const utl::Time& rVal)
162 sal_Int32 nHour = rVal.Hours;
163 sal_Int32 nMin = rVal.Minutes;
164 sal_Int32 nSec = rVal.Seconds;
165 sal_Int32 nNanoSec = rVal.NanoSeconds;
167 return ((nHour*3600000)+(nMin*60000)+(nSec*1000)+(nNanoSec/1000000));
170 //------------------------------------------------------------------------------
171 sal_Int64 DBTypeConversion::getNsFromTime(const utl::Time& rVal)
173 sal_Int32 nHour = rVal.Hours;
174 sal_Int32 nMin = rVal.Minutes;
175 sal_Int32 nSec = rVal.Seconds;
176 sal_Int32 nNanoSec = rVal.NanoSeconds;
178 return nNanoSec +
179 nSec * nanoSecInSec +
180 nMin * (secInMin * nanoSecInSec) +
181 nHour * (minInHour * secInMin * nanoSecInSec);
184 //------------------------------------------------------------------------------
185 static sal_Int32 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
186 31, 31, 30, 31, 30, 31 };
188 //------------------------------------------------------------------------------
189 static sal_Bool implIsLeapYear(sal_Int32 _nYear)
191 return ( ( ((_nYear % 4) == 0)
192 && ((_nYear % 100) != 0)
195 || ((_nYear % 400) == 0)
199 //------------------------------------------------------------------------------
200 static sal_Int32 implDaysInMonth(sal_Int32 _nMonth, sal_Int32 _nYear)
202 OSL_ENSURE(_nMonth > 0 && _nMonth < 13,"Month as invalid value!");
203 if (_nMonth != 2)
204 return aDaysInMonth[_nMonth-1];
205 else
207 if (implIsLeapYear(_nYear))
208 return aDaysInMonth[_nMonth-1] + 1;
209 else
210 return aDaysInMonth[_nMonth-1];
214 //------------------------------------------------------------------------------
215 static sal_Int32 implRelativeToAbsoluteNull(const utl::Date& _rDate)
217 sal_Int32 nDays = 0;
219 // ripped this code from the implementation of tools::Date
220 sal_Int32 nNormalizedYear = _rDate.Year - 1;
221 nDays = nNormalizedYear * 365;
222 // leap years
223 nDays += (nNormalizedYear / 4) - (nNormalizedYear / 100) + (nNormalizedYear / 400);
225 for (sal_Int32 i = 1; i < _rDate.Month; ++i)
226 nDays += implDaysInMonth(i, _rDate.Year);
228 nDays += _rDate.Day;
229 return nDays;
231 //------------------------------------------------------------------------------
232 static void implBuildFromRelative( sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_Int16& rYear)
234 sal_Int32 nTempDays;
235 sal_Int32 i = 0;
236 sal_Bool bCalc;
240 nTempDays = nDays;
241 rYear = (sal_uInt16)((nTempDays / 365) - i);
242 nTempDays -= (rYear-1) * 365;
243 nTempDays -= ((rYear-1) / 4) - ((rYear-1) / 100) + ((rYear-1) / 400);
244 bCalc = sal_False;
245 if ( nTempDays < 1 )
247 i++;
248 bCalc = sal_True;
250 else
252 if ( nTempDays > 365 )
254 if ( (nTempDays != 366) || !implIsLeapYear( rYear ) )
256 i--;
257 bCalc = sal_True;
262 while ( bCalc );
264 rMonth = 1;
265 while ( nTempDays > implDaysInMonth( rMonth, rYear ) )
267 nTempDays -= implDaysInMonth( rMonth, rYear );
268 rMonth++;
270 rDay = (sal_uInt16)nTempDays;
272 //------------------------------------------------------------------------------
273 sal_Int32 DBTypeConversion::toDays(const utl::Date& _rVal, const utl::Date& _rNullDate)
275 return implRelativeToAbsoluteNull(_rVal) - implRelativeToAbsoluteNull(_rNullDate);
278 //------------------------------------------------------------------------------
279 double DBTypeConversion::toDouble(const utl::Date& rVal, const utl::Date& _rNullDate)
281 return (double)toDays(rVal, _rNullDate);
284 //------------------------------------------------------------------------------
285 double DBTypeConversion::toDouble(const utl::Time& rVal)
287 return (double)getNsFromTime(rVal) / fNanoSecondsPerDay;
290 //------------------------------------------------------------------------------
291 double DBTypeConversion::toDouble(const utl::DateTime& _rVal, const utl::Date& _rNullDate)
293 sal_Int64 nTime = toDays(utl::Date(_rVal.Day, _rVal.Month, _rVal.Year), _rNullDate);
294 utl::Time aTimePart;
296 aTimePart.Hours = _rVal.Hours;
297 aTimePart.Minutes = _rVal.Minutes;
298 aTimePart.Seconds = _rVal.Seconds;
299 aTimePart.NanoSeconds = _rVal.NanoSeconds;
301 return ((double)nTime) + toDouble(aTimePart);
303 // -------------------------------------------------------------------------
304 static void addDays(sal_Int32 nDays, utl::Date& _rDate)
306 sal_Int32 nTempDays = implRelativeToAbsoluteNull( _rDate );
308 nTempDays += nDays;
309 if ( nTempDays > MAX_DAYS )
311 _rDate.Day = 31;
312 _rDate.Month = 12;
313 _rDate.Year = 9999;
315 else if ( nTempDays <= 0 )
317 _rDate.Day = 1;
318 _rDate.Month = 1;
319 _rDate.Year = 00;
321 else
322 implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year );
324 // -----------------------------------------------------------------------
325 static void subDays( sal_Int32 nDays, utl::Date& _rDate )
327 sal_Int32 nTempDays = implRelativeToAbsoluteNull( _rDate );
329 nTempDays -= nDays;
330 if ( nTempDays > MAX_DAYS )
332 _rDate.Day = 31;
333 _rDate.Month = 12;
334 _rDate.Year = 9999;
336 else if ( nTempDays <= 0 )
338 _rDate.Day = 1;
339 _rDate.Month = 1;
340 _rDate.Year = 00;
342 else
343 implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year );
345 // -------------------------------------------------------------------------
346 utl::Date DBTypeConversion::toDate(double dVal, const utl::Date& _rNullDate)
348 utl::Date aRet = _rNullDate;
350 if (dVal >= 0)
351 addDays((sal_Int32)dVal,aRet);
352 else
353 subDays((sal_uInt32)(-dVal),aRet);
354 // x -= (sal_uInt32)(-nDays);
356 return aRet;
358 // -------------------------------------------------------------------------
359 utl::Time DBTypeConversion::toTime(double dVal, short nDigits)
361 sal_Int32 nDays = (sal_Int32)dVal;
362 sal_Int64 nNS;
364 double fSeconds((dVal - (double)nDays) * (fNanoSecondsPerDay / nanoSecInSec));
365 fSeconds = ::rtl::math::round( fSeconds, nDigits );
366 nNS = fSeconds * nanoSecInSec;
369 sal_Int16 nSign;
370 if ( nNS < 0 )
372 nNS *= -1;
373 nSign = -1;
375 else
376 nSign = 1;
378 utl::Time xRet;
379 // normalize time
380 // we have to sal_Int32 here because otherwise we get an overflow
381 sal_Int64 nNanoSeconds = nNS;
382 sal_Int32 nSeconds = nNanoSeconds / nanoSecInSec;
383 sal_Int32 nMinutes = nSeconds / secInMin;
385 xRet.NanoSeconds = nNanoSeconds % nanoSecInSec;
386 xRet.Seconds = nSeconds % secInMin;
387 xRet.Hours = nMinutes / minInHour;
388 xRet.Minutes = nMinutes % minInHour;
390 // assemble time
391 sal_Int64 nTime = nSign *
392 (xRet.NanoSeconds +
393 xRet.Seconds * secMask +
394 xRet.Minutes * minMask +
395 xRet.Hours * hourMask);
397 if(nTime < 0)
399 xRet.NanoSeconds = nanoSecInSec-1;
400 xRet.Seconds = secInMin-1;
401 xRet.Minutes = minInHour-1;
402 xRet.Hours = 23;
404 return xRet;
406 //------------------------------------------------------------------------------
407 utl::DateTime DBTypeConversion::toDateTime(double dVal, const utl::Date& _rNullDate)
409 utl::Date aDate = toDate(dVal, _rNullDate);
410 // there is not enough precision in a double to have both a date
411 // and a time up to nanoseconds -> limit to microseconds to have
412 // correct rounding, that is e.g. 13:00:00.000000000 instead of
413 // 12:59:59.999999790
414 utl::Time aTime = toTime(dVal, 6);
416 utl::DateTime xRet;
418 xRet.Day = aDate.Day;
419 xRet.Month = aDate.Month;
420 xRet.Year = aDate.Year;
422 xRet.NanoSeconds = aTime.NanoSeconds;
423 xRet.Minutes = aTime.Minutes;
424 xRet.Seconds = aTime.Seconds;
425 xRet.Hours = aTime.Hours;
428 return xRet;
430 //------------------------------------------------------------------------------
431 utl::Date DBTypeConversion::toDate(const OUString& _sSQLString)
433 // get the token out of a string
434 static sal_Unicode sDateSep = '-';
436 sal_Int32 nIndex = 0;
437 sal_uInt16 nYear = 0,
438 nMonth = 0,
439 nDay = 0;
440 nYear = (sal_uInt16)_sSQLString.getToken(0,sDateSep,nIndex).toInt32();
441 if(nIndex != -1)
443 nMonth = (sal_uInt16)_sSQLString.getToken(0,sDateSep,nIndex).toInt32();
444 if(nIndex != -1)
445 nDay = (sal_uInt16)_sSQLString.getToken(0,sDateSep,nIndex).toInt32();
448 return utl::Date(nDay,nMonth,nYear);
451 //-----------------------------------------------------------------------------
452 utl::DateTime DBTypeConversion::toDateTime(const OUString& _sSQLString)
454 //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Timestamp.html#valueOf(java.lang.String)
455 //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Date.html#valueOf(java.lang.String)
456 //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Time.html#valueOf(java.lang.String)
458 // the date part
459 utl::Date aDate = toDate(_sSQLString);
460 utl::Time aTime;
461 sal_Int32 nSeparation = _sSQLString.indexOf( ' ' );
462 if ( -1 != nSeparation )
464 const sal_Unicode *p = _sSQLString.getStr() + nSeparation;
465 const sal_Unicode *const begin = p;
466 for(;isspace(*p);++p);
467 nSeparation += p - begin;
468 aTime = toTime( _sSQLString.copy( nSeparation ) );
471 return utl::DateTime(aTime.NanoSeconds, aTime.Seconds, aTime.Minutes, aTime.Hours,
472 aDate.Day, aDate.Month, aDate.Year, false);
475 //-----------------------------------------------------------------------------
476 utl::Time DBTypeConversion::toTime(const OUString& _sSQLString)
478 utl::Time aTime;
479 ::utl::ISO8601parseTime(_sSQLString, aTime);
480 return aTime;
483 //.........................................................................
484 } // namespace dbtools
485 //.........................................................................
488 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */