简体   繁体   中英

I have a condition comparing DateTime in C# using the < operator and it return's false even if it should not. Why?

I have this code below and the "if ((DateTime)DataReader[0] > DateTime.Now)" condition returns false even if the datetime in the database is greater than the datetimenow.

I used this code before and it use to work I never changed any thing.

So the question is why does the condition return false?

Thanks,

Simon

Boolean active = false;
SqlConnectionUniqueInstance.Instance.Open();
SqlCommand Command = SqlConnectionUniqueInstance.Instance.Connection.CreateCommand();
Command.CommandText = String.Format(@"SELECT [LogoutDateTime] FROM [dbo].[sessions] WHERE [sessionID] = {0}", sessionId.ToString());
SqlDataReader DataReader = Command.ExecuteReader();
while (DataReader.Read())
{

    if ((DateTime)DataReader[0] > DateTime.Now)
        active = true;
}
DataReader.Close();
if (active)
    UpdateTime(sessionId);
Command.Dispose();
return active;

This is the actual answer:

You do not need/have/should to compare DateTime with >, <, == or != operators. Instead you can use the Compare and CompareTo methods of the DateTime class.

Compare : Compares two instances of DateTime and returns an integer that indicates whether the first instance is earlier than, the same as, or later than the second instance.

CompareTo : Overloaded. Compares the value of this instance to a specified DateTime value and indicates whether this instance is earlier than, the same as, or later than the specified DateTime value.

http://msdn.microsoft.com/en-us/library/system.datetime_members.aspx

First of all it is a bad practice to work with DateTime that way. You should store value of DateTime.ToUniversalTime in the database and convert loaded DateTime to local time using DateTime.ToLocalTime method. Also it is not clear how much records will be returned from DB ie you can rewrite active several times. Just show us values of (DateTime)DataReader[0] and DateTime.Now (including DateTime.Kind property)

Also program logic looks obscure - why logout time is in future?

I would suggest having a variable & using that to compare it with DateTime.Now


while (DataReader.Read())
{
    // or use DateTime.Parse instead here
    DateTime dbDate = (DateTime)DataReader[0];
    if (dbDate > DateTime.Now)
        active = true;
}

This will help debugging easier & will help you read what is being returned by DataReader.
On a side note, I am guessing that the DB contains null value.

First thing I'd do is print the two time values so I could see exactly what is happening. As mentioned by aku in the comments, check for timezone differences.

EDIT : Does the logic make sense?

if ((DateTime)DataReader[0] > DateTime.Now)

The Date/Times are logout times right? So this is check is "if the logout time is in the future, then..." - or am I completely misreading this?

My guess,

This could be to do with that while loop, are you looking at ALL the records in the db where sessionID matches?

Why is sessionID not a primary key?

If it is, why the while loop?

Ummm....how are you getting a "LogoutDateTime" that is greater than now? Have you bent time so that you know when your users are going to log out?

If your database field has a default value in it (eg 1/1/1990) then this would explain your problem. Either that or this field should be null until they log out and you should test for null.

The LogoutDateTime is the expiry of the session. So what I check is if the session is expired.

The sessionID is the primary key, so the where clause can't return more than 1 result.

Why am I using a while? Because it's the way I know to use the SqlDataReader. Any better way? Please enlighten me.

Table Create script:

CREATE TABLE [dbo].[Sessions](
    [SessionID] [int] IDENTITY(1,1) NOT NULL,
    [UserId] [int] NOT NULL,
    [LoginDateTime] [datetime2](7) NOT NULL,
    [LogoutDateTime] [datetime2](7) NOT NULL,
    [Culture] [nvarchar](5) NOT NULL
) ON [PRIMARY]

Same method with log:

    public static Boolean GetActive(Int32 sessionId)
    {
        Boolean active = false;
        SqlConnectionUniqueInstance.Instance.Open();
        SqlCommand Command = SqlConnectionUniqueInstance.Instance.Connection.CreateCommand();
        Command.CommandText = String.Format(@"SELECT [LogoutDateTime] FROM [dbo].[sessions] WHERE [sessionID] = {0}", sessionId.ToString());
        SqlDataReader DataReader = Command.ExecuteReader();
        while (DataReader.Read())
        {
            System.IO.File.AppendAllText("C:\\Log.txt", "DataBase Time    :" + ((DateTime)DataReader[0]).ToString() + " Kind:" + ((DateTime)DataReader[0]).Kind.ToString() + "\r\n");
            System.IO.File.AppendAllText("C:\\Log.txt", "DateTime.Now Time:" + DateTime.Now.ToString() + " Kind:" + DateTime.Now.Kind.ToString() + "\r\n");

            if ((DateTime)DataReader[0] > DateTime.Now)
                active = true;
            System.IO.File.AppendAllText("C:\\Log.txt", "active:" + active.ToString() + "\r\n");
        }
        DataReader.Close();
        if (active)
            UpdateTime(sessionId);
        Command.Dispose();
        return active;
    }

Log:

DataBase Time :2009-01-13 01:32:28 Kind:Unspecified

DateTime.Now Time:2009-01-13 01:02:31 Kind:Local

active:False

Your example code is comparing DateTimes with different DateTimeKind. Try converting them to the same kind, such as UTC. This blog post explains the pitfalls of varying DateTimeKind in comparisons.

Thanks guys, I did set a variable to compare and nothing changed. i also ser to compare the Ticks and it did not work. When I subtracted the ticks it confirms to me that the date in the database was greater.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM