I'm inserting a document to MongoDB collection using C# driver, one of the fields types vs a DateTime when i debug the application i see the server time in the "FrameTimeStamp" fields i'm passing to Mongo, this is my code:
FrameDocument frameDoc = new FrameDocument();
frameDoc.Frame = imageBA;
frameDoc.EventCodeId = 1;
frameDoc.SesionId = 1;
frameDoc.FrameTimeStamp = DateTime.Now;
frameDoc.ServerUserId = (int)toMongoDt.Rows[0]["ServerUserId"];
frameDoc.TraderId = (int)toMongoDt.Rows[0]["TraderId"];
frameDoc.ActivePick = (int)toMongoDt.Rows[0]["ActivePick"];
frameDoc.TraderName = (string)toMongoDt.Rows[0]["TraderName"];
frameDoc.ServerUserName = (string)toMongoDt.Rows[0]["ServerUserName"];
var mongoCon = "mongodb://127.0.0.1";
MongoClient client = new MongoClient(mongoCon);
var db = client.GetDatabase("Video");
var frameCollection = db.GetCollection<FrameDocument>("Frame");
frameCollection.InsertOne(frameDoc);
in the shell when I'm reading the data i see it in the following format:
2016-08-14T06:10:33.295Z and the time is not the server time, its UTC, how can i force mongo to write the DateTime as i pass it,?
as per CSHARP-185
MongoDB stores all DateTimes in UTC. Any local times you supply are
converted to UTC when stored in the database. The recommended approach
is to always convert DateTime values to UTC yourself before storing
them in the database, that way you are in full control. You can also
tell the C# driver that you want to work in LocalTime, like this:
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
public DateTime Date
{ get; set; }
Related
I currently have a C# application that queries Cosmos DB. In the database everything is stored as strings. When I query the container for the document and pull out the information it looks like the deserialization process is treating it like a date and its applying the Date Time Offset. Strange part is this process of querying the DB never converts it to a date? I would like it to just pass through the app as its stored in Cosmos.
Here is the document shape in Cosmos:
{
"id": "uniqueId",
"MyDate" : "2021-07-24T23:59:00+0000"
}
Here is the code that connects to CosmosDB
using(var client = new CosmosClient("EndPoint","Key")
{
string sqlQueryText = "Select * From c Where .... ";
QueryDefinition querySQL = new QueryDefination(sqlQueryText);
var container = client.GetContainer("databaseId", "ContainerId");
var iii = container.GetItemQueryIterator<Document>(querySQL);
var myList = new List<Document>();
while(iii.HasMoreResults)
{
FeedResponse<Document> currentRS = iii.ReadNextAsync().Result;
foreach(Document doc in currentRS)
{
myList.Add(doc);
}
}
}
Here is the Output of the this process in C#, By output I mean if you look at the myList Object and inspect the Mydate Property you will see this string below.
"07/24/2021 19:59:00"
which is the date & time with the date time offset.
How do I prevent this?
This application should just pass the string straight through with no regard for "Real Type".
I would just like to get "2021-07-24T23:59:00+0000"
When inserting, the offset is OK, however when retrieving the document, it's resetting to +00:00
Property:
public DateTimeOffset CreatedOn { get; set; }
Insert:
user.CreatedOn = DateTimeOffset.Now; // 01/20/2021 6:05:21 PM +05:30
col.Insert(user);
col.EnsureIndex(x => x.Username);
Find:
using (var db = _liteDbConnection.Create() as LiteDatabase)
{
var col = db.GetCollection<AuthUser>(USERS_COLLECTION);
return col.FindOne(x => x.UserId == userId);
}
user.CreatedOn becomes
01/20/2021 6:05:21 PM +00:00
Am I doing something wrong?
From the documentation
Following the BSON specification, DateTime values are stored only up to the miliseconds. All DateTime values are converted to UTC on storage and converted back to local time on retrieval.
It doesn't look like there's actual DateTimeOffset support. (Personally I think it's a terrible idea to convert to local time on retrieval, but that's a slightly different matter.) Additionally, it looks like it's not really converting to local time properly, given the incorrect offset of 0.
I would suggest avoiding using DateTimeOffset with LiteDb until it's really supported (maintaining the offset).
This happens because LiteDB stores a DateTimeOffset using value.UtcDateTime. This is unfortunate, but it can't be changed due to compatibility. However, you can override this behavior by creating a custom serializer:
BsonMapper.Global.RegisterType<DateTimeOffset>
(
serialize: obj =>
{
var doc = new BsonDocument();
doc["DateTime"] = obj.DateTime.Ticks;
doc["Offset"] = obj.Offset.Ticks;
return doc;
},
deserialize: doc => new DateTimeOffset(doc["DateTime"].AsInt64, new TimeSpan(doc["Offset"].AsInt64))
);
I want to store a DateTime instance into MongoDB using C#. As mongodb uses ISO 8601 as format, the date which I am passing is getting stored with a timestamp which is making querying using that date field a nightmare. I tried DateTime.Now, DateTime.UtcNow, BsonDateTime object but all are saving with current timestamp only. Is there a way using which I can make my date field to store date and rest as Zeros,
Thanks
Piyush Kumar
You can set up a class map for your class to only store the date part of the datetime with the following code:
BsonClassMap.RegisterClassMap<Order>(map =>
{
map.MapProperty(x => x.Date)
.SetSerializer(DateTimeSerializer.DateOnlyInstance);
});
then when execute the following
var client = new MongoClient();
var database = client.GetDatabase("test");
var collection = database.GetCollection<Order>("orders");
await collection.InsertOneAsync(new Order
{
Name = "MyOrder", Date = DateTime.UtcNow.Date
});
we'll get the following in the database
> db.orders.find().pretty()
{
"_id" : ObjectId("5ed8fb7050eb018e5ee13e73"),
"Date" : ISODate("2020-06-04T00:00:00Z")
}
I need to query a MongoDB Collection where the date difference between two date fields, within each Document, is equal to 1 day.
I've tried using the MongoDB.Driver.Builders using the Where or Eq FilterDefinitions but cannot get it to work. Is there a way to do this? If so, is there a way to exclude the time portion so I'm just getting the difference between two dates?
Here is the code I have:
var client = new MongoClient("mongodb://localhost:27017");
var database = client.GetDatabase("local");
var collection = database.GetCollection<BsonDocument>("testCollection");
var builder = Builders<BsonDocument>.Filter;
var filter = builder.Exists("{$cond:[{$gte:[{$divide:[{$subtract:[DateField1,DateField2]},1000*60*60*24]},1]}]}");
var documents = collection.Find(filter).ToList();
In our ASP.NET MVC 5 application we have user profiles with a Timezone ID (IANA).
public class User
{
public int Id { get; set; }
public string TimeZoneId { get; set; }
}
The task is to send all users an email at 6 AM local time. Our plan is to send out emails every hour to all timezones where the local time is 6 AM at that point in time (calculated based on the UTC time of the server).
Since we only have the Timezone ID to go by, I was hoping to get the corresponding Timezone IDs for, let's say, offset -4:00:00 -- taking into account DST.
string[] timezoneIds;
I could then query my database like so:
db.Users.Where(x => timezoneIds.Contains(x.TimeZoneId));
My question is, obviously, is this a decent idea or are there best practices for this problem that I am not aware of?
Thanks.
Simpler code for the "building a dictionary" that Serge shows: use LINQ's lookup, DateTimeZone.GetUtcOffset, and Offset keys instead of TimeSpan values:
var now = SystemClock.Instance.GetCurrentInstant();
var provider = DateTimeZoneProviders.Tzdb;
var idsByCurrentOffset = provider.Ids.ToLookup(id => provider[id].GetUtcOffset(now));
Then you can use:
var offset = Offset.FromHours(5);
foreach (var id in idsByCurrentOffset[offset])
{
...
}
(You don't even need to check for existence first, as the lookup indexer returns an empty sequence when presented with a key that doesn't exist in the lookup.)
You could try the following:
First create a dictionary with all the offsets and the timezones belonging to that offset
Instant now = SystemClock.Instance.Now;
IDateTimeZoneProvider timeZoneProvider = DateTimeZoneProviders.Tzdb;
Dictionary<TimeSpan, List<string>> timezonesForOffset = new Dictionary<TimeSpan, List<string>>();
foreach(var id in timeZoneProvider.Ids){
ZonedDateTime zdt = now.InZone(timeZoneProvider[id]);
var timespan = zdt.Offset.ToTimeSpan();
if(timezonesForOffset.ContainsKey(timespan)){
timezonesForOffset[timespan].Add(id);
} else {
timezonesForOffset[timespan] = new List<string> {id, };
}
}
After you have done that you could use the following snippet to get all users within a certain timezone
var timespan2 = new TimeSpan(1,0,0);
var timezonesWithOffset = timezonesForOffset[timespan2];
var usersinTimezone = db.Users.Where(x=> timezonesWithOffset.Contains(x.TimezoneId)).ToList();
That would get all users in the timezone utc+1