Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / connectivity / source / commontools / dbconversion.cxx
blob81aae73f997811b605db85c27779ae31fb581843
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 #include <stdio.h>
24 #include <com/sun/star/sdbc/SQLException.hpp>
25 #include <com/sun/star/util/Date.hpp>
26 #include <com/sun/star/util/Time.hpp>
27 #include <com/sun/star/util/DateTime.hpp>
28 #include <rtl/ustrbuf.hxx>
29 #include <rtl/math.hxx>
30 #include <unotools/datetime.hxx>
31 #include <sstream>
32 #include <iomanip>
34 #define MAX_DAYS 3636532
36 namespace
38 const sal_Int64 nanoSecInSec = 1000000000;
39 const sal_Int16 secInMin = 60;
40 const sal_Int16 minInHour = 60;
42 const sal_Int64 secMask = 1000000000;
43 const sal_Int64 minMask = 100000000000LL;
44 const sal_Int64 hourMask = 10000000000000LL;
46 const double fNanoSecondsPerDay = nanoSecInSec * secInMin * minInHour * 24.0;
50 namespace dbtools
54 using namespace ::com::sun::star::uno;
55 using namespace ::com::sun::star::util;
56 namespace utl = ::com::sun::star::util;
57 using namespace ::com::sun::star::sdb;
58 using namespace ::com::sun::star::sdbc;
59 using namespace ::com::sun::star::lang;
60 using namespace ::com::sun::star::beans;
64 ::com::sun::star::util::Date DBTypeConversion::getStandardDate()
66 static ::com::sun::star::util::Date STANDARD_DB_DATE(1,1,1900);
67 return STANDARD_DB_DATE;
70 OUString DBTypeConversion::toDateString(const utl::Date& rDate)
72 sal_Char s[11];
73 snprintf(s,
74 sizeof(s),
75 "%04d-%02d-%02d",
76 (int)rDate.Year,
77 (int)rDate.Month,
78 (int)rDate.Day);
79 s[10] = 0;
80 return OUString::createFromAscii(s);
83 OUString DBTypeConversion::toTimeStringS(const utl::Time& rTime)
85 std::ostringstream ostr;
86 using std::setw;
87 ostr.fill('0');
88 ostr << setw(2) << rTime.Hours << ":"
89 << setw(2) << rTime.Minutes << ":"
90 << setw(2) << rTime.Seconds;
91 return OUString::createFromAscii(ostr.str().c_str());
94 OUString DBTypeConversion::toTimeString(const utl::Time& rTime)
96 std::ostringstream ostr;
97 using std::setw;
98 ostr.fill('0');
99 ostr << setw(2) << rTime.Hours << ":"
100 << setw(2) << rTime.Minutes << ":"
101 << setw(2) << rTime.Seconds << "."
102 << setw(9) << rTime.NanoSeconds;
103 return OUString::createFromAscii(ostr.str().c_str());
106 OUString DBTypeConversion::toDateTimeString(const utl::DateTime& _rDateTime)
108 utl::Date aDate(_rDateTime.Day,_rDateTime.Month,_rDateTime.Year);
109 OUStringBuffer aTemp(toDateString(aDate));
110 aTemp.appendAscii(" ");
111 utl::Time const aTime(_rDateTime.NanoSeconds, _rDateTime.Seconds,
112 _rDateTime.Minutes, _rDateTime.Hours, _rDateTime.IsUTC);
113 aTemp.append( toTimeString(aTime) );
114 return aTemp.makeStringAndClear();
117 utl::Date DBTypeConversion::toDate(sal_Int32 _nVal)
119 utl::Date aReturn;
120 aReturn.Day = (sal_uInt16)(_nVal % 100);
121 aReturn.Month = (sal_uInt16)((_nVal / 100) % 100);
122 aReturn.Year = (sal_uInt16)(_nVal / 10000);
123 return aReturn;
127 utl::Time DBTypeConversion::toTime(sal_Int64 _nVal)
129 utl::Time aReturn;
130 sal_uInt64 unVal = static_cast<sal_uInt64>(_nVal >= 0 ? _nVal : -_nVal);
131 aReturn.Hours = unVal / hourMask;
132 aReturn.Minutes = (unVal / minMask) % 100;
133 aReturn.Seconds = (unVal / secMask) % 100;
134 aReturn.NanoSeconds = unVal % secMask;
135 return aReturn;
138 sal_Int64 DBTypeConversion::getNsFromTime(const utl::Time& rVal)
140 sal_Int32 nHour = rVal.Hours;
141 sal_Int32 nMin = rVal.Minutes;
142 sal_Int32 nSec = rVal.Seconds;
143 sal_Int32 nNanoSec = rVal.NanoSeconds;
145 return nNanoSec +
146 nSec * nanoSecInSec +
147 nMin * (secInMin * nanoSecInSec) +
148 nHour * (minInHour * secInMin * nanoSecInSec);
152 static const sal_Int32 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
153 31, 31, 30, 31, 30, 31 };
156 static bool implIsLeapYear(sal_Int32 _nYear)
158 return ( ( ((_nYear % 4) == 0)
159 && ((_nYear % 100) != 0)
162 || ((_nYear % 400) == 0)
167 static sal_Int32 implDaysInMonth(sal_Int32 _nMonth, sal_Int32 _nYear)
169 OSL_ENSURE(_nMonth > 0 && _nMonth < 13,"Month as invalid value!");
170 if (_nMonth != 2)
171 return aDaysInMonth[_nMonth-1];
172 else
174 if (implIsLeapYear(_nYear))
175 return aDaysInMonth[_nMonth-1] + 1;
176 else
177 return aDaysInMonth[_nMonth-1];
182 static sal_Int32 implRelativeToAbsoluteNull(const utl::Date& _rDate)
184 sal_Int32 nDays = 0;
186 // ripped this code from the implementation of tools::Date
187 sal_Int32 nNormalizedYear = _rDate.Year - 1;
188 nDays = nNormalizedYear * 365;
189 // leap years
190 nDays += (nNormalizedYear / 4) - (nNormalizedYear / 100) + (nNormalizedYear / 400);
192 for (sal_Int32 i = 1; i < _rDate.Month; ++i)
193 nDays += implDaysInMonth(i, _rDate.Year);
195 nDays += _rDate.Day;
196 return nDays;
199 static void implBuildFromRelative( sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_Int16& rYear)
201 sal_Int32 nTempDays;
202 sal_Int32 i = 0;
203 bool bCalc;
207 nTempDays = nDays;
208 rYear = (sal_uInt16)((nTempDays / 365) - i);
209 nTempDays -= (rYear-1) * 365;
210 nTempDays -= ((rYear-1) / 4) - ((rYear-1) / 100) + ((rYear-1) / 400);
211 bCalc = false;
212 if ( nTempDays < 1 )
214 i++;
215 bCalc = true;
217 else
219 if ( nTempDays > 365 )
221 if ( (nTempDays != 366) || !implIsLeapYear( rYear ) )
223 i--;
224 bCalc = true;
229 while ( bCalc );
231 rMonth = 1;
232 while ( nTempDays > implDaysInMonth( rMonth, rYear ) )
234 nTempDays -= implDaysInMonth( rMonth, rYear );
235 rMonth++;
237 rDay = (sal_uInt16)nTempDays;
240 sal_Int32 DBTypeConversion::toDays(const utl::Date& _rVal, const utl::Date& _rNullDate)
242 return implRelativeToAbsoluteNull(_rVal) - implRelativeToAbsoluteNull(_rNullDate);
246 double DBTypeConversion::toDouble(const utl::Date& rVal, const utl::Date& _rNullDate)
248 return (double)toDays(rVal, _rNullDate);
252 double DBTypeConversion::toDouble(const utl::Time& rVal)
254 return (double)getNsFromTime(rVal) / fNanoSecondsPerDay;
258 double DBTypeConversion::toDouble(const utl::DateTime& _rVal, const utl::Date& _rNullDate)
260 sal_Int64 nTime = toDays(utl::Date(_rVal.Day, _rVal.Month, _rVal.Year), _rNullDate);
261 utl::Time aTimePart;
263 aTimePart.Hours = _rVal.Hours;
264 aTimePart.Minutes = _rVal.Minutes;
265 aTimePart.Seconds = _rVal.Seconds;
266 aTimePart.NanoSeconds = _rVal.NanoSeconds;
268 return ((double)nTime) + toDouble(aTimePart);
271 static void addDays(sal_Int32 nDays, utl::Date& _rDate)
273 sal_Int32 nTempDays = implRelativeToAbsoluteNull( _rDate );
275 nTempDays += nDays;
276 if ( nTempDays > MAX_DAYS )
278 _rDate.Day = 31;
279 _rDate.Month = 12;
280 _rDate.Year = 9999;
282 else if ( nTempDays <= 0 )
284 _rDate.Day = 1;
285 _rDate.Month = 1;
286 _rDate.Year = 00;
288 else
289 implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year );
292 static void subDays( sal_Int32 nDays, utl::Date& _rDate )
294 sal_Int32 nTempDays = implRelativeToAbsoluteNull( _rDate );
296 nTempDays -= nDays;
297 if ( nTempDays > MAX_DAYS )
299 _rDate.Day = 31;
300 _rDate.Month = 12;
301 _rDate.Year = 9999;
303 else if ( nTempDays <= 0 )
305 _rDate.Day = 1;
306 _rDate.Month = 1;
307 _rDate.Year = 00;
309 else
310 implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year );
313 utl::Date DBTypeConversion::toDate(double dVal, const utl::Date& _rNullDate)
315 utl::Date aRet = _rNullDate;
317 if (dVal >= 0)
318 addDays((sal_Int32)dVal,aRet);
319 else
320 subDays((sal_uInt32)(-dVal),aRet);
321 // x -= (sal_uInt32)(-nDays);
323 return aRet;
326 utl::Time DBTypeConversion::toTime(double dVal, short nDigits)
328 sal_Int32 nDays = (sal_Int32)dVal;
329 sal_Int64 nNS;
331 double fSeconds((dVal - (double)nDays) * (fNanoSecondsPerDay / nanoSecInSec));
332 fSeconds = ::rtl::math::round( fSeconds, nDigits );
333 nNS = fSeconds * nanoSecInSec;
336 sal_Int16 nSign;
337 if ( nNS < 0 )
339 nNS *= -1;
340 nSign = -1;
342 else
343 nSign = 1;
345 utl::Time xRet;
346 // normalize time
347 // we have to sal_Int32 here because otherwise we get an overflow
348 sal_Int64 nNanoSeconds = nNS;
349 sal_Int32 nSeconds = nNanoSeconds / nanoSecInSec;
350 sal_Int32 nMinutes = nSeconds / secInMin;
352 xRet.NanoSeconds = nNanoSeconds % nanoSecInSec;
353 xRet.Seconds = nSeconds % secInMin;
354 xRet.Hours = nMinutes / minInHour;
355 xRet.Minutes = nMinutes % minInHour;
357 // assemble time
358 sal_Int64 nTime = nSign *
359 (xRet.NanoSeconds +
360 xRet.Seconds * secMask +
361 xRet.Minutes * minMask +
362 xRet.Hours * hourMask);
364 if(nTime < 0)
366 xRet.NanoSeconds = nanoSecInSec-1;
367 xRet.Seconds = secInMin-1;
368 xRet.Minutes = minInHour-1;
369 xRet.Hours = 23;
371 return xRet;
374 utl::DateTime DBTypeConversion::toDateTime(double dVal, const utl::Date& _rNullDate)
376 utl::Date aDate = toDate(dVal, _rNullDate);
377 // there is not enough precision in a double to have both a date
378 // and a time up to nanoseconds -> limit to microseconds to have
379 // correct rounding, that is e.g. 13:00:00.000000000 instead of
380 // 12:59:59.999999790
381 utl::Time aTime = toTime(dVal, 6);
383 utl::DateTime xRet;
385 xRet.Day = aDate.Day;
386 xRet.Month = aDate.Month;
387 xRet.Year = aDate.Year;
389 xRet.NanoSeconds = aTime.NanoSeconds;
390 xRet.Minutes = aTime.Minutes;
391 xRet.Seconds = aTime.Seconds;
392 xRet.Hours = aTime.Hours;
395 return xRet;
398 utl::Date DBTypeConversion::toDate(const OUString& _sSQLString)
400 // get the token out of a string
401 static sal_Unicode sDateSep = '-';
403 sal_Int32 nIndex = 0;
404 sal_uInt16 nYear = 0,
405 nMonth = 0,
406 nDay = 0;
407 nYear = (sal_uInt16)_sSQLString.getToken(0,sDateSep,nIndex).toInt32();
408 if(nIndex != -1)
410 nMonth = (sal_uInt16)_sSQLString.getToken(0,sDateSep,nIndex).toInt32();
411 if(nIndex != -1)
412 nDay = (sal_uInt16)_sSQLString.getToken(0,sDateSep,nIndex).toInt32();
415 return utl::Date(nDay,nMonth,nYear);
419 utl::DateTime DBTypeConversion::toDateTime(const OUString& _sSQLString)
421 //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Timestamp.html#valueOf(java.lang.String)
422 //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Date.html#valueOf(java.lang.String)
423 //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Time.html#valueOf(java.lang.String)
425 // the date part
426 utl::Date aDate = toDate(_sSQLString);
427 utl::Time aTime;
428 sal_Int32 nSeparation = _sSQLString.indexOf( ' ' );
429 if ( -1 != nSeparation )
431 const sal_Unicode *p = _sSQLString.getStr() + nSeparation;
432 const sal_Unicode *const begin = p;
433 while (isspace(*p)) { ++p; }
434 nSeparation += p - begin;
435 aTime = toTime( _sSQLString.copy( nSeparation ) );
438 return utl::DateTime(aTime.NanoSeconds, aTime.Seconds, aTime.Minutes, aTime.Hours,
439 aDate.Day, aDate.Month, aDate.Year, false);
443 utl::Time DBTypeConversion::toTime(const OUString& _sSQLString)
445 utl::Time aTime;
446 ::utl::ISO8601parseTime(_sSQLString, aTime);
447 return aTime;
451 } // namespace dbtools
455 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */