1 karl 1.66 //%2006////////////////////////////////////////////////////////////////////////
|
2 mike 1.10 //
|
3 karl 1.42 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
|
6 karl 1.37 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.42 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
|
9 karl 1.50 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.66 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
|
13 mike 1.10 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
15 kumpf 1.22 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
18 mike 1.10 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
|
20 karl 1.66 //
|
21 kumpf 1.22 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
|
22 mike 1.10 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
24 kumpf 1.22 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
27 mike 1.10 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
32 //%/////////////////////////////////////////////////////////////////////////////
33
|
34 mike 1.71 #include <cstring>
35 #include <cassert>
36 #include <fstream>
|
37 david.dillard 1.54 #include "CIMDateTime.h"
|
38 mike 1.71 #include "Exception.h"
|
39 kumpf 1.78 #include "AutoPtr.h"
|
40 mike 1.71 #include "PegasusAssert.h"
|
41 kumpf 1.72 #include <time.h>
|
42 mike 1.10
|
43 mike 1.71 #if defined(PEGASUS_OS_TYPE_UNIX) || defined(PEGASUS_OS_VMS)
44 # include <sys/time.h>
45 #elif defined(PEGASUS_OS_TYPE_WINDOWS)
46 # include <sstream>
47 # include <iomanip>
48 # include <windows.h>
|
49 kumpf 1.14 #else
|
50 mike 1.71 # error "unsupported platform"
|
51 kumpf 1.14 #endif
52
53 PEGASUS_USING_STD;
54
|
55 mike 1.10 PEGASUS_NAMESPACE_BEGIN
56
57 #define PEGASUS_ARRAY_T CIMDateTime
58 # include "ArrayImpl.h"
59 #undef PEGASUS_ARRAY_T
60
|
61 mike 1.71 //==============================================================================
62 //
63 // CIMDateTimeRep
64 //
65 //==============================================================================
66
67 class CIMDateTimeRep
68 {
69 public:
|
70 mike 1.11
|
71 mike 1.71 // Number of microseconds elapsed since January 1, 1 BCE.
72 Uint64 usec;
|
73 mike 1.11
|
74 mike 1.71 // UTC offset
75 Uint32 utcOffset;
|
76 mike 1.10
|
77 mike 1.71 // ':' for intervals. '-' or '+' for time stamps.
78 Uint16 sign;
|
79 w.white 1.43
|
80 mike 1.71 // Number of wild characters ('*') used to initialize this object.
81 Uint16 numWildcards;
82 };
|
83 kumpf 1.67
|
84 mike 1.71 //==============================================================================
85 //
86 // Local constants.
87 //
88 //==============================================================================
|
89 kumpf 1.67
|
90 mike 1.71 // Julian day of "1 BCE January 1".
91 static const Uint32 JULIAN_ONE_BCE = 1721060;
|
92 mike 1.10
|
93 mike 1.71 // Number of microseconds in one second.
94 static const Uint64 SECOND = 1000000;
|
95 david.dillard 1.54
|
96 mike 1.71 // Number of microseconds in one minute.
97 static const Uint64 MINUTE = 60 * SECOND;
|
98 w.white 1.43
|
99 mike 1.71 // Number of microseconds in one hour.
100 static const Uint64 HOUR = 60 * MINUTE;
|
101 w.white 1.43
|
102 mike 1.71 // Number of microseconds in one day.
103 static const Uint64 DAY = 24 * HOUR;
|
104 w.white 1.43
|
105 mike 1.71 // Number of microseconds in ten thousand years.
|
106 kumpf 1.76 static const Uint64 TEN_THOUSAND_YEARS =
|
107 mike 1.71 PEGASUS_UINT64_LITERAL(315569520000000000);
|
108 david.dillard 1.54
|
109 mike 1.71 // Number of microseconds in one million days.
|
110 kumpf 1.76 static const Uint64 HUNDRED_MILLION_DAYS =
|
111 mike 1.71 PEGASUS_UINT64_LITERAL(8640000000000000000);
|
112 david.dillard 1.54
|
113 mike 1.71 // Adding this to the POSIX 1970 microseconds epoch produces a 1 BCE epoch
114 // as used by this class.
|
115 kumpf 1.76 static const Uint64 POSIX_1970_EPOCH_OFFSET =
|
116 kumpf 1.77 PEGASUS_UINT64_LITERAL(62167219200000000);
|
117 a.arora 1.40
|
118 mike 1.71 //==============================================================================
119 //
120 // Local functions.
121 //
122 //==============================================================================
|
123 a.arora 1.40
|
124 mike 1.71 /** Returns true if argument is a leap year.
|
125 w.white 1.43 */
|
126 mike 1.71 static inline bool _isLeapYear(Uint32 year)
|
127 w.white 1.43 {
|
128 mike 1.71 return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
|
129 w.white 1.43 }
130
|
131 mike 1.71 /** Calculates the number of days in a given month, accounting for leap year.
|
132 w.white 1.43 */
|
133 mike 1.71 static Uint32 _getDaysPerMonth(Uint32 year, Uint32 month)
|
134 w.white 1.43 {
|
135 mike 1.71 static char _daysPerMonth[] =
136 {
137 31, /* JAN */
138 28, /* FEB */
139 31, /* MAR */
140 30, /* APR */
141 31, /* MAY */
142 30, /* JUN */
143 31, /* JUL */
144 31, /* AUG */
145 30, /* SEP */
146 31, /* OCT */
147 30, /* NOV */
148 31, /* DEC */
149 };
150
151 // If February:
152
153 if (month == 2 && _isLeapYear(year))
154 return 29;
|
155 david.dillard 1.54
|
156 mike 1.71 return _daysPerMonth[month - 1];
|
157 w.white 1.43 }
|
158 david.dillard 1.54
|
159 mike 1.71 /** Convert month, day, and year to a Julian day (in the Gregorian calendar).
160 Return julian day.
161 */
162 static inline Uint32 _toJulianDay(Uint32 year, Uint32 month, Uint32 day)
|
163 w.white 1.43 {
|
164 mike 1.71 // Formula adapted from "FREQUENTLY ASKED QUESTIONS ABOUT CALENDARS"
165 // (see http://www.tondering.dk/claus/calendar.html).
|
166 david.dillard 1.54
|
167 mike 1.71 int a = (14 - month)/12;
168 int y = year+4800-a;
169 int m = month + 12*a - 3;
170 return day + (153*m+2)/5 + y*365 + y/4 - y/100 + y/400 - 32045;
|
171 w.white 1.43 }
172
|
173 mike 1.71 /** Convert a Julian day number (in the Gregorian calendar) to year, month,
174 and day.
175 */
176 static inline void _fromJulianDay(
177 Uint32 jd, Uint32& year, Uint32& month, Uint32& day)
|
178 w.white 1.43 {
|
179 mike 1.71 // Formula adapted from "FREQUENTLY ASKED QUESTIONS ABOUT CALENDARS"
180 // (see http://www.tondering.dk/claus/calendar.html).
|
181 david.dillard 1.54
|
182 mike 1.71 int a = jd + 32044;
183 int b = (4*a+3)/146097;
184 int c = a - (b*146097)/4;
185 int d = (4*c+3)/1461;
186 int e = c - (1461*d)/4;
187 int m = (5*e+2)/153;
188 day = e - (153*m+2)/5 + 1;
189 month = m + 3 - 12*(m/10);
190 year = b*100 + d - 4800 + m/10;
|
191 w.white 1.43 }
192
|
193 mike 1.71 /** Optimized version of _strToUint32() for n=2 case.
|
194 w.white 1.43 */
|
195 mike 1.71 static inline bool _strToUint32_n2(const Uint16* s, Uint32& x)
|
196 w.white 1.43 {
|
197 mike 1.71 Uint32 c0 = s[0] - '0';
|
198 w.white 1.43
|
199 mike 1.71 if (c0 > 9)
|
200 w.white 1.43 return false;
|
201 david.dillard 1.54
|
202 mike 1.71 Uint32 c1 = s[1] - '0';
|
203 w.white 1.43
|
204 mike 1.71 if (c1 > 9)
|
205 w.white 1.43 return false;
206
|
207 mike 1.71 x = 10 * c0 + c1;
|
208 w.white 1.43
209 return true;
210 }
211
|
212 mike 1.71 /** Powers of ten.
|
213 w.white 1.43 */
|
214 mike 1.71 static const Uint32 _tens[] =
|
215 mike 1.10 {
|
216 mike 1.71 1,
217 10,
218 100,
219 1000,
220 10000,
221 100000,
222 1000000,
223 10000000,
224 };
|
225 kumpf 1.53
|
226 mike 1.71 /** Convert the next n digits to integer. Return true on success. Return
227 false if a non-digit was encountered in the first n characters. Don't
228 call with n > 8.
|
229 w.white 1.43 */
|
230 mike 1.71 static inline bool _strToUint32(const Uint16* s, size_t n, Uint32& x)
|
231 mike 1.10 {
|
232 mike 1.71 switch (n)
|
233 kumpf 1.21 {
|
234 mike 1.71 case 2:
235 return _strToUint32_n2(s, x);
|
236 kumpf 1.53
|
237 mike 1.71 default:
238 {
239 x = 0;
|
240 mike 1.10
|
241 mike 1.71 const Uint32* m = _tens;
|
242 kumpf 1.53
|
243 mike 1.71 for (const Uint16* p = &s[n]; n--; )
244 {
245 Uint16 c = *--p - '0';
|
246 kumpf 1.53
|
247 mike 1.71 if (c > 9)
248 return false;
|
249 w.white 1.43
|
250 mike 1.71 x += *m++ * c;
251 }
|
252 david.dillard 1.54
|
253 mike 1.71 return true;
254 }
|
255 kumpf 1.67 }
|
256 mike 1.71 }
|
257 kumpf 1.67
|
258 mike 1.71 /** Parse the integer component pointed to by s. Return WILDCARD if s consists
259 entirely of '*' characters. Returns the integer if it consists entirely
|
260 kumpf 1.76 of digits. Throw exception if digits and '*' are mixed. Also throw
|
261 mike 1.71 exception if digits are encountered when priorWildcards parameter is true.
262 */
263 static inline Uint32 _parseComponent(
264 const Uint16*& s, size_t n, bool& priorWildcards)
265 {
266 // Check whether all characters are '*'.
|
267 david.dillard 1.54
|
268 mike 1.71 if (*s == '*')
|
269 kumpf 1.67 {
|
270 mike 1.71 bool allWild = true;
|
271 w.white 1.43
|
272 mike 1.71 for (size_t i = 0; i < n; i++)
|
273 kumpf 1.67 {
|
274 mike 1.71 if (s[i] != '*')
|
275 kumpf 1.67 {
|
276 mike 1.71 allWild = false;
|
277 kumpf 1.67 break;
278 }
|
279 w.white 1.43 }
280
|
281 mike 1.71 if (allWild)
282 {
283 s += n;
284 priorWildcards = true;
285 return Uint32(-1);
286 }
287 }
|
288 w.white 1.43
|
289 mike 1.71 if (priorWildcards)
290 throw InvalidDateTimeFormatException();
|
291 w.white 1.43
|
292 mike 1.71 Uint32 x;
|
293 kumpf 1.53
|
294 mike 1.71 if (!_strToUint32(s, n, x))
295 throw InvalidDateTimeFormatException();
|
296 david.dillard 1.54
|
297 mike 1.71 s += n;
298 return x;
|
299 mike 1.10 }
300
|
301 mike 1.71 /** Return true if all characters of the string are asterisks.
|
302 w.white 1.43 */
|
303 mike 1.71 static inline bool _allAsterisks(const Uint16* s, size_t n)
|
304 mike 1.10 {
|
305 mike 1.71 for (size_t i = 0; i < n; i++)
306 {
307 if (s[i] != '*')
308 return false;
|
309 w.white 1.43 }
|
310 mike 1.10
|
311 mike 1.71 return true;
|
312 mike 1.10 }
313
|
314 mike 1.71 /** Parse the microseconds component of the given string (6 characters).
|
315 kumpf 1.76 Set numSignificantMicrosecondDigits to the number of leading significant
316 digits (non-asterisks). Note that once an asterisk is encountered, all
317 subsequent characters must be asterisks. Returns the number of
318 microseconds. Throws an exception if priorWildcards is true and any digits
|
319 mike 1.71 are encountered or if digits occurs after asterisks.
320 */
321 static Uint32 _parseMicroseconds(
322 const Uint16*& s,
323 bool priorWildcards,
324 Uint16& numSignificantDigits)
|
325 a.arora 1.40 {
|
326 mike 1.71 static const Uint32 _mult[] = { 100000, 10000, 1000, 100, 10, 1, };
|
327 a.arora 1.40
|
328 mike 1.71 // If wildcards encountered in previous components, then the first
329 // character must be an asterisk.
|
330 mike 1.10
|
331 mike 1.71 if (priorWildcards && s[0] != '*')
332 throw InvalidDateTimeFormatException();
|
333 w.white 1.43
|
334 mike 1.71 // Examine characters left to right.
|
335 mike 1.10
|
336 mike 1.71 numSignificantDigits = 0;
337 Uint32 x = 0;
|
338 w.white 1.43
|
339 mike 1.71 for (size_t i = 0; i < 6; i++)
340 {
341 Uint32 c = s[i] - '0';
|
342 kumpf 1.26
|
343 mike 1.71 if (c < 10)
344 {
345 // A digit:
346 x += c * _mult[i];
347 }
348 else if (c == Uint32('*' - '0'))
349 {
350 // An asterisk:
351 numSignificantDigits = Uint16(i);
|
352 w.white 1.43
|
353 mike 1.71 // All remaining characters must be asterisks.
|
354 mike 1.10
|
355 mike 1.71 if (!_allAsterisks(s + i, 6 - i))
356 throw InvalidDateTimeFormatException();
|
357 mike 1.10
|
358 mike 1.71 s += 6;
359 return x;
360 }
361 else
362 {
363 // An illegal character.
364 throw InvalidDateTimeFormatException();
365 }
|
366 w.white 1.43 }
|
367 mike 1.10
|
368 mike 1.71 numSignificantDigits = 6;
369 s += 6;
370 return x;
371 }
|
372 mike 1.10
|
373 mike 1.71 /** Similar to strcmp() but accounts for wildcards. Compares the first twenty
374 five corresponding characters of s1 and s2. Returns the first non-zero
375 difference, unless one of the characters is an asterisk, in which case
376 it proceeds to the next character. The return value has the following
377 meaning:
|
378 david.dillard 1.54
|
379 mike 1.71 0 : s1 is lexographically equal to s2
380 < 0 : s1 is lexographically less than s2
381 > 0 : s1 is lexographically greather than s2
382 */
383 static int _matchTimeStampStrings(const char* s1, const char* s2)
384 {
385 for (size_t i = 0; i < 25; i++)
386 {
387 char c1 = s1[i];
388 char c2 = s2[i];
|
389 w.white 1.43
|
390 mike 1.71 if (c1 == '*' || c2 == '*')
391 continue;
|
392 mike 1.10
|
393 mike 1.71 int r = c1 - c2;
|
394 mike 1.10
|
395 mike 1.71 if (r)
396 return r;
|
397 mike 1.10 }
|
398 david.dillard 1.54
|
399 mike 1.71 // Identical
400 return 0;
401 }
|
402 mike 1.10
|
403 mike 1.71 /** Normalize timestamps by including the utcOffset in the usec member and
404 then setting utcOffset to zero.
405 */
406 static inline void _normalize(CIMDateTimeRep* in)
407 {
408 if (in->sign != ':')
409 {
410 // DDDDDDDDHHMMSS.MMMMMM:000
|
411 mike 1.10
|
412 mike 1.71 Uint64 hours = (in->utcOffset / 60) * HOUR;
413 Uint64 minutes = (in->utcOffset % 60) * MINUTE;
|
414 w.white 1.43
|
415 mike 1.71 // If minutes not wildcarded.
416 // Else if hours not wildcarded.
|
417 w.white 1.43
|
418 mike 1.71 if (in->numWildcards < 10)
419 {
420 if (in->sign == '+')
421 in->usec -= hours + minutes;
422 else
423 in->usec += hours + minutes;
|
424 w.white 1.43 }
|
425 mike 1.71 else if (in->numWildcards < 12)
426 {
427 if (in->sign == '+')
428 in->usec -= hours;
429 else
430 in->usec += hours;
|
431 w.white 1.43 }
432
|
433 mike 1.71 in->utcOffset = 0;
434 in->sign = '+';
435 }
436 }
|
437 david.dillard 1.54
|
438 mike 1.71 /** Converts the representation object to microseconds. For intervals, this
439 quantity is the same as usec member. Time stamps are normalized so that
440 the usec component contains the UTF offset.
441 */
442 static Uint64 _toMicroSeconds(const CIMDateTimeRep* rep)
443 {
444 if (rep->sign == ':')
445 return rep->usec;
|
446 w.white 1.43
|
447 mike 1.71 CIMDateTimeRep tmp = *rep;
448 _normalize(&tmp);
449 return tmp.usec;
450 }
|
451 w.white 1.43
|
452 mike 1.71 /** Converts a CIMDateTimeRep representation to its canonical string
453 representation as defined in the "CIM infrastructure Specification".
454 Note that this implementation preserves any wildcard characters used
455 to initially create the CIMDateTime object.
456 */
457 static void _toCStr(const CIMDateTimeRep* rep, char buffer[26])
458 {
459 if (rep->sign == ':')
460 {
461 // Extract components:
|
462 david.dillard 1.54
|
463 mike 1.71 Uint64 usec = rep->usec;
464 Uint32 microseconds = Uint32(usec % SECOND);
465 Uint32 seconds = Uint32((usec / SECOND) % 60);
466 Uint32 minutes = Uint32((usec / MINUTE) % 60);
467 Uint32 hours = Uint32((usec / HOUR) % 24);
468 Uint32 days = Uint32((usec / DAY));
|
469 w.white 1.43
|
470 mike 1.71 // Format the string.
|
471 w.white 1.43
|
472 mike 1.71 sprintf(
|
473 kumpf 1.76 buffer,
|
474 mike 1.71 "%08u%02u%02u%02u.%06u:000",
475 Uint32(days),
476 Uint32(hours),
477 Uint32(minutes),
478 Uint32(seconds),
479 Uint32(microseconds));
480 }
481 else
482 {
483 // Extract components:
|
484 w.white 1.43
|
485 mike 1.71 Uint64 usec = rep->usec;
486 Uint32 microseconds = Uint32(usec % SECOND);
487 Uint32 seconds = Uint32((usec / SECOND) % 60);
488 Uint32 minutes = Uint32((usec / MINUTE) % 60);
489 Uint32 hours = Uint32((usec / HOUR) % 24);
490 Uint32 days = Uint32((usec / DAY));
491 Uint32 jd = Uint32(days + JULIAN_ONE_BCE);
492
493 // Convert back from julian to year/month/day:
494
495 Uint32 year;
496 Uint32 month;
497 Uint32 day;
498 _fromJulianDay(jd, year, month, day);
|
499 w.white 1.43
|
500 mike 1.71 // Format the string.
|
501 w.white 1.43
|
502 mike 1.71 sprintf(
|
503 kumpf 1.76 buffer,
|
504 mike 1.71 "%04u%02u%02u%02u%02u%02u.%06u%c%03d",
505 Uint32(year),
506 Uint32(month),
507 Uint32(day),
508 Uint32(hours),
509 Uint32(minutes),
510 Uint32(seconds),
511 Uint32(microseconds),
512 rep->sign,
513 rep->utcOffset);
514 }
515
516 // Fill buffer with '*' chars (if any).
517 {
518 char* first = buffer + 20;
519 char* last = buffer + 20 - rep->numWildcards;
|
520 w.white 1.43
|
521 mike 1.71 if (rep->numWildcards > 6)
522 last--;
|
523 w.white 1.43
|
524 mike 1.71 for (; first != last; first--)
|
525 kumpf 1.62 {
|
526 mike 1.71 if (*first != '.')
527 *first = '*';
|
528 w.white 1.43 }
|
529 mike 1.71 }
530 }
|
531 mike 1.10
|
532 mike 1.71 /** This table is used to convert integers between 0 and 99 (inclusive) to
533 a char16 array, with zero padding.
534 */
535 static Uint16 _intToStrTable[][2] =
536 {
537 { '0', '0', },
538 { '0', '1', },
539 { '0', '2', },
540 { '0', '3', },
541 { '0', '4', },
542 { '0', '5', },
543 { '0', '6', },
544 { '0', '7', },
545 { '0', '8', },
546 { '0', '9', },
547 { '1', '0', },
548 { '1', '1', },
549 { '1', '2', },
550 { '1', '3', },
551 { '1', '4', },
552 { '1', '5', },
553 mike 1.71 { '1', '6', },
554 { '1', '7', },
555 { '1', '8', },
556 { '1', '9', },
557 { '2', '0', },
558 { '2', '1', },
559 { '2', '2', },
560 { '2', '3', },
561 { '2', '4', },
562 { '2', '5', },
563 { '2', '6', },
564 { '2', '7', },
565 { '2', '8', },
566 { '2', '9', },
567 { '3', '0', },
568 { '3', '1', },
569 { '3', '2', },
570 { '3', '3', },
571 { '3', '4', },
572 { '3', '5', },
573 { '3', '6', },
574 mike 1.71 { '3', '7', },
575 { '3', '8', },
576 { '3', '9', },
577 { '4', '0', },
578 { '4', '1', },
579 { '4', '2', },
580 { '4', '3', },
581 { '4', '4', },
582 { '4', '5', },
583 { '4', '6', },
584 { '4', '7', },
585 { '4', '8', },
586 { '4', '9', },
587 { '5', '0', },
588 { '5', '1', },
589 { '5', '2', },
590 { '5', '3', },
591 { '5', '4', },
592 { '5', '5', },
593 { '5', '6', },
594 { '5', '7', },
595 mike 1.71 { '5', '8', },
596 { '5', '9', },
597 { '6', '0', },
598 { '6', '1', },
599 { '6', '2', },
600 { '6', '3', },
601 { '6', '4', },
602 { '6', '5', },
603 { '6', '6', },
604 { '6', '7', },
605 { '6', '8', },
606 { '6', '9', },
607 { '7', '0', },
608 { '7', '1', },
609 { '7', '2', },
610 { '7', '3', },
611 { '7', '4', },
612 { '7', '5', },
613 { '7', '6', },
614 { '7', '7', },
615 { '7', '8', },
616 mike 1.71 { '7', '9', },
617 { '8', '0', },
618 { '8', '1', },
619 { '8', '2', },
620 { '8', '3', },
621 { '8', '4', },
622 { '8', '5', },
623 { '8', '6', },
624 { '8', '7', },
625 { '8', '8', },
626 { '8', '9', },
627 { '9', '0', },
628 { '9', '1', },
629 { '9', '2', },
630 { '9', '3', },
631 { '9', '4', },
632 { '9', '5', },
633 { '9', '6', },
634 { '9', '7', },
635 { '9', '8', },
636 { '9', '9', },
637 mike 1.71 };
638
639 /** Convert integer x to a zero-padded char16 string. Legal for x less than
640 100000000.
641 */
642 static inline void _intToChar16String(Uint32 x, Uint16*& str, size_t numDigits)
643 {
644 if (numDigits == 2)
645 {
646 str[0] = _intToStrTable[x][0];
647 str[1] = _intToStrTable[x][1];
648 str += 2;
649 return;
650 }
|
651 mike 1.10
|
652 mike 1.71 while (numDigits--)
653 {
654 Uint32 d = _tens[numDigits];
655 Uint32 n = x / d;
656 x %= d;
657 *str++ = n + '0';
|
658 w.white 1.43 }
|
659 mike 1.71 }
660
661 static void _toChar16Str(const CIMDateTimeRep* rep, Char16* data_)
662 {
663 Uint16* data = (Uint16*)data_;
|
664 mike 1.10
|
665 mike 1.71 if (rep->sign == ':')
666 {
667 // DDDDDDDDHHMMSS.MMMMMM:000
|
668 mike 1.10
|
669 mike 1.71 Uint64 usec = rep->usec;
670 Uint32 microseconds = Uint32(usec % SECOND);
671 Uint32 seconds = Uint32((usec / SECOND) % 60);
672 Uint32 minutes = Uint32((usec / MINUTE) % 60);
673 Uint32 hours = Uint32((usec / HOUR) % 24);
674 Uint32 days = Uint32((usec / DAY));
|
675 david.dillard 1.54
|
676 mike 1.71 _intToChar16String(days, data, 8);
677 _intToChar16String(hours, data, 2);
678 _intToChar16String(minutes, data, 2);
679 _intToChar16String(seconds, data, 2);
680 *data++ = '.';
681 _intToChar16String(microseconds, data, 6);
682 data[0] = ':';
683 data[1] = '0';
684 data[2] = '0';
685 data[3] = '0';
|
686 w.white 1.43 }
|
687 mike 1.71 else
688 {
689 // YYYYMMDDHHMMSS.MMMMMMSUTC
690
691 Uint64 usec = rep->usec;
692 Uint32 microseconds = Uint32(usec % SECOND);
693 Uint32 seconds = Uint32((usec / SECOND) % 60);
694 Uint32 minutes = Uint32((usec / MINUTE) % 60);
695 Uint32 hours = Uint32((usec / HOUR) % 24);
696 Uint32 days = Uint32((usec / DAY));
697 Uint32 jd = Uint32(days + JULIAN_ONE_BCE);
698 Uint32 year;
699 Uint32 month;
700 Uint32 day;
701 _fromJulianDay(jd, year, month, day);
702
703 _intToChar16String(year, data, 4);
704 _intToChar16String(month, data, 2);
705 _intToChar16String(day, data, 2);
706 _intToChar16String(hours, data, 2);
707 _intToChar16String(minutes, data, 2);
708 mike 1.71 _intToChar16String(seconds, data, 2);
709 *data++ = '.';
710 _intToChar16String(microseconds, data, 6);
711 *data++ = rep->sign;
712 _intToChar16String(rep->utcOffset, data, 3);
713 }
714
715 // Fill buffer with '*' chars (if any).
716 {
717 Uint16* first = (Uint16*)data_ + 20;
718 Uint16* last = (Uint16*)data_ + 20 - rep->numWildcards;
|
719 mike 1.10
|
720 mike 1.71 if (rep->numWildcards > 6)
721 last--;
|
722 w.white 1.43
|
723 mike 1.71 for (; first != last; first--)
724 {
725 if (*first != '.')
726 *first = '*';
|
727 w.white 1.43 }
|
728 kumpf 1.63 }
|
729 mike 1.71 }
730
731 /** Compares the two CIMDateTime representations. The return value is one of
732 the following.
|
733 w.white 1.43
|
734 mike 1.71 0 : x is equal to y
735 < 0 : x is less than y
736 > 0 : x is greater than y
|
737 w.white 1.43
|
738 mike 1.71 This function throws TypeMismatchException if x and y are not of the
739 same type (time stamps or intervals).
|
740 w.white 1.43
|
741 mike 1.71 Algorithm: If both representations have zero numWildcards members, then
742 the comparison is simply _toMicroSeconds(x) - _toMicroSeconds(y). If either
743 has a non-zero numWildcards member, then they are converted to to canonical
744 string format and compared lexographically with _matchTimeStampStrings().
745 If so, then time stamps must be normalized (usec must be adjusted for the
746 sign and utcOffset).
747 */
748 static int _compare(const CIMDateTimeRep* x, const CIMDateTimeRep* y)
749 {
750 bool xIsInterval = x->sign == ':';
751 bool yIsInterval = y->sign == ':';
|
752 w.white 1.45
|
753 mike 1.71 if (xIsInterval != yIsInterval)
754 {
755 MessageLoaderParms parms(
756 "Common.CIMDateTime.INVALID_OPERATION_COMP_DIF",
757 "Trying to compare CIMDateTime objects of differing types");
758 throw TypeMismatchException(parms);
|
759 w.white 1.43 }
|
760 mike 1.10
|
761 mike 1.71 if (x->numWildcards == 0 && y->numWildcards == 0)
762 {
763 Uint64 xm = _toMicroSeconds(x);
764 Uint64 ym = _toMicroSeconds(y);
|
765 w.white 1.47
|
766 mike 1.71 if (xm < ym)
767 return -1;
768 else if (xm > ym)
769 return 1;
|
770 david.dillard 1.54
|
771 mike 1.71 return 0;
|
772 w.white 1.43 }
|
773 mike 1.71 else
774 {
775 if (!xIsInterval)
776 {
777 // Normalize before comparing.
|
778 david.dillard 1.54
|
779 mike 1.71 CIMDateTimeRep x1 = *x;
780 _normalize(&x1);
|
781 mike 1.10
|
782 mike 1.71 CIMDateTimeRep y1 = *y;
783 _normalize(&y1);
|
784 mike 1.10
|
785 mike 1.71 char s1[26];
786 char s2[26];
787 _toCStr(&x1, s1);
788 _toCStr(&y1, s2);
789 return _matchTimeStampStrings(s1, s2);
790 }
791 else
792 {
793 char s1[26];
794 char s2[26];
795 _toCStr(x, s1);
796 _toCStr(y, s2);
797 return _matchTimeStampStrings(s1, s2);
798 }
799 }
|
800 w.white 1.43 }
|
801 mike 1.10
|
802 mike 1.71 //==============================================================================
803 //
804 // CIMDateTime
805 //
806 //==============================================================================
|
807 mike 1.10
|
808 mike 1.71 const Uint32 CIMDateTime::WILDCARD = Uint32(-1);
|
809 mike 1.10
|
810 mike 1.71 CIMDateTime::CIMDateTime()
|
811 w.white 1.43 {
|
812 mike 1.71 _rep = new CIMDateTimeRep;
813 memset(_rep, 0, sizeof(CIMDateTimeRep));
814 _rep->sign = ':';
|
815 mike 1.10 }
816
|
817 mike 1.71 CIMDateTime::CIMDateTime(const CIMDateTime& x)
|
818 mike 1.10 {
|
819 mike 1.71 _rep = new CIMDateTimeRep;
820 memcpy(_rep, x._rep, sizeof(CIMDateTimeRep));
|
821 w.white 1.43 }
822
|
823 mike 1.71 CIMDateTime::CIMDateTime(const String& str)
|
824 david.dillard 1.54 {
|
825 mike 1.71 _rep = new CIMDateTimeRep;
|
826 kumpf 1.78 AutoPtr<CIMDateTimeRep> autoRep(_rep); // Prevent memory leak on exception
|
827 mike 1.71 set(str);
|
828 kumpf 1.78 autoRep.release();
|
829 w.white 1.43 }
830
|
831 mike 1.71 CIMDateTime::CIMDateTime(Uint64 usec, Boolean isInterval)
|
832 w.white 1.43 {
|
833 mike 1.71 if (!isInterval && usec >= TEN_THOUSAND_YEARS)
|
834 kumpf 1.67 {
|
835 mike 1.71 MessageLoaderParms parms(
836 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
837 "Cannot create a CIMDateTime time stamp beyond the year 10,000");
838 throw DateTimeOutOfRangeException(parms);
|
839 w.white 1.43 }
|
840 mike 1.71
841 if (isInterval && usec >= HUNDRED_MILLION_DAYS)
|
842 kumpf 1.67 {
|
843 mike 1.71 MessageLoaderParms parms(
844 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
845 "Cannot create a CIMDateTime interval greater than 100 million "
846 "days");
847 throw DateTimeOutOfRangeException(parms);
|
848 w.white 1.43 }
|
849 david.dillard 1.54
|
850 mike 1.71 _rep = new CIMDateTimeRep;
851 _rep->usec = usec;
852 _rep->utcOffset = 0;
853 _rep->sign = isInterval ? ':' : '+';
854 _rep->numWildcards = 0;
855 }
856
857 CIMDateTime::CIMDateTime(
858 Uint32 year,
859 Uint32 month,
860 Uint32 day,
861 Uint32 hours,
862 Uint32 minutes,
863 Uint32 seconds,
864 Uint32 microseconds,
865 Uint32 numSignificantMicrosecondDigits,
866 Sint32 utcOffset)
867 {
868 _rep = new CIMDateTimeRep;
|
869 kumpf 1.78 AutoPtr<CIMDateTimeRep> autoRep(_rep); // Prevent memory leak on exception
|
870 mike 1.71 setTimeStamp(year, month, day, hours, minutes, seconds, microseconds,
871 numSignificantMicrosecondDigits, utcOffset);
|
872 kumpf 1.78 autoRep.release();
|
873 mike 1.71 }
874
875 CIMDateTime::CIMDateTime(
876 Uint32 days,
877 Uint32 hours,
878 Uint32 minutes,
879 Uint32 seconds,
880 Uint32 microseconds,
881 Uint32 numSignificantMicrosecondDigits)
882 {
883 _rep = new CIMDateTimeRep;
|
884 kumpf 1.78 AutoPtr<CIMDateTimeRep> autoRep(_rep); // Prevent memory leak on exception
|
885 mike 1.71 setInterval(days, hours, minutes, seconds, microseconds,
886 numSignificantMicrosecondDigits);
|
887 kumpf 1.78 autoRep.release();
|
888 mike 1.71 }
|
889 w.white 1.43
|
890 mike 1.71 CIMDateTime::CIMDateTime(CIMDateTimeRep* rep) : _rep(rep)
891 {
892 }
|
893 w.white 1.43
|
894 mike 1.71 CIMDateTime::~CIMDateTime()
895 {
896 delete _rep;
897 }
|
898 david.dillard 1.54
|
899 mike 1.71 CIMDateTime& CIMDateTime::operator=(const CIMDateTime& x)
900 {
901 if (this != &x)
902 memcpy(_rep, x._rep, sizeof(CIMDateTimeRep));
|
903 david.dillard 1.54
|
904 mike 1.71 return *this;
905 }
|
906 w.white 1.43
|
907 mike 1.71 void CIMDateTime::clear()
908 {
909 memset(_rep, 0, sizeof(CIMDateTimeRep));
910 _rep->sign = ':';
911 }
|
912 kumpf 1.67
|
913 mike 1.71 void CIMDateTime::set(const String& str)
914 {
915 clear();
|
916 w.white 1.43
|
917 mike 1.71 if (str.size() != 25)
918 throw InvalidDateTimeFormatException();
|
919 david.dillard 1.54
|
920 mike 1.71 const Uint16* s = (const Uint16*)str.getChar16Data();
921 Uint16 sign = s[21];
|
922 w.white 1.43
|
923 mike 1.71 if (sign == ':')
924 {
925 bool priorWildcards = false;
|
926 mike 1.10
|
927 mike 1.71 // It's an interval of the form "DDDDDDDDHHMMSS.MMMMMM:000"
|
928 w.white 1.43
|
929 mike 1.71 // Parse days:
|
930 kumpf 1.14
|
931 mike 1.71 Uint32 days = _parseComponent(s, 8, priorWildcards);
932 Uint32 hours = _parseComponent(s, 2, priorWildcards);
933 Uint32 minutes = _parseComponent(s, 2, priorWildcards);
934 Uint32 seconds = _parseComponent(s, 2, priorWildcards);
|
935 w.white 1.43
|
936 mike 1.71 // Skip over dot:
|
937 david.dillard 1.54
|
938 mike 1.71 if (*s++ != '.')
939 throw InvalidDateTimeFormatException();
|
940 w.white 1.43
|
941 mike 1.71 // Parse microseconds:
|
942 w.white 1.43
|
943 mike 1.71 Uint16 numSignificantMicrosecondDigits;
944 Uint32 microseconds = _parseMicroseconds(
945 s, priorWildcards, numSignificantMicrosecondDigits);
|
946 w.white 1.43
|
947 mike 1.71 // Skip over ':'.
|
948 david.dillard 1.54
|
949 mike 1.71 s++;
|
950 w.white 1.43
|
951 mike 1.71 // Expect "000".
|
952 w.white 1.43
|
953 mike 1.71 if (!(s[0] == '0' && s[1] == '0' && s[2] == '0'))
954 throw InvalidDateTimeFormatException();
|
955 w.white 1.43
|
956 mike 1.71 // Set representation:
|
957 w.white 1.43
|
958 mike 1.71 setInterval(
959 days,
960 hours,
961 minutes,
962 seconds,
963 microseconds,
964 numSignificantMicrosecondDigits);
|
965 w.white 1.43 }
|
966 mike 1.71 else if (sign == '-' || sign == '+')
967 {
968 bool priorWildcards = false;
|
969 w.white 1.43
|
970 mike 1.71 // It's a time stamp of the form "YYYYMMDDHHMMSS.MMMMMMSUTC"
|
971 w.white 1.43
|
972 mike 1.71 // Parse year, month, day, hours, minutes, seconds:
|
973 w.white 1.43
|
974 mike 1.71 Uint32 year = _parseComponent(s, 4, priorWildcards);
975 Uint32 month = _parseComponent(s, 2, priorWildcards);
976 Uint32 day = _parseComponent(s, 2, priorWildcards);
977 Uint32 hours = _parseComponent(s, 2, priorWildcards);
978 Uint32 minutes = _parseComponent(s, 2, priorWildcards);
979 Uint32 seconds = _parseComponent(s, 2, priorWildcards);
|
980 w.white 1.43
|
981 mike 1.71 // Skip over dot:
|
982 kumpf 1.14
|
983 mike 1.71 if (*s++ != '.')
984 throw InvalidDateTimeFormatException();
|
985 w.white 1.43
|
986 mike 1.71 // Parse microseconds:
|
987 w.white 1.43
|
988 mike 1.71 Uint16 numSignificantMicrosecondDigits;
989 Uint32 microseconds = _parseMicroseconds(
990 s, priorWildcards, numSignificantMicrosecondDigits);
|
991 kumpf 1.14
|
992 mike 1.71 // Skip over sign:
|
993 kumpf 1.14
|
994 mike 1.71 s++;
|
995 w.white 1.43
|
996 mike 1.71 // Parse UTF offset.
|
997 david.dillard 1.54
|
998 mike 1.71 Uint32 utcOffset;
|
999 kumpf 1.76
|
1000 mike 1.71 if (!_strToUint32(s, 3, utcOffset))
1001 throw InvalidDateTimeFormatException();
|
1002 w.white 1.43
|
1003 mike 1.71 // Set representation:
|
1004 david.dillard 1.54
|
1005 mike 1.71 setTimeStamp(
1006 year,
1007 month,
1008 day,
1009 hours,
1010 minutes,
1011 seconds,
1012 microseconds,
1013 numSignificantMicrosecondDigits,
1014 sign == '+' ? utcOffset : -Sint16(utcOffset));
|
1015 w.white 1.43 }
|
1016 david.dillard 1.54 else
|
1017 mike 1.71 {
1018 throw InvalidDateTimeFormatException();
1019 }
1020 }
|
1021 david.dillard 1.54
|
1022 mike 1.71 void CIMDateTime::setTimeStamp(
1023 Uint32 year,
1024 Uint32 month,
1025 Uint32 day,
1026 Uint32 hours,
1027 Uint32 minutes,
1028 Uint32 seconds,
1029 Uint32 microseconds,
1030 Uint32 numSignificantMicrosecondDigits,
1031 Sint32 utcOffset)
1032 {
1033 clear();
|
1034 kumpf 1.26
|
1035 mike 1.71 Uint32 numWildcards = 0;
|
1036 w.white 1.43
|
1037 mike 1.71 // Check Year:
|
1038 w.white 1.43
|
1039 david.dillard 1.54
|
1040 mike 1.71 if (year == WILDCARD)
1041 {
1042 year = 0;
1043 numWildcards = 20;
1044 }
1045 else if (year > 9999)
1046 {
1047 MessageLoaderParms parms(
1048 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1049 "year is greater than 9999");
1050 throw DateTimeOutOfRangeException(parms);
|
1051 w.white 1.43 }
1052
|
1053 mike 1.71 // Check Month:
|
1054 david.dillard 1.54
|
1055 mike 1.71 if (month == WILDCARD)
1056 {
1057 month = 1;
|
1058 david.dillard 1.54
|
1059 mike 1.71 if (!numWildcards)
1060 numWildcards = 16;
1061 }
1062 else if (month < 1 || month > 12)
1063 {
1064 MessageLoaderParms parms(
1065 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1066 "illegal month number");
1067 throw DateTimeOutOfRangeException(parms);
1068 }
|
1069 w.white 1.43
|
1070 mike 1.71 // Check day:
|
1071 w.white 1.43
|
1072 mike 1.71 if (day == WILDCARD)
1073 {
1074 day = 1;
|
1075 w.white 1.43
|
1076 mike 1.71 if (!numWildcards)
1077 numWildcards = 14;
1078 }
1079 else if (day < 1 || day > _getDaysPerMonth(year, month))
1080 {
1081 MessageLoaderParms parms(
1082 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1083 "illegal day number");
1084 throw DateTimeOutOfRangeException(parms);
1085 }
|
1086 w.white 1.43
|
1087 mike 1.71 // Check hours:
|
1088 w.white 1.43
|
1089 mike 1.71 if (hours == WILDCARD)
1090 {
1091 hours = 0;
|
1092 david.dillard 1.54
|
1093 mike 1.71 if (!numWildcards)
1094 numWildcards = 12;
|
1095 w.white 1.43 }
|
1096 mike 1.71 else if (hours > 23)
1097 {
1098 MessageLoaderParms parms(
1099 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1100 "illegal hours number ");
1101 throw DateTimeOutOfRangeException(parms);
|
1102 w.white 1.43 }
1103
|
1104 mike 1.71 // Check minutes:
|
1105 w.white 1.43
|
1106 mike 1.71 if (minutes == WILDCARD)
1107 {
1108 minutes = 0;
|
1109 w.white 1.43
|
1110 mike 1.71 if (!numWildcards)
1111 numWildcards = 10;
1112 }
1113 else if (minutes > 59)
1114 {
1115 MessageLoaderParms parms(
1116 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1117 "illegal minutes number ");
1118 throw DateTimeOutOfRangeException(parms);
1119 }
|
1120 w.white 1.43
|
1121 mike 1.71 // Check seconds:
|
1122 w.white 1.43
|
1123 mike 1.71 if (seconds == WILDCARD)
1124 {
1125 seconds = 0;
|
1126 kumpf 1.14
|
1127 mike 1.71 if (!numWildcards)
1128 numWildcards = 8;
1129 }
1130 else if (seconds > 59)
1131 {
1132 MessageLoaderParms parms(
1133 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1134 "illegal seconds number ");
1135 throw DateTimeOutOfRangeException(parms);
1136 }
|
1137 w.white 1.43
|
1138 mike 1.71 // Check microseconds:
|
1139 kumpf 1.68
|
1140 mike 1.71 if (numSignificantMicrosecondDigits > 6)
|
1141 kumpf 1.68 {
|
1142 mike 1.71 MessageLoaderParms parms(
1143 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1144 "bad numSignificantMicrosecondDigits (must fall between 0 and 6)");
1145 throw DateTimeOutOfRangeException(parms);
|
1146 w.white 1.43 }
|
1147 mike 1.71
1148 if (microseconds > 999999)
|
1149 kumpf 1.68 {
|
1150 mike 1.71 MessageLoaderParms parms(
1151 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1152 "microseconds number must be less than 999999");
1153 throw DateTimeOutOfRangeException(parms);
|
1154 w.white 1.43 }
|
1155 kumpf 1.20
|
1156 mike 1.71 if (!numWildcards)
1157 numWildcards = 6 - numSignificantMicrosecondDigits;
|
1158 david.dillard 1.54
|
1159 mike 1.71 // Check UTC offset:
1160
1161 if (utcOffset < -999 || utcOffset > 999)
|
1162 kumpf 1.68 {
|
1163 mike 1.71 MessageLoaderParms parms(
1164 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1165 "illegal utcOffset");
1166 throw DateTimeOutOfRangeException(parms);
|
1167 kumpf 1.14 }
|
1168 kumpf 1.68
|
1169 mike 1.71 // Set the representation.
|
1170 w.white 1.43
|
1171 mike 1.71 Uint32 days = _toJulianDay(year, month, day) - JULIAN_ONE_BCE;
|
1172 w.white 1.43
|
1173 mike 1.71 // Multiply in 64-bit to prevent overflow.
1174 _rep->usec =
1175 Uint64(microseconds) +
1176 Uint64((seconds * SECOND)) +
1177 Uint64((minutes * MINUTE)) +
1178 Uint64((hours * HOUR)) +
1179 Uint64((days * DAY));
1180 _rep->sign = utcOffset < 0 ? '-' : '+';
1181 _rep->utcOffset = utcOffset < 0 ? -utcOffset : utcOffset;
1182 _rep->numWildcards = numWildcards;
1183 }
1184
1185 void CIMDateTime::setInterval(
1186 Uint32 days,
1187 Uint32 hours,
1188 Uint32 minutes,
1189 Uint32 seconds,
1190 Uint32 microseconds,
1191 Uint32 numSignificantMicrosecondDigits)
1192 {
1193 clear();
|
1194 w.white 1.43
|
1195 mike 1.71 Uint32 numWildcards = 0;
|
1196 david.dillard 1.54
|
1197 mike 1.71 // Check days:
|
1198 w.white 1.43
|
1199 mike 1.71 if (days == WILDCARD)
1200 {
1201 days = 1;
|
1202 david.dillard 1.54
|
1203 mike 1.71 if (!numWildcards)
1204 numWildcards = 20;
|
1205 w.white 1.43 }
|
1206 mike 1.71 else if (days > 99999999)
1207 {
1208 MessageLoaderParms parms(
1209 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1210 "illegal days number (must be less than 100000000");
1211 throw DateTimeOutOfRangeException(parms);
|
1212 w.white 1.43 }
|
1213 mike 1.71
1214 // Check hours:
1215
1216 if (hours == WILDCARD)
1217 {
1218 hours = 0;
1219
1220 if (!numWildcards)
1221 numWildcards = 12;
|
1222 david.dillard 1.54 }
|
1223 mike 1.71 else if (hours > 23)
1224 {
1225 MessageLoaderParms parms(
1226 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1227 "illegal hours number ");
1228 throw DateTimeOutOfRangeException(parms);
|
1229 w.white 1.43 }
1230
|
1231 mike 1.71 // Check minutes:
1232
1233 if (minutes == WILDCARD)
1234 {
1235 minutes = 0;
|
1236 w.white 1.43
|
1237 mike 1.71 if (!numWildcards)
1238 numWildcards = 10;
1239 }
1240 else if (minutes > 59)
1241 {
1242 MessageLoaderParms parms(
1243 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1244 "illegal minutes number ");
1245 throw DateTimeOutOfRangeException(parms);
1246 }
|
1247 w.white 1.43
|
1248 mike 1.71 // Check seconds:
|
1249 w.white 1.43
|
1250 mike 1.71 if (seconds == WILDCARD)
1251 {
1252 seconds = 0;
|
1253 david.dillard 1.54
|
1254 mike 1.71 if (!numWildcards)
1255 numWildcards = 8;
|
1256 w.white 1.43 }
|
1257 mike 1.71 else if (seconds > 59)
1258 {
1259 MessageLoaderParms parms(
1260 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1261 "illegal seconds number ");
1262 throw DateTimeOutOfRangeException(parms);
1263 }
1264
1265 // Check microseconds:
|
1266 w.white 1.43
|
1267 mike 1.71 if (numSignificantMicrosecondDigits > 6)
1268 {
1269 MessageLoaderParms parms(
1270 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1271 "bad numSignificantMicrosecondDigits (must fall between 0 and 6)");
1272 throw DateTimeOutOfRangeException(parms);
|
1273 w.white 1.43 }
|
1274 david.dillard 1.54
|
1275 mike 1.71 if (microseconds > 999999)
1276 {
1277 MessageLoaderParms parms(
1278 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1279 "microseconds number must be less than 999999");
1280 throw DateTimeOutOfRangeException(parms);
1281 }
|
1282 david.dillard 1.54
|
1283 mike 1.71 if (!numWildcards)
1284 numWildcards = 6 - numSignificantMicrosecondDigits;
|
1285 w.white 1.43
|
1286 mike 1.71 // Set the representation.
|
1287 w.white 1.43
|
1288 mike 1.71 _rep->usec =
1289 microseconds +
1290 (seconds * SECOND) +
1291 (minutes * MINUTE) +
1292 (hours * HOUR) +
1293 (days * DAY);
1294 _rep->sign = ':';
1295 _rep->utcOffset = 0;
1296 _rep->numWildcards = numWildcards;
1297 }
|
1298 david.dillard 1.54
|
1299 mike 1.71 String CIMDateTime::toString() const
1300 {
1301 Char16 str[26];
1302 _toChar16Str(_rep, str);
1303 return String(str, 25);
|
1304 w.white 1.43 }
1305
|
1306 mike 1.71 Sint64 CIMDateTime::getDifference(CIMDateTime x, CIMDateTime y)
1307 {
1308 if (x.isInterval() != y.isInterval())
1309 throw InvalidDateTimeFormatException();
|
1310 w.white 1.43
|
1311 mike 1.71 return y.toMicroSeconds() - x.toMicroSeconds();
1312 }
|
1313 w.white 1.43
|
1314 mike 1.71 Boolean CIMDateTime::isInterval() const
|
1315 w.white 1.43 {
|
1316 mike 1.71 return _rep->sign == ':';
1317 }
|
1318 w.white 1.43
|
1319 mike 1.71 Boolean CIMDateTime::isInterval()
1320 {
1321 return _rep->sign == ':';
1322 }
|
1323 w.white 1.43
|
1324 mike 1.71 Boolean CIMDateTime::isTimeStamp() const
1325 {
1326 return _rep->sign != ':';
1327 }
|
1328 david.dillard 1.54
|
1329 mike 1.71 Uint64 CIMDateTime::toMicroSeconds() const
1330 {
1331 return _toMicroSeconds(_rep);
1332 }
|
1333 w.white 1.43
|
1334 mike 1.71 Boolean CIMDateTime::equal(const CIMDateTime& x) const
1335 {
1336 return _compare(_rep, x._rep) == 0;
1337 }
|
1338 w.white 1.43
|
1339 mike 1.71 CIMDateTime CIMDateTime::operator+(const CIMDateTime& x) const
1340 {
1341 CIMDateTime result(*this);
1342 return result+=(x);
|
1343 w.white 1.43 }
1344
|
1345 mike 1.71 CIMDateTime& CIMDateTime::operator+=(const CIMDateTime& x)
|
1346 w.white 1.43 {
|
1347 mike 1.71 // ATTN: check for overflow?
|
1348 w.white 1.43
|
1349 mike 1.71 if (!x.isInterval())
1350 throw TypeMismatchException();
|
1351 david.dillard 1.54
|
1352 mike 1.71 if (isInterval())
1353 _rep->usec += x._rep->usec;
1354 else
1355 _rep->usec += x.toMicroSeconds();
|
1356 david.dillard 1.54
|
1357 mike 1.71 return *this;
|
1358 w.white 1.43 }
1359
|
1360 mike 1.71 CIMDateTime CIMDateTime::operator-(const CIMDateTime& dt) const
|
1361 w.white 1.43 {
|
1362 mike 1.71 // ATTN: check for overflow?
1363 // ATTN: use operator-=()?
|
1364 w.white 1.43
|
1365 mike 1.71 if (isInterval() && !dt.isInterval())
|
1366 david.dillard 1.54 throw TypeMismatchException();
|
1367 w.white 1.43
|
1368 mike 1.71 Uint64 x = toMicroSeconds();
1369 Uint64 y = dt.toMicroSeconds();
|
1370 w.white 1.43
|
1371 mike 1.71 if (x < y)
1372 {
1373 MessageLoaderParms parms(
1374 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1375 "Result of subtracting two CIMDateTimes would be negative.");
1376 throw DateTimeOutOfRangeException(parms);
|
1377 w.white 1.43 }
1378
|
1379 mike 1.71 if (isInterval() == dt.isInterval())
1380 {
|
1381 kumpf 1.76 // TIMESTAMP - TIMESTAMP
|
1382 mike 1.71 // OR
1383 // INTERVAL - INTERVAL
1384 return CIMDateTime(x - y, true);
|
1385 w.white 1.43 }
|
1386 mike 1.71 else
1387 {
1388 // TIMESTAMP - INTERVAL (INTERVAL - TIMESTAMP eliminated above).
1389 CIMDateTime tmp(x - y, false);
1390 tmp._rep->sign = _rep->sign;
1391 tmp._rep->utcOffset = _rep->utcOffset;
1392 tmp._rep->numWildcards = _rep->numWildcards;
1393 return tmp;
|
1394 w.white 1.43 }
|
1395 mike 1.71 }
|
1396 w.white 1.43
|
1397 mike 1.71 CIMDateTime& CIMDateTime::operator-=(const CIMDateTime& x)
1398 {
1399 // ATTN: check for overflow?
|
1400 david.dillard 1.54
|
1401 mike 1.71 if (!x.isInterval())
1402 throw TypeMismatchException();
|
1403 w.white 1.43
|
1404 mike 1.71 if (_rep->usec < x._rep->usec)
1405 {
1406 MessageLoaderParms parms(
1407 "Common.Exception.DATETIME_OUT_OF_RANGE_EXCEPTION",
1408 "Result of subtracting two CIMDateTimes would be negative.");
1409 throw DateTimeOutOfRangeException(parms);
1410 }
|
1411 w.white 1.43
|
1412 mike 1.71 if (isInterval())
1413 _rep->usec -= x._rep->usec;
1414 else
1415 _rep->usec -= x.toMicroSeconds();
|
1416 w.white 1.43
|
1417 mike 1.71 return *this;
1418 }
|
1419 w.white 1.43
|
1420 mike 1.71 CIMDateTime CIMDateTime::operator*(Uint64 x) const
|
1421 w.white 1.43 {
|
1422 mike 1.71 CIMDateTime result(*this);
1423 return result*=(x);
1424 }
|
1425 w.white 1.43
|
1426 marek 1.73 CIMDateTime& CIMDateTime::operator*=(Uint64 x)
|
1427 mike 1.71 {
1428 if (!isInterval())
1429 throw TypeMismatchException();
|
1430 w.white 1.43
|
1431 mike 1.71 _rep->usec *= x;
1432 return *this;
1433 }
|
1434 w.white 1.43
|
1435 mike 1.71 CIMDateTime CIMDateTime::operator/(Uint64 x) const
1436 {
1437 CIMDateTime result(*this);
1438 return result/=(x);
|
1439 w.white 1.43 }
1440
|
1441 marek 1.73 CIMDateTime& CIMDateTime::operator/=(Uint64 x)
|
1442 mike 1.71 {
1443 if (!isInterval())
1444 {
1445 MessageLoaderParms parms(
1446 "Common.CIMDateTime.INVALID_OPERATION_DIV_INT",
1447 "Can not divide a TimeStamp by an integer");
1448 throw TypeMismatchException(parms);
1449 }
|
1450 w.white 1.43
|
1451 kumpf 1.76 if (x == 0)
|
1452 mike 1.71 {
1453 MessageLoaderParms parms(
1454 "Common.CIMDateTime.INVALID_OPERATION_DIV_ZERO",
1455 "Can not divide CIMDateTime by zero");
1456 throw Exception(parms);
1457 }
|
1458 w.white 1.43
|
1459 mike 1.71 _rep->usec /= x;
1460 return *this;
1461 }
|
1462 w.white 1.43
|
1463 mike 1.71 Uint64 CIMDateTime::operator/(const CIMDateTime& x) const
|
1464 w.white 1.43 {
|
1465 mike 1.71 if (!isInterval() || !x.isInterval())
1466 {
1467 MessageLoaderParms parms(
1468 "Common.CIMDateTime.INVALID_OPERATION_DIV_TS",
1469 "Can not divide two CIMDateTime objects if one of them is "
1470 "a TimeStamp");
1471 throw TypeMismatchException(parms);
1472 }
|
1473 david.dillard 1.54
|
1474 kumpf 1.76 if (x._rep->usec == 0)
|
1475 mike 1.71 {
1476 MessageLoaderParms parms(
1477 "Common.CIMDateTime.INVALID_OPERATION_DIV_ZERO",
1478 "Can not divide CIMDateTime by zero");
1479 throw Exception(parms);
|
1480 w.white 1.43 }
|
1481 kumpf 1.14
|
1482 mike 1.71 return _rep->usec / x._rep->usec;
1483 }
|
1484 w.white 1.43
|
1485 mike 1.71 Boolean CIMDateTime::operator<(const CIMDateTime& x) const
1486 {
1487 return _compare(_rep, x._rep) < 0;
1488 }
|
1489 w.white 1.43
|
1490 mike 1.71 Boolean CIMDateTime::operator<=(const CIMDateTime& x) const
1491 {
1492 return _compare(_rep, x._rep) <= 0;
1493 }
|
1494 david.dillard 1.54
|
1495 mike 1.71 Boolean CIMDateTime::operator>(const CIMDateTime& x) const
1496 {
1497 return _compare(_rep, x._rep) > 0;
1498 }
|
1499 w.white 1.43
|
1500 mike 1.71 Boolean CIMDateTime::operator>=(const CIMDateTime& x) const
1501 {
1502 return _compare(_rep, x._rep) >= 0;
|
1503 w.white 1.43 }
1504
|
1505 mike 1.71 Boolean CIMDateTime::operator!=(const CIMDateTime& x) const
1506 {
1507 return _compare(_rep, x._rep) != 0;
1508 }
|
1509 w.white 1.43
|
1510 mike 1.71 Boolean operator==(const CIMDateTime& x, const CIMDateTime& y)
|
1511 w.white 1.43 {
|
1512 mike 1.71 return x.equal(y);
|
1513 w.white 1.43 }
1514
|
1515 mike 1.71 //==============================================================================
1516 //
1517 // PEGASUS_OS_TYPE_UNIX
1518 //
1519 //==============================================================================
|
1520 w.white 1.43
|
1521 carson.hovey 1.75 #if defined(PEGASUS_OS_TYPE_UNIX) || defined(PEGASUS_OS_VMS)
|
1522 w.white 1.43
|
1523 mike 1.71 CIMDateTime CIMDateTime::getCurrentDateTime()
|
1524 w.white 1.43 {
|
1525 mike 1.71 // Get sec and usec:
|
1526 w.white 1.43
|
1527 mike 1.71 time_t sec;
1528 Uint64 usec;
|
1529 marek 1.74 // ATTN: if this fails on your platform, use time() to obtain the
1530 // sec element and set usec to zero.
1531 struct timeval tv;
|
1532 carson.hovey 1.75 #if defined(PEGASUS_OS_VMS)
1533 void *tz = NULL;
1534 #else
|
1535 marek 1.74 struct timezone tz;
|
1536 carson.hovey 1.75 #endif
|
1537 marek 1.74 gettimeofday(&tv, &tz);
1538 sec = tv.tv_sec;
1539 usec = Uint64(tv.tv_usec);
|
1540 kumpf 1.14
|
1541 mike 1.71 // Get the localtime
|
1542 david.dillard 1.54
|
1543 mike 1.71 struct tm* tmval;
1544 struct tm tmvalBuffer;
1545 tmval = localtime_r(&sec, &tmvalBuffer);
1546 PEGASUS_ASSERT(tmval != 0);
|
1547 w.white 1.43
|
1548 mike 1.71 // Calculate minutes East of GMT.
|
1549 w.white 1.43
|
1550 mike 1.71 int tzMinutesEast;
1551 {
1552 # if defined(PEGASUS_OS_SOLARIS)
|
1553 kumpf 1.76 tzMinutesEast =
|
1554 mike 1.71 -(int)((tmval->tm_isdst > 0 && daylight) ? altzone : timezone) / 60;
1555 # elif defined(PEGASUS_OS_HPUX)
1556 tzMinutesEast = - (int) timezone / 60;
1557 if ((tmval->tm_isdst > 0) && daylight)
1558 {
|
1559 kumpf 1.76 // ATTN: It is unclear how to determine the DST offset.
|
1560 mike 1.71 // Assume 1 hour.
1561 tzMinutesEast += 60;
1562 }
|
1563 carson.hovey 1.75 # elif defined(PEGASUS_OS_LINUX) || defined(PEGASUS_OS_VMS)
|
1564 mike 1.71 tzMinutesEast = (int) tmval->tm_gmtoff/60;
1565 # else
|
1566 kumpf 1.77 tzMinutesEast = -tz.tz_minuteswest;
|
1567 marek 1.74 if (tz.tz_dsttime > 0)
|
1568 kumpf 1.77 {
|
1569 kumpf 1.76 // ATTN: It is unclear how to determine the DST offset.
|
1570 marek 1.74 // Assume 1 hour.
|
1571 kumpf 1.77 tzMinutesEast += 60;
1572 }
|
1573 mike 1.71 # endif
1574 }
|
1575 w.white 1.43
|
1576 mike 1.71 // Create the representation object.
|
1577 w.white 1.43
|
1578 mike 1.71 CIMDateTimeRep* rep = new CIMDateTimeRep;
|
1579 kumpf 1.76 rep->usec =
|
1580 kumpf 1.77 POSIX_1970_EPOCH_OFFSET +
1581 Uint64(sec + tzMinutesEast * 60) * Uint64(1000000) +
1582 Uint64(usec);
|
1583 mike 1.71 rep->sign = tzMinutesEast < 0 ? '-' : '+';
1584 rep->utcOffset = tzMinutesEast < 0 ? -tzMinutesEast : tzMinutesEast;
1585 rep->numWildcards = 0;
|
1586 w.white 1.43
|
1587 mike 1.71 return CIMDateTime(rep);
1588 }
|
1589 w.white 1.43
|
1590 mike 1.71 #endif /* PEGASUS_OS_TYPE_UNIX */
|
1591 w.white 1.43
|
1592 mike 1.71 //==============================================================================
1593 //
1594 // PEGASUS_OS_TYPE_WINDOWS
1595 //
1596 //==============================================================================
|
1597 w.white 1.43
|
1598 mike 1.71 #if defined(PEGASUS_OS_TYPE_WINDOWS)
|
1599 w.white 1.43
|
1600 mike 1.71 Boolean getCurrentTimeZone(Sint16& currentTimeZone)
|
1601 w.white 1.43 {
|
1602 mike 1.71 currentTimeZone = 0;
1603 TIME_ZONE_INFORMATION timezone;
1604 ::memset(&timezone, 0, sizeof(timezone));
|
1605 david.dillard 1.54
|
1606 kumpf 1.76 switch(::GetTimeZoneInformation(&timezone))
|
1607 mike 1.71 {
1608 case TIME_ZONE_ID_UNKNOWN:
1609 {
1610 currentTimeZone = static_cast<Sint16>(timezone.Bias);
1611 break;
1612 }
|
1613 w.white 1.43
|
1614 mike 1.71 case TIME_ZONE_ID_STANDARD:
1615 {
|
1616 kumpf 1.76 currentTimeZone =
|
1617 mike 1.71 static_cast<Sint16>(timezone.Bias + timezone.StandardBias);
1618 break;
1619 }
|
1620 w.white 1.43
|
1621 mike 1.71 case TIME_ZONE_ID_DAYLIGHT:
1622 {
|
1623 kumpf 1.76 currentTimeZone =
|
1624 mike 1.71 static_cast<Sint16>(timezone.Bias + timezone.DaylightBias);
1625 break;
1626 }
|
1627 w.white 1.43
|
1628 mike 1.71 default:
1629 break;
|
1630 kumpf 1.20 }
|
1631 w.white 1.43
|
1632 kumpf 1.76 // the bias used to calculate the time zone is a factor that is used to
1633 // determine the UTC time from the local time. to get the UTC offset from
|
1634 mike 1.71 // the local time, use the inverse.
|
1635 w.white 1.43
|
1636 kumpf 1.76 if (currentTimeZone != 0)
|
1637 mike 1.71 {
1638 currentTimeZone *= -1;
1639 }
|
1640 w.white 1.43
|
1641 mike 1.71 return true;
1642 }
|
1643 w.white 1.43
|
1644 mike 1.71 CIMDateTime CIMDateTime::getCurrentDateTime()
|
1645 w.white 1.43 {
|
1646 mike 1.71 // Get system time.
|
1647 w.white 1.43
|
1648 mike 1.71 SYSTEMTIME time;
1649 memset(&time, 0, sizeof(time));
1650 GetLocalTime(&time);
|
1651 david.dillard 1.54
|
1652 mike 1.71 // Get UTC offset.
|
1653 kumpf 1.20
|
1654 mike 1.71 Sint32 utcOffset = 0;
1655 Sint16 currentTimeZone;
|
1656 kumpf 1.20
|
1657 mike 1.71 if (getCurrentTimeZone(currentTimeZone))
1658 utcOffset = currentTimeZone;
|
1659 w.white 1.43
|
1660 mike 1.71 // Create the CIMDateTime object.
|
1661 w.white 1.43
|
1662 mike 1.71 return CIMDateTime(
1663 time.wYear,
1664 time.wMonth,
1665 time.wDay,
1666 time.wHour,
1667 time.wMinute,
1668 time.wSecond,
1669 time.wMilliseconds * 1000,
1670 6,
1671 utcOffset);
|
1672 w.white 1.43 }
1673
|
1674 mike 1.71 #endif /* PEGASUS_OS_TYPE_WINDOWS */
|
1675 w.white 1.43
|
1676 mike 1.71 /*
1677 ================================================================================
|
1678 w.white 1.43
|
1679 mike 1.71 Notes:
|
1680 w.white 1.43
|
1681 mike 1.71 (1) The legacy implementation added the UTC offset when it was negative and
|
1682 kumpf 1.76 substracted it when it was positive. I preserved this behavior but
|
1683 mike 1.71 suspect it may be wrong.
|
1684 kumpf 1.20
|
1685 mike 1.71 (2) Evenetually change getCurrentDateTime() to use constructor that takes
1686 a single microseconds component.
|
1687 kumpf 1.14
|
1688 mike 1.71 (4) Add overflow checking for adds and multiplies.
|
1689 david.dillard 1.54
|
1690 mike 1.71 ================================================================================
1691 */
|
1692 w.white 1.43
|
1693 mike 1.10 PEGASUS_NAMESPACE_END
|