2013-04-17 2 views
8

У меня есть запрос о том, как datetimes сравниваются/сохраняются на C#. Рассмотрим следующий код:Сравнение равных дат, не сравниваемых

var createdDate = DateTime.Now; 
using (cr = new LanguageDictionaryRepository(ds)) { 
    cr.Add(new Sybrin10.Data.DTO.LanguageDictionary() { 
     Active = true, 
     CreatedDate = createdDate, 
     CultureCode = cultureCode, 
     Data = new System.Text.UTF8Encoding().GetBytes("Test") 
    }); 
    cr.Save(); 

    var y = cr.FindBy(x => x.CultureCode == cultureCode && x.CreatedDate == createdDate).FirstOrDefault(); 
    Assert.IsNotNull(y); 

Assert.IsNotNull не удается из-за проверки даты и времени. Я ожидал бы, что, поскольку экземпляр LanguageDictionary создается с величиной переменной, они будут равны. Это использует Telerik.OpenAccess и MSSQL как уровень БД, поэтому я предполагаю, что проблема возникает. Может ли кто-нибудь сказать мне, есть ли что-то, что мне не хватает, и как правильно сравнивать эти значения.

EDIT: значения тика различны, но я не знаю, почему, поскольку оба они происходят из той же переменной, которую я назначаю только один раз.

+1

Вы уверены, что даты идентичны? При сравнении будет учитываться количество часов/минут/секунд/миллисекунд. – Oded

+0

Это то, что значения тика различны, но я не уверен, почему, поскольку они оба происходят из той же переменной createdDate. – Ash

+0

System.DateTime – Ash

ответ

15

Попробуйте использовать DateTime.Equals(x.CreatedDate, createdDate), это может вам помочь.

Кроме этого, надлежащее DateTime сравнение - это очень сложный объект с часовыми поясами, смещениями, utc, местным временем и еще много чего. Я бы совсем не удивился при простом сравнении между двумя кажущимися идентичными датами, чтобы вернуть false.

Если значение Ticks отличается от чтения и записи, вы можете столкнуться с проблемой DateTimeKind, где вы пишете DateTimeKind.Local в базу данных, но получить обратно в DateTimeKind.Unspecified.

Другой вариант может быть (если разница достаточно мала), что DateTime поле в базе данных не достаточно, чтобы сохранить такое же количество миллисекунд, как .net DateTime:

Один тик составляет сто наносекунд или одну десятую миллионную долю секунды. В миллисекундах насчитывается 10 000 тиков.

В зависимости от вашего хранилища данных он может быть не таким подробным, как этот. Значения DateTime не исходят из одного источника, один считывается из памяти, другой считывается из базы данных.

+0

Спасибо за идею, но это тоже не сработало. – Ash

+0

В этом случае сравнивается строковое представление дат действительной? – Ash

+0

Если вы просто хотите вернуть созданную запись, см. Teleriks [How to: Insert Objects] (http://www.telerik.com/help/openaccess-orm/developer-guide-crud-add.html). После сохранения будет восстановлен созданный первичный ключ. –

0

Я думаю, вам будет лучше использовать DateTime.UtcNow при хранении данных, а затем вам не придется беспокоиться о проблемах с летним временем и т. Д. Затем вы можете отобразить его, как вы хотите позже, используя культуру Вы выбираете.

+0

Это не сработало. – Ash

2

SqlServer хранит datetime в (около) шагом в 3 миллисекунды.

значений даты и времени округлены до шагом .000, .003 или .007 секунд

билета туда и обратно из DateTime через базу данных, таким образом, может быть смещена на несколько мс.

Таким образом, вы не должны проверить «точно равно», но «достаточно близко»

var y = cr.FindBy(x => x.CultureCode == cultureCode && 
        x.CreatedDate >= createdDate.AddMilliseconds(-5) && 
        x.CreatedDate <= createdDate.AddMilliseconds(5)) 
    .FirstOrDefault(); 
+0

Я не знал этого, спасибо, что указал на это, я бы поднял, но ваш образец кода не очень практичен в реальности. теперь, если вы сделаете это расширение, теперь мы говорим –

+0

Вы можете использовать '(x.CreatedDate - createdDate) .Milliseconds <4', если вы ищете более короткую нотацию. – DdW

+2

@DdW - вам нужно добавить «Math.Abs» вокруг него, потому что вы можете получить отрицательные значения из этого сравнения (которые, конечно же, всегда <4) –