Strange issue with Date.Parse / ParseExact not altering date (ASP.Net) - asp.net

I have a bit of a head scratcher with the Date.Parse /ParseExact functionality in VB.
To surmise, I have an ASP.Net 4.0 app, on one of the pages there is a calendar control which the user chooses a date and time, these are fed into a string (strReqDeadline) which takes the following European / UK date time format: dd/MM/yyyy HH:mm:ss.fff
So for example the contents of strReqDeadline would be: 29/03/2013 16:30:00.000
I then need to insert this into a SQL datetime column, so obviously it needs converted from UK to the US/datetime format. I've been attempting to do this with Date.Parse and Date.ParseExact with no success. The following should work according to the research I've done:
strReqDeadline = "29/03/2013 16:30:00.000"
Dim usDate = As Date = Date.ParseExact(strReqDeadline, "dd/MM/yyyy HH:mm:ss.fff", System.Globalization.CultureInfo.InvariantCulture)
However, what actually happens at runtime is bizzare, the Date.ParseExact function trims off the fractal seconds from the time (as far as I can see it shouldn't be doing this because the filter specifies .fff), and otherwise leaves the entire string completely unchanged.
So, if the value of usDate is output, it appears as follows: 29/03/2013 16:30:00
What it should contain is datetime: 3/29/2013 4:30PM
The really strange thing is if I put a watch on usDate and start the app, in the development environment its value shows as #3/29/2013 4:30PM#, both in the watch list and when hovered over in the source window, but any form of output displays the original string, just minus the fractions of second, and doesn't convert to datetime.
From what I read the 'InvariantCulture' specification should negate any locale specific issues with output, but just in case this were the issue I also tried specifying an explicit local culture with System.Globalization.CultureInfo.CreateSpecificCulture("en-GB") (tried fr-FR too), but this makes no difference. The Windows regional settings on both the client and server are set to UK if this bears any relevance.
Maybe I'm missing something very obvious but I just can't see why I'm getting this output, Date.ParseExact doesn't throw any exceptions or complain about the string not being recognised, but I'm struggling to understand why it just removes the fraction seconds and does nothing else, especially since the input spring matches the specified mask exactly.
I'd be very interested to hear if anyone else has experienced an odd issue like this and what you did with it!
Thanks :)
EDIT: Full code with SQL section is as follows:
strReqDeadline = "29/03/2013 16:30:00.000"
Dim usDate As Date = Date.ParseExact(strReqDeadline, "dd/MM/yyyy HH:mm:ss.fff", System.Globalization.CultureInfo.InvariantCulture)
'SQL
Dim con As New Data.SqlClient.SqlConnection("data source=XXXXX;initial catalog=YYYYY;Integrated Security=True")
Dim cmd As New Data.SqlClient.SqlCommand()
cmd.Connection = con
cmd.CommandText = "INSERT INTO Requests (ReqOwnerID, ReqDeadline, ReqStatus)" _
& "VALUES ('" & UserID & "', '" & usDate & "', '1')"
con.Open()
Dim NewReqID = cmd.ExecuteScalar()
con.Close()
'

Why is it you thin it is not working? These are all the same underlying date/time:
29/03/2013 16:30:00.000
29/03/2013 16:30:00
3/29/2013 4:00PM
You cannot rely on what hovering over a non-string variable shows to determine its inner value. All you are seeing is the evaluation of ToString(). If you want a String to show the fractions seconds, then you need to call ToString() and specify the format "dd/MM/yyyy HH:mm:ss.fff". By default a DateTime type if not going to show your fractions seconds when you convert to a String.
If you are not using parameters (and you should be) then your final SQL statement after injecting the DateTime would be something like this:
INSERT INTO MyTableWithDate
(column1
,column2
,MyDateCol)
VALUES
('a'
,'b'
,'20130329 16:30:00.557')
As I mentioned before, a Date datatype is not String. It's an object (or a rather a DateTime structure, by I digress). You must call the correct ToString() meth0d.
Try using this withing your SQL string:
& "VALUES ('" & UserID & "', '" & usDate.ToString("yyyyMMdd HH:mm:ss.fff") & "', '1')"
Of course, there is little point converting a string to Date object to immediately convert it back to a string again, but this code should work.

usDate is an object of type DateTime, and it appears to be storing the correct value. When you are inspecting it, you are seeing a string representation of that datetime value. It doesn't contain either 29/03/2013 16:30:00 or 3/29/2013 4:30PM, those are just two valid representations of what it contains.
You say
any form of output displays the original string
This is not true. In fact you have control over how it is output when you call ToString(), where a format can be specified

What you are doing looks correct i.e. using Date.ParseExact to convert a date in UK format to a Date type. The issue you are having is that when it displays this as a string it is displaying it in your local culture (the debugger appears to always want to display in US format), but the Date you have set is correct.

Related

Convert date in textboxes to date in SQL Server

I am working in ASP.NET as front end and SQL Server 2012 as backend. In ASP.NET, the user enters a date in 3 textboxes in the format DD/MM/YYYY.
Now I have concatenated these textbox values into a string. In SQL Server, I want to save this date into column DOB with a data type of DATE.
Below is concatenated string in ASP.net
string strDOB = txtYY.Text + "/" + txtMM.Text + "/" + txtDD.Text;
How can I now save this strDOB in SQL Server?
Stop using strings. Besides the advice in the comments to use a dedicated picker control, the next best advice is to parse those strings into integers (briefly), then construct a DateTime object from that and then do not let it get converted back into a string. It's when people let extra string/date conversions happen that they introduce formatting problems. So get the value:
var year = Int32.Parse(txtYY.Text);
var month = Int32.Parse(txtMM.Text);
var day = Int32.Parse(txtDD.Text);
var dob = new DateTime(year,month,day);
And then pass it to SQL Server:
var cmd = new SqlCommand(...);
cmd.Parameters.Add("#DOB",SqlDbType.Date).Value = dob;
And make sure that your query uses the parameter #DOB wherever you want to use that value.
Try this:
UPDATE [Table] SET [Column] = '' + strDOB + ''
Be careful, though... this hasn't been sanitized to guard against SQL Injection. I've only demonstrated the direct answer to your question, nothing more.
As a best practice, you should never concatenate together unchecked user input and store the result in a column. Techniques for preventing this are outside the scope of this Q&A, but are easily discovered with a minimal amount of searching.
--EDIT--
I defer to Damien's answer on this one. I agree with his syntax suggestions.

SQLite REAL error

I am having some trouble with SQLite. I used to save "time" as an int, but i now want it as a double, which is causing some problems. I remake my database everytime i try a new fix, but it has no effect. Whenever i try to save, it get the error "4 values for 3 columns". when i change it all back to an int, it works fine again. Also, if i just remove "time all togeater from the saving process, i get the error "2 values for 3 columns". I have no clue what is going on. Does a real take up two values or whats the deal?
Creating the table:
sql = "CREATE TABLE Speed (id INTEGER PRIMARY KEY AUTOINCREMENT, LanguageType VARCHAR(20), cardsetNumber INT, time REAL)";
command = new SQLiteCommand(sql, dbConnection);
command.ExecuteNonQuery();
Adding to the table:
public void SaveSpeed(int cardsetNumber, LanguageType lt, double time)
{
Open();
sql = "insert into Speed (cardsetNumber, LanguageType, time) values (" + cardsetNumber + ", '" + lt + "', " + time + ")";
command = new SQLiteCommand(sql, dbConnection);
command.ExecuteNonQuery();
Close();
}
According to Wikipedia, Denmark uses a comma as a decimal separator. Most probably, the default culture of your process is the Danish one that imposes exactly that decimal separator when converting decimal numbers to strings.
You are doing two things that you shouldn't be doing in your code, though in this case, changing one will fix the problem:
You convert a value to a string based on a culture that is not the invariant culture for any other purpose than displaying it to the user.
You are constructing an SQL query with custom values by concatenating the values unescaped into the query string.
The first means that code that does not expect to read locale-specific number formats will simply interpret your string differently than intended. In particular, that is true when reading the string on another machine (that has another default locale set), but in this case, it is simply because the SQL parser does never expect any locale-specific number formats (and, as the comma serves as the argument separator, the syntax would actually stop being well-defined unless the parser would add any further locale-specific amendments).
The second can cause really bad trouble, so you are best served by always avoiding it.
So, what is happening here? With that locale-specific conversion, the time number is converted to something like 1,2, which is interpreted by the SQL parser as two integer numbers (separated with a comma), not as one decimal number. Hence the error message about the argument count.
The first problem could be solved by explicitly specifying the invariant culture for string conversions when the result is targeted at programs rather than humans. Always do that when you, or someone else, intends to read the value back into a number type, for example, when storing it in a text-based format for computers such as CSV or XML.
As for the second issue, to insert any custom (literal) values into your SQL query, (especially, but not exclusively, those that are not hard-coded somewhere but received from user-input), parametrize your query string:
sql = "insert into Speed (cardsetNumber, LanguageType, time) values (#cardsetNumber, #lt, #time)";
command = new SQLiteCommand(sql, dbConnection);
command.Parameters.AddWithValue("#cardsetNumber", cardsetNumber);
command.Parameters.AddWithValue("#lt", lt);
command.Parameters.AddWithValue("#time", time);
This will automatically insert any quotation or escape marks to the literal values, and there is no risk of intentional or accidental SQL injection.

Converting Decimal In a Label to an Integer

Currently using VS2008, VB.NET, SQL.
I have a FormView from a Data Source that is getting some fields that are stored as Decimals in the SQL Database.
I am grabbing the field from the FormView as such:
Dim AvgTicketL As Label = CType(frmMerchantProfile.FindControl("F10Label"), Label)
I need to take this value, and convert it to an Integer, then send it along to an API. I have the API Calls done, tested and working, but I'm getting an error as when it is getting this value, the API is returning "Must be an Integer" error.
What I have tried so far:
Dim AvgTicketL As Label = CType(frmMerchantProfile.FindControl("F10Label"), Label)
Dim AvgTicket1 As Integer
AvgTicket1 = Double.Parse(AvgTicket.Text)
Do something with AvgTicket1
I have also attempted to Round the Value, then convert it and call it - no luck.
Checking the value of AvgTicket1 (Writing it out to a Label or Response.Write) shows "100", where the database value was 100.00. But the API is still getting 100.00, apparently. Any other conversion method that I've attempted states errors that the Label cannot be converted to Integer.
What are some methods I can successfully convert this value to an integer from a label?
The title of your question and the text of your question point to two different things.
Assuming you want to know how to safely convert the decimal value retrieved from the database, which is presumably the value of AvgTicketL, before calling your API you would do the following:
Create a variable of datatype Integer and use System.Int32.TryParse() to safely convert the decimal to an integer. Then pass that variable. (Code coming)
Dim testInt as Integer = -1
If System.Int32.TryParse(AvgTicketL.Text, testInt) Then
' Do something with testInt - call the API using the value
Else
' code to execute if the parse fails.
' This could be whatever you need the code to do if the value of AvgTicketL.Text can't be properly parsed into an Int value.
End If
After some fooling around this is what I was able to do to get this to work...
I took some of what David had said, and then just made a simple adjustment - I don't know why I hadn't thought of it earlier!
Dim AvgTicketL As Label = CType(frmMerchantProfile.FindControl("F10Label"), Label)
Dim AvgTicketI As Integer = "-1"
I dimmed a second variable as an int, then
AvgTicketI = CInt(AvgTicketL.Text)
From there, I just called AvgTicketI as the variable to pass to the API. Worked!
Thanks, David, for the guidance!

stop vb.net from turning 02/02/2011 to 2/2/2011

For some reason vb keeps changing my dates format and removes the 0s at first this wasnt a problem but it really messes up my sorting in my gridview.
Dim aftersubtraction As Date
aftersubtraction = departuredate.AddDays(-dates1.Text)
dates.Add(aftersubtraction.AddDays(-gracep.Text))
DateTime objects store their variables as integers. It will always engage in this behavior. To prevent it, you need to format the date as a string of your choosing before you send it where-ever you send it:
aftersubtraction.ToString("MM/dd/yyyy")
Don't confuse how a date is stored internally (doesn't really matter), to how you display it.
"Feb 2nd 2011" is the same date as "02/02/2011" or "2/2/11".
When you have a date variable and want to display it a certain way, you should use the correct format string - either a custom or a standard one.
In your case you seem to want this:
Dim outputDate as String = myDate.ToString("dd/MM/yyyy") ' European/UK style
Dim outputDate as String = myDate.ToString("MM/dd/yyyy") ' US style
Try this:
.ToString("MM/dd/yyyy")
In addition to what Joel said - you shouldn't be sorting on the string representation of a date object - you should be sorting on the date value itself, then it won't matter how it's sorted.
Change your Region and Language settings to your correct culture this will probably solve your issue, but if you have problems with sorting dates in a gridview you might be passing a datasource that stores the date as a string.

Date Time format problem in sql server

I have an application in asp.net which worked fine untill recently when i changed the datetime format in Regional and Language Settings in Control Panel.
The date time format was default when i installed XP. I chose Indian standard time while installing XP.
I changed the date time format to dd/MM/yyyy HH:mm:ss. And my application started to throw an exception whenever i tried to insert any datetime in to the table.
The exception i get is:
System.Data.SqlClient.SqlException: Error converting data type varchar to datetime.
Please help me on this
Hard to know exactly what's going on without seeing the code that's throwing. However, if you need to communicate dates to SQL Server, it is generally good practice to use the ISO 8601 standard for representation because it is unambiguous and locale-independent. The most important formats are:
yyyy-MM-dd for dates
hh:mm:ss for time
yyyy-MM-dd hh:mm:ss for date/time
My guess is that you have a query that's sending over dates in the current locale, and the locale on the server does not match.
Edit: And for the record, this doesn't preclude anything that Rob said in his answer, i.e. try to avoid passing hard-coded dates or hard-coded SQL at all. This only applies if you need to for some reason.
Edit 2: I've been informed that the yyyy-MM-dd format can still be wrong for some locales; so instead of this, if you need to pass in a literal date string, you should instead use yyyyMMdd.
As per my comment, you'll probably want to make sure you're using code that behaves in a similar way to the code below (i.e. using parameters rather than string concatenation)
var myConnectionString = "connection string goes here";
var myDateValue = DateTime.Now;
using (var connection = new SqlConnection(myConnectionString))
{
using (var command = new SqlCommand("SELECT COUNT(1) FROM dbo.table WHERE datecolumn = #datevalue", connection))
{
var dateValueParameter = new SqlParameter("#datevalue", myDateValue);
command.Parameters.Add(dateValueParameter);
var result = Convert.ToInt32(command.ExecuteScalar());
}
}
Try adding "Current Language=YourLanguage" to the SQL server connection string. Where YourLanguage is the language you want SQL to use when reading values such as the dates.
You can see a list of all languages supported by SQL by executing the following SQL command:
select * from master.dbo.syslanguages

Resources