1>garden.cpp(59): error C2061: syntax error : identifier 'Date' 1>garden.cpp(59): error C2228: left of '.obj' must have class/struct/union 1>garden.cpp(59): error C2143: syntax error : missing ';' before ')' 1>garden.cpp(59): error C2143: syntax error : missing ';' before ')'
Which tells me I have no idea how to assign a date with the C++ driver. For the life of me, I couldn't find anything in the online docs or a google search except for a ticket requesting examples in the documentation.
You're looking for a mongo::Date_t object, which will get serialized with BSON's datetime type. Its constructor takes an integer representing milliseconds since the epoch. See [1] for its definition. Once you've initialized one, you can pass it in directly to the BSON() macro in place of where "new Date(...)" was in your snippet.
You also have other options for ways to generate BSON datetime values. Here's your example using C-style dates (see [2] for definitions of the various BSONObjBuilder helper methods):
> 1>garden.cpp(59): error C2061: syntax error : identifier 'Date' > 1>garden.cpp(59): error C2228: left of '.obj' must have class/struct/union > 1>garden.cpp(59): error C2143: syntax error : missing ';' before ')' > 1>garden.cpp(59): error C2143: syntax error : missing ';' before ')'
> Which tells me I have no idea how to assign a date with the C++ driver. For the life of me, I couldn't find anything in the online docs or a google search except for a ticket requesting examples in the documentation.
So, the trick is not to use the BSON helpers? There isn't a way to assign a date with BSON? Or can I set the date to a BSONElement and then stream it with BSON?
If not, I'll stop using BSON when building my BSONObjs. Doesn't this mean BSON is fairly limited?
No, that wasn't what I was saying. I presented two different solutions; the first used the BSON() macro, and the second didn't. I'll spell out the first one more explicitly:
long long birthDateInMillisSinceEpoch = ...; mongo::BSONObj doc = BSON(mongo::GENOID << "name" << "George" << "birthdate" << new mongo::Date_t(birthDateInMillisSinceEpoch));
You can generate "birthDateInMillisSinceEpoch" using POSIX functions like the ones I called before, or Boost's Date-Time library, etc.
It's illustrative to see the BSONObjBuilder methods being used explicitly, since the BSON() macro stream operator is implemented with BSONObjBuilder. To see a list of all of the different objects you can use the stream syntax with, see all of the implementations of append() in the bsonobjbuilder.h file I linked to earlier.
On Wednesday, October 31, 2012 4:39:46 PM UTC-7, George Thompson wrote:
> So, the trick is not to use the BSON helpers? There isn't a way to assign > a date with BSON? Or can I set the date to a BSONElement and then stream it > with BSON?
> If not, I'll stop using BSON when building my BSONObjs. Doesn't this mean > BSON is fairly limited?
Your solution has the right idea. See [1] for a similar but more succinct one (the snippet under the "Boost to Mongo" section of the question). When you're generalizing, make sure you handle dates before the epoch correctly (these are represented by Date_t objects initialized with negative values).
Passing in the Date_t object to the << operator without calling "new" is correct (I left it in as a typo when copy-pasting your original line). "new" returns a pointer, which C++ will implicitly cast to a bool here, throwing away the date information you're trying to serialize (in addition to creating a memory leak).
// Create a mongo date (Date_t) from year, month, and day passed as integers // (year = with century, month = 1 - 12, day = 1-31) mongo::Date_t MongoDate(const int &year, const int &month, const int &day) { boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); try { boost::posix_time::ptime ptime_date(boost::gregorian::date(year,month,day)); boost::posix_time::time_duration const diff = ptime_date - epoch; long long ms = diff.total_milliseconds(); return mongo::Date_t(ms); } catch (std::out_of_range& oor) { std::cerr << year << "-" << month << "-" << day << " is an invalid date: " << oor.what() << endl; return mongo::Date_t(0); } }
(Note: Please ignore the absurdity of returning mongo::Date_t(0) -- I'm either going to use Boost::Optional to return a NULL or stop using BSON and handling the addition of dates with a function using BSONObjBuilder).
This works for the full range of boost dates, 1400 - 10000. I'm confused why it works since Date_t is an unsigned long long. However, after executing "birthdate" << MongoDate(1960,4,16), the shell's db.personnel.find() displays ISODate("1960-04-16T00:00:00Z") and "cout << doc.toString() << endl" displays "new Date(-306460800000)". misc.h does have a "TODO: make signed". I'm using 2.2.0.
I had tried to solve this before posting here using tm and mktime and never had any luck. Replicating from the Stackoverflow link:
This didn't compile -- I believe it should be mktime(&tm_date). mktimereturns seconds whereas I intend to generalize this further by allowing times including milliseconds. mktime returns "-1" with years less than 1970. I'm sure there is a way to finesse this to work properly, but I am not seeing why the first solution isn't somewhat more intuitive. But I lack experience in using "struct tm" and mktime, so I'm sure that is the source of the solution's apparent deficiencies.
> I'm confused why it works since Date_t is an unsigned long long.
Your solution works because Date_t's member "millis" is interpreted as a signed value when read, such as when MongoDB reads it as BSON off the wire (your first example, with .find()), and in bson-inl.h's BSONElement::toString (your second example, with cout).
> mktime returns "-1" with years less than 1970.
That's not strictly the case: mktime() attempts to convert its argument to a time_t (which on 32-bit platforms is generally limited to dates from ~1901 to ~2038), and returns (time_t)-1 if it can't be represented as such. You're correct in that you can't use this solution if you need sub-second precision.
Your pure-Boost solution is fine; it overcomes a number of POSIX's limitations that you saw in the other approaches.
On Friday, November 2, 2012 4:09:35 PM UTC-4, Therefore wrote:
> This is the generalization I came up with:
> // Create a mongo date (Date_t) from year, month, and day passed as > integers > // (year = with century, month = 1 - 12, day = 1-31) > mongo::Date_t MongoDate(const int &year, const int &month, const int > &day) > { > boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); > try > { > boost::posix_time::ptime > ptime_date(boost::gregorian::date(year,month,day)); > boost::posix_time::time_duration const diff = ptime_date - epoch; > long long ms = diff.total_milliseconds(); > return mongo::Date_t(ms); > } > catch (std::out_of_range& oor) > { > std::cerr << year << "-" << month << "-" << day << " is an > invalid date: " << oor.what() << endl; > return mongo::Date_t(0); > } > }
> (Note: Please ignore the absurdity of returning mongo::Date_t(0) -- I'm > either going to use Boost::Optional to return a NULL or stop using BSONand handling the addition of dates with a function using > BSONObjBuilder).
> This works for the full range of boost dates, 1400 - 10000. I'm confused > why it works since Date_t is an unsigned long long. However, after > executing "birthdate" << MongoDate(1960,4,16), the shell's db.personnel.find() > displays ISODate("1960-04-16T00:00:00Z") and "cout << doc.toString() << > endl" displays "new Date(-306460800000)". misc.h does have a "TODO: make > signed". I'm using 2.2.0.
> I had tried to solve this before posting here using tm and mktime and > never had any luck. Replicating from the Stackoverflow link:
> This didn't compile -- I believe it should be mktime(&tm_date). mktimereturns seconds whereas I intend to generalize this further by allowing > times including milliseconds. mktime returns "-1" with years less than > 1970. I'm sure there is a way to finesse this to work properly, but I am > not seeing why the first solution isn't somewhat more intuitive. But I lack > experience in using "struct tm" and mktime, so I'm sure that is the > source of the solution's apparent deficiencies.