1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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>
36 #define MAX_DAYS 3636532
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 //.........................................................................
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
)
85 return OUString::createFromAscii(s
);
87 //------------------------------------------------------------------
88 OUString
DBTypeConversion::toTimeString(const utl::Time
& rTime
)
90 std::ostringstream ostr
;
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
)
115 aReturn
.Day
= (sal_uInt16
)(_nVal
% 100);
116 aReturn
.Month
= (sal_uInt16
)((_nVal
/ 100) % 100);
117 aReturn
.Year
= (sal_uInt16
)(_nVal
/ 10000);
121 //------------------------------------------------------------------------------
122 utl::Time
DBTypeConversion::toTime(sal_Int64 _nVal
)
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
;
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
)
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
;
153 return nNanoSeconds
+
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
;
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!");
204 return aDaysInMonth
[_nMonth
-1];
207 if (implIsLeapYear(_nYear
))
208 return aDaysInMonth
[_nMonth
-1] + 1;
210 return aDaysInMonth
[_nMonth
-1];
214 //------------------------------------------------------------------------------
215 static sal_Int32
implRelativeToAbsoluteNull(const utl::Date
& _rDate
)
219 // ripped this code from the implementation of tools::Date
220 sal_Int32 nNormalizedYear
= _rDate
.Year
- 1;
221 nDays
= nNormalizedYear
* 365;
223 nDays
+= (nNormalizedYear
/ 4) - (nNormalizedYear
/ 100) + (nNormalizedYear
/ 400);
225 for (sal_Int32 i
= 1; i
< _rDate
.Month
; ++i
)
226 nDays
+= implDaysInMonth(i
, _rDate
.Year
);
231 //------------------------------------------------------------------------------
232 static void implBuildFromRelative( sal_Int32 nDays
, sal_uInt16
& rDay
, sal_uInt16
& rMonth
, sal_Int16
& rYear
)
241 rYear
= (sal_uInt16
)((nTempDays
/ 365) - i
);
242 nTempDays
-= (rYear
-1) * 365;
243 nTempDays
-= ((rYear
-1) / 4) - ((rYear
-1) / 100) + ((rYear
-1) / 400);
252 if ( nTempDays
> 365 )
254 if ( (nTempDays
!= 366) || !implIsLeapYear( rYear
) )
265 while ( nTempDays
> implDaysInMonth( rMonth
, rYear
) )
267 nTempDays
-= implDaysInMonth( rMonth
, rYear
);
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
);
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
);
309 if ( nTempDays
> MAX_DAYS
)
315 else if ( nTempDays
<= 0 )
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
);
330 if ( nTempDays
> MAX_DAYS
)
336 else if ( nTempDays
<= 0 )
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
;
351 addDays((sal_Int32
)dVal
,aRet
);
353 subDays((sal_uInt32
)(-dVal
),aRet
);
354 // x -= (sal_uInt32)(-nDays);
358 // -------------------------------------------------------------------------
359 utl::Time
DBTypeConversion::toTime(double dVal
, short nDigits
)
361 sal_Int32 nDays
= (sal_Int32
)dVal
;
364 double fSeconds((dVal
- (double)nDays
) * (fNanoSecondsPerDay
/ nanoSecInSec
));
365 fSeconds
= ::rtl::math::round( fSeconds
, nDigits
);
366 nNS
= fSeconds
* nanoSecInSec
;
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
;
391 sal_Int64 nTime
= nSign
*
393 xRet
.Seconds
* secMask
+
394 xRet
.Minutes
* minMask
+
395 xRet
.Hours
* hourMask
);
399 xRet
.NanoSeconds
= nanoSecInSec
-1;
400 xRet
.Seconds
= secInMin
-1;
401 xRet
.Minutes
= minInHour
-1;
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);
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
;
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,
440 nYear
= (sal_uInt16
)_sSQLString
.getToken(0,sDateSep
,nIndex
).toInt32();
443 nMonth
= (sal_uInt16
)_sSQLString
.getToken(0,sDateSep
,nIndex
).toInt32();
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)
459 utl::Date aDate
= toDate(_sSQLString
);
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
)
479 ::utl::ISO8601parseTime(_sSQLString
, aTime
);
483 //.........................................................................
484 } // namespace dbtools
485 //.........................................................................
488 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */