wierzę, że są coraz mylić ze stref czasowych zwłaszcza przesunięcie części.
MongoDb zawsze zapisuje datę w czasie UTC.
Tak więc, gdy patrzysz na datę w MongoDB, zawsze musisz wziąć pod uwagę offset w swojej lokalnej strefie czasowej.
Zawsze będziesz wysyłać datę w lokalnej strefie czasowej. Sterownik Mongo C# zmienia czas z lokalnego na UTC przed kontynuowaniem.
Na przykład
Kiedy zapisać dokument z CreatedOn = 2017-04-05 15:21:23.234
(lokalnej strefy czasowej (Ameryka/Chicago)), ale jeśli spojrzeć na dokumentach w DB będzie można zobaczyć coś ISODate("2017-04-05T20:21:23.234Z")
czyli czas lokalny przesunięcie od UTC, który jest -5 godzin.
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
wskazuje kierowcy, aby zamienić czas na czas lokalny od czasu UTC, gdy ponownie wysyłasz BSON z powrotem do POCO.
Oto przypadek testowy wyjaśniający zachowanie.
Kod:
class Program
{
static void Main(string[] args)
{
var mongo = new MongoClient("mongodb://localhost:27017/test");
var db = mongo.GetDatabase("test");
db.DropCollection("students");
db.CreateCollection("students");
var collection = db.GetCollection<Student>("students");
var today = DateTime.Now; //2017-04-05 15:21:23.234
var yesterday = today.AddDays(-1);//2017-04-04 15:21:23.234
// Create 2 documents (yesterday & today)
collection.InsertMany(new[]
{
new Student{Description = "today", CreatedOn = today},
new Student{Description = "yesterday", CreatedOn = yesterday},
}
);
var filterBuilder1 = Builders<Student>.Filter;
var filter1 = filterBuilder1.Eq(x => x.CreatedOn, today);
List<Student> searchResult1 = collection.Find(filter1).ToList();
Console.Write(searchResult1.Count == 1);
var filterBuilder2 = Builders<Student>.Filter;
var filter2 = filterBuilder2.Eq(x => x.CreatedOn, yesterday);
List<Student> searchResult2 = collection.Find(filter2).ToList();
Console.Write(searchResult2.Count == 1);
}
}
public class Student
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
public DateTime CreatedOn { get; set; }
public string Description { get; set; }
}
Kolekcja: (patrząc przez Mongo shell)
{
"_id" : ObjectId("58e559c76d3a9d2cb0449d84"),
"CreatedOn" : ISODate("2017-04-04T20:21:23.234Z"),
"Description" : "yesterday"
}
{
"_id" : ObjectId("58e559c76d3a9d2cb0449d85"),
"CreatedOn" : ISODate("2017-04-05T20:21:23.234Z"),
"Description" : "today"
}
Aktualizacja:
"CreatedOn": ISODate("2017-03-31T20:27:12.914+05:00")
Powód twoje porównanie nie działa to
var start = new DateTime(2017, 03, 31);
var end = new DateTime(2017, 03, 31);
To dostaje wysłać do serwera tak jak $gte
niż ISODate("2017-03-31T00:00:00.000+05:00")
i $lte
niż ISODate("2017-03-31T00:00:00.000+05:00")
i robi znaleźć powyższego wpisu.
Właściwy sposób do kwerendy dla today
bieżąco będzie
var start = new DateTime(2017, 03, 31);
var end = new DateTime(2017, 04, 01);
i zaktualizować filtr
var filter = filterBuilder.Gte(x => x.CreatedOn, start) &
filterBuilder.Lt(x => x.CreatedOn, end);
więc teraz zapytanie zakres jest wysyłanie do serwera jako $gte
niż ISODate("2017-03-31T00:00:00.000+05:00")
i $lt
niż ISODate("2017-04-01T00:00:00.000+05:00")
i powinieneś być w stanie znaleźć wszystkie mecze na dziś.
Aktualizacja 2
zmienić bazę danych do przechowywania czasu daty z częścią zestawu czasu do 00:00:00. Spowoduje to również usunięcie części czasu z równania z db, a twoje stare zapytania o pasmo będą działać dobrze dla wszystkich przypadków.
Zmień swoją zapisać metoda,
var today = DateTime.Today; //2017-03-31 00:00:00.000
Można wrócić do starej definicji filtra.
Coś
var start = new DateTime(2017, 03, 31);
var end = new DateTime(2017, 03, 31);
i zaktualizować filtr do
var filter = filterBuilder.Gte(x => x.CreatedOn, start) &
filterBuilder.Lte(x => x.CreatedOn, end);
Więc teraz zapytanie zakres jest wysyłanie do serwera jako $gte
niż ISODate("2017-03-31T00:00:00.000+05:00")
i $lte
niż ISODate("2017-03-31T00:00:00.000+05:00")
i powinieneś być w stanie znaleźć wszystko mecze na dziś.
Aktualizacja 3 - Porównanie tylko z datą przy użyciu BsonDocument
.
Chodzi o to, aby dodać strefy czasowej, która jest +5:00
aktualne UTC serwera i przekształcić na format datetime obliczoną ciąg yyyy-MM-dd
wykorzystaniem $dateToSting
operatora następuje przez porównanie z datą ciąg wejściowy w tym samym formacie.
To zadziała w Twojej strefie czasowej, ale nie będzie działać w DST przestrzegając stref czasowych.
Mongo Wersja 3,4
Można użyć $addFields
etap, który dodaje nowe pole CreatedOnDate
zachowując wszystkie istniejące właściwości i ostatni $project
upuścić CreatedOnDate
od ostatecznej odpowiedzi po stosunku.
Shell Zapytanie:
{
"$addFields": {
"CreatedOnDate": {
"$dateToString": {
"format": "%Y-%m-%d",
"date": {
"$add": ["$CreatedOn", 18000000]
}
}
}
}
}, {
"$match": {
"CreatedOnDate": {
"$gte": "2017-03-31",
"$lte": "2017-03-31"
}
}
}, {
"$project": {
"CreatedOnDate": 0
}
}
C# Kod:
var start = new DateTime(2017, 03, 31);
var end = new DateTime(2017, 03, 31);
var addFields = BsonDocument.Parse("{$addFields: { CreatedOnDate: { $dateToString: { format: '%Y-%m-%d', date: {$add: ['$CreatedOn', 18000000] }} }} }");
var match = new BsonDocument("CreatedOnDate", new BsonDocument("$gte", start.ToString("yyyy-MM-dd")).Add("$lte", end.ToString("yyyy-MM-dd")));
var project = new BsonDocument
{
{ "CreatedOnDate", 0 }
};
var pipeline = collection.Aggregate().AppendStage<BsonDocument>(addFields)
.Match(match)
.Project(project);
var list = pipeline.ToList();
List<Student> searchResult = list.Select(doc => BsonSerializer.Deserialize<Student>(doc)).ToList();
Mongo Version = 3,2
samo jak powyżej, ale ten rurociąg wykorzystuje $project
więc musisz dodać wszystkie pola, które chcesz zachować w ostatecznej odpowiedzi.
Shell Zapytanie:
{
"$project": {
"CreatedOn": 1,
"Description": 1,
"CreatedOnDate": {
"$dateToString": {
"format": "%Y-%m-%d",
"date": {
"$add": ["$CreatedOn", 18000000]
}
}
}
}
}, {
"$match": {
"CreatedOnDate": {
"$gte": "2017-03-31",
"$lte": "2017-03-31"
}
}
}, {
"$project": {
"CreatedOn": 1,
"Description": 1
}
}
C# Kod:
var start = new DateTime(2017, 03, 31);
var end = new DateTime(2017, 03, 31);
var project1 = new BsonDocument
{
{ "CreatedOn", 1 },
{ "Description", 1 },
{ "CreatedOnDate", new BsonDocument("$dateToString", new BsonDocument("format", "%Y-%m-%d")
.Add("date", new BsonDocument("$add", new BsonArray(new object[] { "$CreatedOn", 5 * 60 * 60 * 1000 }))))
}
};
var match = new BsonDocument("CreatedOnDate", new BsonDocument("$gte", start.ToString("yyyy-MM-dd")).Add("$lte", end.ToString("yyyy-MM-dd")));
var project2 = new BsonDocument
{
{ "CreatedOn", 1 },
{ "Description", 1 }
};
var pipeline = collection.Aggregate()
.Project(project1)
.Match(match)
.Project(project2);
var list = pipeline.ToList();
List<Student> searchResult = list.Select(doc => BsonSerializer.Deserialize<Student>(doc)).ToList();
Update 4 - tylko Data porównanie, który współpracuje z oszczędności światła dziennego.
Mongo Version = 3,6
Wszystko pozostaje takie same oczekiwać $dateToString
odbędzie strefę czasową zamiast stałe przesunięcie, które powinny dbać o dziennych zmian oszczędzania światła pod uwagę.
Shell Aktualizacja:
{
"$addFields": {
"CreatedOnDate": {
"$dateToString": {
"format": "%Y-%m-%d",
"date": "$CreatedOn",
"timezone": "America/New_York"
}
}
}
}
C# Update:
var addFields = BsonDocument.Parse("{$addFields: { CreatedOnDate: { $dateToString: { format: '%Y-%m-%d', date: "$CreatedOn", "timezone": "America/New_York"} }} }");
można dodać przykładowy dokument ze swojej kolekcji, które oczekują zapytanie dla bieżącego dnia do powrotu? – Veeram
Zapisuję DateTime.Now w bazie danych zobacz moje edytowane pytanie –
Thanls @Veeram dla dzisiejszych przykładów Mogę używać metod AddDays, ale co z innymi, mam aktualizacje filtra dla dat, które mam. Potrzebujesz jakiegoś ogólnego rozwiązania. –