(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.78.4.1             "%04u%02u%02u%02u%02u%02u.%06u%c%03u",
 505 mike          1.71                 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