Is it possible to compare two dates if they are formatted in different ways? One date is coming from a ColdFusion UI input which is in the following format:
mm/dd/yyyy
My timestamp in my MSSQL database is in the following format:
yyyy/mm/dd
Background: I need to write a query that compares the dates and returns rows with a timestamp after the user selected date. Would I need to reformat either date?
Example:
<cfset start_date = 'form.sDate'>
<cfquery name="sortDate" datasource="RC">
SELECT *
FROM my_db_table
WHERE Submission_Date > #start_date#
</cfquery>
First off, always use cfqueryparam in your queries when dynamically including content. Second, you should be able to use start_date "as is" to compare the date to the date in the database
So, something like:
<cfquery name="sortDate" datasource="RC">
SELECT *
FROM my_db_table
WHERE Submission_Date > <cfqueryparam value="#start_date#" cfsqltype="cf_sql_date">
</cfquery>
Last, you can always test the raw sql in MSSQL Management Studio to test the date comparison.
(Too long for comments...)
There are a few subtle distinctions here it is important to understand.
You are working with a string and a date object, not two dates. Also, SQL Server does not actually store dates in yyyy/mm/dd format. Dates are stored as big numbers internally. Since those are difficult for humans to process, whatever IDE you are using displays them in a more human friendly way, such as yyyy/mm/dd format. But again, that does not mean the database actually stores them as strings.
Since the datepicker value is a string, you should validate it first, then convert the string into a date object. Comparing apples and oranges (ie dates and strings) is common gotcha. That is almost always where date queries go awry. That is why converting the string into a date object is important. It ensures the database compares the same things ie two dates and that the results will always be what you expect.
Finally, use cfqueryparam to pass the value to your database correctly. Be sure to use the cfsqltype which corresponds to the db column: cf_sql_date (date only) or cf_sql_timestamp (date and time).
Technically, if the strings are always in mm/dd/yyyy format you can pass in the string "as is" and CF will automatically convert it for you. However, trusting the input will always be in the right format is not a great idea. Validating input and using cfqueryparam will ensure the most consistent results.
Related
I've had a similar problem with dates before.
I'm querying a proprietary CMS database that stores dates as a string 'YYYYMMDD'.
I'm using...
convert(varchar(10),right(VarCompletionDate,2)+'/'+substring(VarCompletionDate,5,2)+'/'+left(varCompletionDate,4), 103)
to convert to 'DD/MM/YYYY' format. On the SQL side this appears to work but in Excel, the date is treated like a string rather than a date and I'm not getting the date filters that you would get with a proper date field...
what am I doing wrong here? is the convertconverting to a varchar rather than a date? ...if I do Convert(date,... I get conversion errors.
In excel, you can select a data cell and confirm that the data does not have an apostrophe sign as suffix.
This forces excel to treat the data as text. If you do find it, please do a find and replace all in your selected data range.
If there is no apostrophe, select your data and go to Home>Number>format dropdown and then select long date or short date as the format type.
This will then bring up the date filters.
Managed to find the answer!
Convert(date,....)
Was the correct treatment to output a date format from SQL.
The Pivot table wouldn't recognise the field as a date after a refresh unless I recreated the pivot table - there must be some kind of data type persistence going on in Excel.
I have a VB6 application where I insert a set of dates into a SQL-SERVER. Each time I insert a value, it gets inserted as 1978-12-12 00:00:00.000. Is it possible to specify in the INSERT statement, how you want the date to be formatted? VB6 does not seem to recognize CONVERT. I did previously CONVERT date when I loaded it into a MSHFlexGrid like this:
Convert(varchar,tblClient.DOB, 101)
But I did this in a select statement. Will SQL let me insert a value in a format MM/DD/YYYY as I need it later in that format.
The reason why I need the formatting is because I connected all my tables in SQL-SERVER2008 to Access for report generating purposes. So I need it formatted correctly in SQL-SERVER2008 as it dynamically connects to Access.
Ideally, the data type of the column in the database is set to Date or DateTime. Basically, if you want to store a date, then use a date date type.
That being said, in VB6 you usually have to (at least temporarily) store the date as a string so there is almost always a string to date conversion that happens somewhere.
Will SQL let me insert a value in a format MM/DD/YYYY
Yes. But you should not do this. Instead, you should insert the date with the format "YYYYMMDD". Notice that there are no delimiters. The problem with mm/dd/yyyy is that it could accidentally be interpreted as the wrong date. For example, 1/2/2015 would be interpreted as Feb 1, 2015 if you lived in England, or Jan 2, 2015 if you live in the US. However, SQL Server will always interpret 20150102 and Jan 2, 2015.
Once you have the data stored the way you want in the database (as an actual date data type), you should actually return it as a date to your front end (either Access or VB6). In the front end, you should use the format command to display the date. The format command will use the regional settings of the computer to display dates the way the user wants to see it.
Ex:
txtDateOfBirth.Text = Format(rs.Fields.Item("DOB").value, "Short Date")
Doing things this way... you should never have problems with dates.
The best way is not to store formatted dates in your database server.
One way you can get what you want is by using a view where you format your data and use that as input for your report:
CREATE VIEW myreport
SELECT replace(convert(NVARCHAR, mydate, 106), ' ', '/') from mytable
But I would recommend formatting dates on the application level.
You can use VB6s format function prep the date before inserting it into SQL. Here's an example (tested in VBA).
Format(Now(), "YYYY-MM-DD")
The date stored in my database is 01-01-1900 for field emp_doj(Data Type DATE).
But while retrieving the data, the value is 01-jan-00, even though formatted with dd-mm-yyyy.
I am comparing retrieved date field with some other date in SQL query.
select *
form persons
where per_join = to_date(to_char(i.emp_doj,'DD-MM-YYYY'),'DD-MM-YYYY')
Here the value of to_date(to_char(i.emp_doj,'DD-MM-YYYY'),'DD-MM-YYYY') results in 01-01-00, instead of 01-01-1900
I suspect it's your default NLS settings for the IDE you are using that is merely displaying the dates with a two digit year. Oracle does not store dates in any specific format. It stores them in a binary format internally.
Therefore I suggest you check the settings for your IDE and/or database and you will see the NLS date format set to DD-MM-YY, alter this and set it to DD-MM-YYYY and you will see the dates as you wish to see them.
As for your query, why use TO_CHAR and then TO_DATE? If emp_doj is a date field and per_join is also a date then just compare them directly for equality. If you are trying to cut the time portion off your emp_doj values then just use TRUNC().
For examples and reference on NLS: http://www.orafaq.com/wiki/NLS
More here: http://www.oracle.com/technetwork/database/globalization/nls-lang-099431.html
select to_char(emp_doj,'dd-mm-yyyy') from yourtable
I have got some temporary solutions it currently works for me, I simply changed my select query to
select *
form persons
where to_date(per_join,'DD-MM-YYYY')= to_date(i.emp_doj,'DD-MM-YYYY')
I need to take data between certain dates. But I get the following error.
AdsDateStarted : 03/18/2010 01:51:38.000 AM
AdsDateENded : 09/13/2010 05:00:00.000 PM
formatdate function converts today's date to 3/22/2010 format.
SQL = "SELECT * FROM Ads"
SQL = SQL & " WHERE AdsActive = 1 AND AdsAreasID = "& rtt &" AND CONVERT(VARCHAR(10), AdsDateStarted, 101) <= "& formatdate(Date()) &" AND CONVERT(VARCHAR(10), AdsDateEnded, 101) >= "& formatdate(Date()) &""
Set kdFonksiyon = objConn.Execute(SQL)
THe reason is that you have forgotten the apostrophes around the dates, so you get an expression like 3/22/2010 instead of a date literal like '3/22/2010'. The expression evaluates to an int value, so the database tries to convert the varchar values to int values also in order to compare them.
Instead of inserting the date in the query as a string, you should use parameters. Then you don't have to bother with apostrophes, but more importantly you don't have to guess what date format the database might accept.
As you use the dates as strings, there is no problem with parsing the strings to dates as the code is written now, but as you have chosen a date format that is not comparable as strings, your comparison will not work properly. If you want to compare dates as strings, you have to use an ISO 8601 format like 2010-03-22 that is comparable as strings, or preferrably compare the dates as proper dates, which is faster. (Even a lot faster if an index can be used.)
One of the immediate problems is that you need to put single quotes around the date values you are concatenating into the SQL string. Also, try to avoid any datetime conversion issues by using a standard ISO format like: yyyy-mm-dd
I would however strongly recommend you parameterise the query instead of building it up dynamically like this. So for example...
SQL = "SELECT * FROM Ads WHERE AdsActive=1 AND AdsAreasID = #rtt AND....."
And then pass in the values as parameters to the query. This will help with performance (execution plan reuse) and security (helps guard against SQL injection).
Use DateTime type parameters, please, and do not put together the date and time as a string.
If you HAVE to do that, use the international form that is accepted everywhree: 2010-03-22
Your problem is most likely different locales between client and server. You format as 3/22 and the server understands "day 3 of the 22nd month".
This is bypassed by using parameters of the language neutral iso form, as indicated above.
SQL Server recognizes 'yyyyMMdd hh:mm:ss' as a valid date time and lets you compare in this format. So if your formatDateTime function returns date in yyyyMMdd format that would do. You do not require to do a CONVERT on AdsDateStarted & AdsDateEnded.
Example:
SELECT * FROM Ads WHERE AdsDateStarted > '20100101' AND AdsDateEnded <= '20100321 11:59:59'
This query would retrieve all the records matching the date condition.
I have a legacy application where the input is a date string, i.e.:
06/12/2009
The format of the input is always a string, and is consistent, it's always dd/mm/yyyy
At the moment the legacy app just INSERTS this in a DateTime fields. Obviously if the Localization Culture settings of the Server change, we have a bug.
Two questions:
One:
Whats the safest way to store Dates in SQLServer in this situation?
Is there a format that will always be correctly interpreted regardless of the order of day and month?
Two:
What settings exactly determines the culture of a SQLServer DB, is it an OS setting, or a setting of that DB, or what?
cheers
Format YYYY-MM-DD is unambiguous, meaning that SQL Server won't confuse the month
and day when converting a string value to DATETIME. (I've never experienced a problem with an implicit conversion using that format using the four digit year.)
The "safest" (and most convenient) way to store date values in SQL Server is to use DATETIME datatype.
Use the CONVERT function to explicitly specify the input and output formats when converting between DATETIME and strings.
SQL Server 2005 Documentation on CONVERT style argument values:
http://msdn.microsoft.com/en-us/library/ms187928(SQL.90).aspx
To convert a string representation to DATETIME datatype:
select CONVERT(datetime, '2009-06-03', 20)
The first argument is datatype to convert to, the second argument is the expression to be converted, the third argument is the style.
(style 20 is ODBC Canonical format = 'YYYY-MM-DD HH:MI:SS' (24 hour clock)
[FOLLOWUP]
To convert a DATETIME expression (e.g. getdate() to VARCHAR in 'YYYY-MM-DD' format:
select CONVERT(varchar(10), getdate(), 20)
Note that specifying varchar(10) gets you just the first 10 characters of the etnire 'YYYY-MM-DD HH:MM:SS' format.
[/FOLLOWUP]
As to what determines the default formats, that's going to be research. We avoid the issues caused by default formats by specifying the formats.
I would recommend storing all dates in UTC time when they are placed into the database. It will be consistent that way.
Storing dates like this seems to work well...
YYYY-MM-DD
See SET DATEFORMAT. The SQL 'culture' is set by SET LANGUAGE at a session level. SQL Server has its own date format settings, independent of the hosting OS. This is for several reasons: ANSI compliance, to prevent OS changes from affecting applications using the database hosted on that host and not least is compatibility, the SQL long predates the OS is currently running on.
Keep in mind that DATA is not its PRESENTATION. In this case that DATA is a DATE or DATETIME, regardless of how you show them.
As for inserting/updating/comparing datetime values, I quote the BOL:
When specifying dates in comparisons
or for input to INSERT or UPDATE
statements, use constants that are
interpreted the same for all language
settings: ADO, OLE DB, and ODBC
applications should use the ODBC
timestamp, date, and time escape
clauses of:
{ ts 'yyyy-mm-dd
hh:mm:ss[.fff] '} such as: { ts
'1998-09-24 10:02:20' }
{ d 'yyyy-mm-dd'} such as: { d '1998-09-24' }
{ t 'hh:mm:ss'} such as: { t '10:02:20'}
I can assure you that, if you use this formats they will always work, regardless of the locale of you server
I'm a bit conservative in these matters, but I prefer to use separate Year / Month / Day fields in the table, rather than a Date field that uses a DBMS-specific data type. It certainly takes more space, but the lack of ambiguity and increased portability is worth it to me.
The price you pay is that you don't get free date/time arithmetic and sorting, but it's easy enough to do yourself or by a slightly more complex "ORDER BY" clause.
I agree with the advice from spencer7593, but please be aware that using cast or convert without a format can give unexpected results. This T-SQL query returns 12, not 1.
set language British
select month(CAST('2016-01-12' AS datetime))
Normally I prefer to insert as
insert into tbl values('yyyyMMdd')
Then, itll be inserted in proper format based on db.