@@ -38,49 +38,40 @@ namespace mongo {
3838    Value::~Value () {
3939    }
4040
41-     Value::Value ():
42-         type (jstNULL),
43-         oidValue (),
44-         dateValue (),
45-         stringValue (),
46-         pDocumentValue (),
47-         vpValue () {
48-     }
41+     Value::Value (): type(jstNULL) {}
4942
50-     Value::Value (BSONType theType):
51-         type (theType),
52-         oidValue (),
53-         dateValue (),
54-         stringValue (),
55-         pDocumentValue (),
56-         vpValue () {
43+     Value::Value (BSONType theType): type(theType) {
5744        switch (type) {
5845        case  Undefined:
5946        case  jstNULL:
6047        case  Object: //  empty
6148        case  Array: //  empty
6249            break ;
6350
64-         case  NumberDouble:
65-             doubleValue = 0 ;
66-             break ;
67- 
6851        case  Bool:
6952            boolValue = false ;
7053            break ;
7154
72-         case  NumberInt :
73-             intValue  = 0 ;
55+         case  NumberDouble :
56+             doubleValue  = 0 ;
7457            break ;
7558
76-         case  Timestamp :
77-             timestampValue  = OpTime () ;
59+         case  NumberInt :
60+             intValue  = 0 ;
7861            break ;
7962
8063        case  NumberLong:
8164            longValue = 0 ;
8265            break ;
8366
67+         case  Date:
68+             dateValue = 0 ;
69+             break ;
70+ 
71+         case  Timestamp:
72+             timestampValue = OpTime ();
73+             break ;
74+ 
8475        default :
8576            //  nothing else is allowed
8677            uassert (16001 , str::stream () <<
@@ -153,7 +144,8 @@ namespace mongo {
153144            break ;
154145
155146        case  Date:
156-             dateValue = pBsonElement->Date ();
147+             //  this is really signed but typed as unsigned for historical reasons
148+             dateValue = static_cast <long  long >(pBsonElement->Date ().millis );
157149            break ;
158150
159151        case  RegEx:
@@ -233,15 +225,10 @@ namespace mongo {
233225        return  pValue;
234226    }
235227
236-     Value::Value (const  Date_t &value):
237-         type(Date),
238-         pDocumentValue(),
239-         vpValue() {
240-         dateValue = value;
241-     }
242- 
243-     intrusive_ptr<const  Value> Value::createDate (const  Date_t &value) {
244-         intrusive_ptr<const  Value> pValue (new  Value (value));
228+     intrusive_ptr<const  Value> Value::createDate (const  long  long  &value) {
229+         //  Can't directly construct because constructor would clash with createLong
230+         intrusive_ptr<Value> pValue (new  Value (Date));
231+         pValue->dateValue  = value;
245232        return  pValue;
246233    }
247234
@@ -353,7 +340,7 @@ namespace mongo {
353340        return  boolValue;
354341    }
355342
356-     Date_t  Value::getDate () const  {
343+     long   long  Value::getDate () const  {
357344        verify (getType () == Date);
358345        return  dateValue;
359346    }
@@ -431,7 +418,7 @@ namespace mongo {
431418            break ;
432419
433420        case  Date:
434-             pBuilder->append (getDate ());
421+             pBuilder->append (Date_t ( getDate () ));
435422            break ;
436423
437424        case  RegEx:
@@ -622,14 +609,14 @@ namespace mongo {
622609        return  (double )0 ;
623610    }
624611
625-     Date_t  Value::coerceToDate () const  {
612+     long   long  Value::coerceToDate () const  {
626613        switch (type) {
627614
628615        case  Date:
629616            return  dateValue; 
630617
631618        case  Timestamp:
632-             return  Date_t ( timestampValue.getSecs () * 1000ULL ) ;
619+             return  timestampValue.getSecs () * 1000LL ;
633620
634621        default :
635622            uassert (16006 , str::stream () <<
@@ -638,6 +625,49 @@ namespace mongo {
638625        } //  switch(type)
639626    }
640627
628+     time_t  Value::coerceToTimeT () const  {
629+         long  long  millis = coerceToDate ();
630+         if  (millis < 0 ) {
631+             //  We want the division below to truncate toward -inf rather than 0
632+             //  eg Dec 31, 1969 23:59:58.001 should be -2 seconds rather than -1
633+             //  This is needed to get the correct values from coerceToTM
634+             if  ( -1999  / 1000  != -2 ) { //  this is implementation defined
635+                 millis -= 1000 -1 ;
636+             }
637+         }
638+         const  long  long  seconds = millis / 1000 ;
639+ 
640+         uassert (16421 , " Can't handle date values outside of time_t range"  ,
641+                seconds >= std::numeric_limits<time_t >::min () &&
642+                seconds <= std::numeric_limits<time_t >::max ());
643+ 
644+         return  static_cast <time_t >(seconds);
645+     }
646+     tm Value::coerceToTm () const  {
647+         //  See implementation in Date_t.
648+         //  Can't reuse that here because it doesn't support times before 1970
649+         time_t  dtime = coerceToTimeT ();
650+         tm out;
651+ 
652+ #if  defined(_WIN32) //  Both the argument order and the return values differ
653+         bool  itWorked = gmtime_s (&out, &dtime) == 0 ;
654+ #else 
655+         bool  itWorked = gmtime_r (&dtime, &out) != NULL ;
656+ #endif 
657+ 
658+         if  (!itWorked) {
659+             if  (dtime < 0 ) {
660+                 //  Windows docs say it doesn't support these, but empirically it seems to work
661+                 uasserted (16422 , " gmtime failed - your system doesn't support dates before 1970"  );
662+             }
663+             else  {
664+                 uasserted (16423 , str::stream () << " gmtime failed to convert time_t of "   << dtime);
665+             }
666+         }
667+ 
668+         return  out;
669+     }
670+ 
641671    string Value::coerceToString () const  {
642672        stringstream ss;
643673        switch (type) {
@@ -661,7 +691,7 @@ namespace mongo {
661691            return  ss.str ();
662692
663693        case  Date:
664-             return  dateValue. toString ( );
694+             return  time_t_to_String ( coerceToTimeT () );
665695
666696        case  jstNULL:
667697        case  Undefined:
@@ -842,10 +872,8 @@ namespace mongo {
842872            return  -1 ;
843873
844874        case  Date: {
845-             //  need to convert to long long to handle dates before 1970
846-             //  see BSONElement::compareElementValues
847-             long  long  l = static_cast <long  long >(rL->dateValue .millis );
848-             long  long  r = static_cast <long  long >(rR->dateValue .millis );
875+             long  long  l = rL->dateValue ;
876+             long  long  r = rR->dateValue ;
849877            if  (l < r)
850878                return  -1 ;
851879            if  (l > r)
@@ -938,7 +966,7 @@ namespace mongo {
938966            break ;
939967
940968        case  Date:
941-             boost::hash_combine (seed, ( unsigned   long   long ) dateValue);
969+             boost::hash_combine (seed, dateValue);
942970            break ;
943971
944972        case  RegEx:
0 commit comments