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