Ya no necesitas investigar más en otras webs porque llegaste al espacio necesario, poseemos la solución que deseas y sin complicarte.
Solución:
Creo que se está confundiendo con las zonas horarias, especialmente con la parte de compensación.
MongoDb siempre guarda la fecha en hora UTC.
Entonces, cuando mira la fecha y hora en MongoDB, siempre debe tener en cuenta el desplazamiento de su zona horaria local.
Siempre enviará la fecha en la zona horaria local. El controlador Mongo C # cambia la hora de local a UTC antes de persistir.
Por ejemplo
Cuando guardo el documento con CreatedOn = 2017-04-05 15:21:23.234
(zona horaria local (América / Chicago)) pero cuando mire los documentos en la base de datos verá algo ISODate("2017-04-05T20:21:23.234Z")
es decir, la diferencia de hora local con respecto a UTC es de -5 horas.
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
indica al conductor que convierta la hora a la hora local de UTC cuando descarrile el BSON de nuevo a su POCO.
Aquí está el caso de prueba que explica el comportamiento.
Codigo:
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("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 StudentDescription = "today", CreatedOn = today,
new StudentDescription = "yesterday", CreatedOn = yesterday,
);
var filterBuilder1 = Builders.Filter;
var filter1 = filterBuilder1.Eq(x => x.CreatedOn, today);
List searchResult1 = collection.Find(filter1).ToList();
Console.Write(searchResult1.Count == 1);
var filterBuilder2 = Builders.Filter;
var filter2 = filterBuilder2.Eq(x => x.CreatedOn, yesterday);
List 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;
Colección: (cuando se ve a través de la cáscara de mongo)
"_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"
Actualizar :
"CreatedOn": ISODate("2017-03-31T20:27:12.914+05:00")
La razón por la que su comparación no funciona es
var start = new DateTime(2017, 03, 31);
var end = new DateTime(2017, 03, 31);
Esto se envía al servidor como $gte
que ISODate("2017-03-31T00:00:00.000+05:00")
y $lte
que ISODate("2017-03-31T00:00:00.000+05:00")
y no encuentra la entrada anterior.
La forma correcta de consultar today
la fecha será
var start = new DateTime(2017, 03, 31);
var end = new DateTime(2017, 04, 01);
y actualice su filtro para
var filter = filterBuilder.Gte(x => x.CreatedOn, start) &
filterBuilder.Lt(x => x.CreatedOn, end);
Así que ahora su consulta de rango se envía al servidor como $gte
que ISODate("2017-03-31T00:00:00.000+05:00")
y $lt
que ISODate("2017-04-01T00:00:00.000+05:00")
y debería poder encontrar todas las coincidencias para hoy.
Actualización 2
Cambie su base de datos para almacenar la fecha y la hora con la parte de la hora establecida en 00:00:00. Esto también eliminará la parte de tiempo de la ecuación de db y sus consultas de rango anteriores funcionarán bien en todos los casos.
Cambie su método de guardado para usar
var today = DateTime.Today; //2017-03-31 00:00:00.000
Puede volver a la definición de filtro anterior.
Algo como
var start = new DateTime(2017, 03, 31);
var end = new DateTime(2017, 03, 31);
y actualice su filtro para
var filter = filterBuilder.Gte(x => x.CreatedOn, start) &
filterBuilder.Lte(x => x.CreatedOn, end);
Entonces ahora su consulta de rango se envía al servidor como $gte
que ISODate("2017-03-31T00:00:00.000+05:00")
y $lte
que ISODate("2017-03-31T00:00:00.000+05:00")
y debería poder encontrar todas las coincidencias para hoy.
Actualización 3 – Comparación de solo fecha usando BsonDocument
.
La idea aquí es agregar un desplazamiento de zona horaria que es +5:00
a la fecha UTC del servidor y transforme la fecha y hora calculada en string yyyy-MM-dd
formato usando $dateToSting
operador seguido de comparación en la entrada string fecha en el mismo formato.
Esto funcionará en tu zona horaria, pero no funcionará en horario de verano observando las zonas horarias.
Mongo Versión 3.4
Puedes usar $addFields
etapa que agrega un nuevo campo CreatedOnDate
manteniendo todas las propiedades existentes y por último $project
dejar caer el CreatedOnDate
de la respuesta final después de la comparación.
Consulta de Shell:
"$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ódigo C #:
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(addFields)
.Match(match)
.Project(project);
var list = pipeline.ToList();
List searchResult = list.Select(doc => BsonSerializer.Deserialize(doc)).ToList();
Versión de Mongo = 3.2
Igual que el anterior, pero esta canalización utiliza $project
por lo que tendrá que agregar todos los campos que desea mantener en la respuesta final.
Consulta de Shell:
"$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ódigo C #:
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 searchResult = list.Select(doc => BsonSerializer.Deserialize(doc)).ToList();
Actualización 4 – Comparación de solo fecha que funciona con el horario de verano.
Versión de Mongo = 3.6
Todo permanece igual, espera $dateToString
tomará la zona horaria en lugar de la compensación fija que debería tener en cuenta los cambios de horario de verano.
Actualización de Shell:
"$addFields":
"CreatedOnDate":
"$dateToString":
"format": "%Y-%m-%d",
"date": "$CreatedOn",
"timezone": "America/New_York"
Actualización de C #:
var addFields = BsonDocument.Parse("$addFields: CreatedOnDate: $dateToString: format: '%Y-%m-%d', date: "$CreatedOn", "timezone": "America/New_York" ");
Si guardas alguna desconfianza y disposición de mejorar nuestro artículo te recomendamos dejar una interpretación y con mucho placer lo observaremos.