8

Using NUnit 2.2 on .NET 3.5, the following test fails when using DateTime.Equals. Why?

[TestFixture]
public class AttributeValueModelTest
{
    public class HasDate
    {
        public DateTime? DateValue
        {
            get
            {
                DateTime value;
                return DateTime.TryParse(ObjectValue.ToString(), out value) ? value : new DateTime?();
            }
        }

        public object ObjectValue { get; set; }
    }

    [Test]
    public void TwoDates()
    {
        DateTime actual = DateTime.Now;
        var date = new HasDate {ObjectValue = actual};
        Assert.IsTrue(date.DateValue.Value.Equals(actual));
    }
}
flipdoubt
  • 13,897
  • 15
  • 64
  • 96

5 Answers5

16

The dates aren't equal. TryParse drops some ticks. Compare the Tick values.

For one test run:

Console.WriteLine(date.DateValue.Value.Ticks);
Console.WriteLine(actual.Ticks);

Yields:

633646934930000000
633646934936763185
Amy B
  • 108,202
  • 21
  • 135
  • 185
3

The problem isn't really TryParse, but actually ToString().

A DateTime object starts with precision (if not accuracy) down to millionth of seconds. ToString() convertsit into a string, with precision only to a second.

TryParse is doing the best it can with what it is given.

If you add a format specifier (along the lines of "yyyy-MM-dd HH:mm:ss.ffffff"), it should work.

James Curran
  • 101,701
  • 37
  • 181
  • 258
1

To specify a format that includes all the precision, you can use the String.Format() method. The example that James gives would look like this:

String.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", ObjectValue);

I don't know what that will do when you pass it something that's not a date.

Perhaps a simpler approach is to add a special case when you've already got a date object:

    public DateTime? DateValue
    {
        get
        {
            DateTime value = ObjectValue as DateTime;
            if (value != null) return value;
            return DateTime.TryParse(ObjectValue.ToString(), out value) ? value : new DateTime?();
        }
    }
Don Kirkby
  • 53,582
  • 27
  • 205
  • 286
0

I don't know if this is the same in .NET, but in Java the equals often will only compare if the instances are the same, not if the values are the same. You'd instead want to use compareTo.

Stephane Grenier
  • 15,527
  • 38
  • 117
  • 192
  • No, in Java, the == operator is used for reference equality and the equals() method is used for value equality. – Adam Rosenfield Dec 12 '08 at 20:35
  • @Adam: Not by default. You have to override Object's equals method to get the behavior you're describing. – Bill the Lizard Dec 12 '08 at 20:38
  • In Soviet Russia, == equals Object.Equals – Amy B Dec 12 '08 at 20:51
  • @Adam. Coding conservatively you always assuming it compares the instances because that's the most common case. Going the other way will sometimes get you into trouble and take a while to debug. Only when you absolutely know should you use equals(). – Stephane Grenier Dec 12 '08 at 22:02
0

public DateTime? DateValue
        {
            get
            {
                DateTime value;
                bool isDate = DateTime.TryParse(ObjectValue.ToString(), out value); 
                return isDate ? new DateTime?(value) : new DateTime?();
            }
        }

shahkalpesh
  • 33,172
  • 3
  • 63
  • 88
  • I haven't run the code. this is purely based on the glance. I am sorry,if I am not of any help. – shahkalpesh Dec 12 '08 at 20:46
  • Sorry, but it is TryParse that is the problem. – flipdoubt Dec 12 '08 at 20:49
  • Thanks. When I looked at the code, it looks like it is returning DateTime (when TryParse is successful) instead of DateTime?. One thing I learn here is that you can assign an instance of DateTime to DateTime? :) – shahkalpesh Dec 12 '08 at 20:52