(file) Return to CIMDateTime.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

   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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2