I hired a freelancer a little while ago to parse a website which had a datetime field. I had to put the project on the back burner shortly after the freelancer completed and now that I'm getting back into it, I've noticed some issues when I go into the MySQL database.
Specifically, there are two different datetime formats and I can't figure out how to update them into a unified MySQL sortable datetime field
Apr 8 - 2:23 AM <- for current year updates
Tue, Dec 2, 2014 06:06:00 PM <- for all previous year updates
2014-12-02 06:06:00PM <- desired format
I have a unique id in the table so I can select and update the formats easily. All "Apr 8 - 2:23 AM" format is < '6340' for example. I also have created a "date_proper" column to update the current date column.
I just can't for the life of me figure out the correct code to update the different formats into the same unified format. Any help would be much appreciated.
You need to use str_to_date() for this. First, fix the date_proper column so it is a datetime. Formats should be handled on input and output. The proper storage for dates is using native formats:
alter table modify date_proper datetime;
Then you can update the values:
update t
date_proper = (case when format < '6340'
then str_to_date(concat(year(now), ' ', col), '%Y %b %d - %h:%i %p'
else str_to_date(substr(col, 5), '%b %d, %Y %h:%i:%s %p'
end);
Related
Good day,
I am trying to fetch range of data in my database but i cant get any result when i try to query like this.
SELECT * FROM `doc_history` WHERE date BETWEEN '07-13-2020 Mon 10:13:32 am' AND '07-20-2020 Mon 01:24:28 pm'
but if i try only to search specific date. it normally show the data. but when it comes to RANGE SEARCH, it show nothing.
I am trying to convert this date format to a simplified date format "07-20-2020 Mon 01:24:28 pm" to "07-20-2020".
I tried others formula but still no result.
You should valid MySQL timestamp/datetime literals:
SELECT *
FROM doc_history
WHERE STR_TO_DATE(date, '%m-%d-%Y %a %h:%i:%s %p')
BETWEEN '2020-07-20 13:24:28' AND '2020-07-20 13:24:28';
But note that you are currently not really searching for a range, but rather a point in time. So the above query I wrote is equivalent to:
SELECT *
FROM doc_history
WHERE STR_TO_DATE(date, '%m-%d-%Y %a %h:%i:%s %p') = '2020-07-20 13:24:28';
If you want a meaningful range, then the start and end values should be different points in time.
I created a table in which i used timestamp column which tells the record is updated on that time and date.
create table age_info (age tinyint not null,created_on timestamp not null );
But i want to change display like this.select date_format(Now() ,'%W, %e %M %Y # %r');
Tuesday, 31 July 2015 # 02:32:16 PM
But don't know how to do it. When i insert values
insert into age_info(age) values (19);
in the table it show like this.
age created_on
19 2015-07-31 18:55:01
I Don't know how to use this function date_format with timestamp column to show like that format.
I think this will help you to solve the answer
SELECT DATE_FORMAT(`created_on` , '%W, %e %b %Y # %r') FROM `age_info`;
To insert,
INSERT INTO `age_info` (`age`) select DATE_FORMAT(now() , '%W %e, %b %Y # %r')created_on from age_info
Note that, You need to change the table field to varchar.
You can keep the format you want by changing your column definition to a text column. Is that what you really want? You'll lose all the benefits a timestamp column offers (easy date and time calculations, etc).
You can't change the datetime column type to store the data as you want, it changes the meaning of the datetime and no advantage of it, although you can use it to select the format whatever you want using date_format() function.
my mysql database tb_date (varchar 20):
16 November 2014
06 December 2014
01 April 2014
12 April 2015
I want select between 01 January 2014 until 31 December 2014, how the query is with date conversion?
thanks..
This is an anti-pattern, storing date values in VARCHAR columns, rather than using datatypes specifically designed and implemented for storing date values... DATE, DATETIME or TIMESTAMP.
To answer your question, before it gets closed, you could use the STR_TO_DATE function to convert the strings into DATE datatype, and then do the comparison. MySQL won't be able to make use of an index range scan operation, it will need to evaluate that function on every flipping row in the table.
As an example:
SELECT t.mycol
FROM mytable t
WHERE STR_TO_DATE(t.mycol,'%d %M %Y') >= '2014-01-01'
AND STR_TO_DATE(t.mycol,'%d %M %Y') < '2015-01-01'
We'll need to check the MySQL Reference Manual to verify that '%M' is the right format specifier for the full month name...
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-format
Yes, it looks like I guessed right. M is the month name.
As I already commented, you should store your date as Timestamp or Data format then you could simply compare.
However, there is still a solution.. You can convert the varchar to a date directly in your query :
select * from yourTable
where (str_to_date(tb_date, '%d %M %Y') between '2014-01-01' and '2014-12-31');
But please don't use this hack and change your date format...
Edit : If you are really willing to use varchar to store your date, change it to varchar(17) which is the max character possible using your string format.
I have read various questions here on Stackoverflow about the use of FROM_UNIXTIME but none directly deal with what I am trying to do. I have one timestamp in a variable coming from php (that has been reformatted - e.g. 25 March 2014) to a function which uses a database query to determine if there are other entries in the database that have the same date (not time). I've run across various methods for formatting and comparing timestamp entries using MySql and ended up with the following but I understand that it isn't very efficient. Does anyone know of a better way to accomplish this?
FROM_UNIXTIME(sd.timestart, "%e %M %Y") = ?'
where the variable in my array for comparison is the date format listed above. This accomplishes what I want but, again, I don't think it is the most efficient way to get this done. Any advice and/or ideas will be much appreciated.
*EDIT*
My timestamp is stored as an integer so I'm trying to use:
$thissessiondate = strtotime($date->timestart, strtotime('today'));
and
$tomorrowdate = strtotime($date->timestart, strtotime('tomorrow'));
to do trim to midnight but get an error (strtotime() expects parameter 2 to be long) and when I move 'today' to the first argument position, I get a conversion to 11 pm instead of 0:00...? I'm making some progress but my very incomplete knowledge of both PHP and MySQL are holding me back.
If you can avoid it, don't wrap columns used in predicates in expressions.
Have your predicates on bare columns to make index range scans possible. You want the datatype conversion to happen over on the literal side of the predicate, wherever possible.
The STR_TO_DATE function is the most convenient for this.
Assuming the timestart column is DATE, DATETIME or TIMESTAMP (which it really should be, if it represents a point in time.)
WHERE sd.timestart >= STR_TO_DATE( ? , "%e %M %Y")
AND sd.timestart < STR_TO_DATE( ? , "%e %M %Y") + INTERVAL 1 DAY
Effectively, what that's doing is taking the string passed in as the first argument to the STR_TO_DATE function, MySQL is going to convert that string to a DATETIME, based on the format specified as the second argument. And that effectively becomes a literal that MySQL can use to compare to the stored values in the column.
If there's an appropriate index available, MySQL will consider an index range scan operation to satisfy that predicate.
You'd need to pass in the same value twice, but that's not really a problem.
On the second line, we're just adding a day to the same value. So what MySQL is seeing is this:
WHERE sd.timestart >= STR_TO_DATE( '25 March 2014' , "%e %M %Y")
AND sd.timestart < STR_TO_DATE( '25 March 2014' , "%e %M %Y") + INTERVAL 1 DAY
In terms of performance, that's equivalent to:
WHERE sd.timestart >= '2014-03-15 00:00:00'
AND sd.timestart < '2014-03-16 00:00:00'
If you do it the other way around, and wrap timestart in a function, that's going to require MySQL to evaluate the function on every single row (or at least, on every row that isn't filtered out by another predicate first.)
IMPORANT NOTE
Be aware that MySQL interprets datetime values as being in the timezone of the MySQL connection, which defaults to the timezone setting of the MySQL server. MySQL is going to interpret datetime literals in the current setting of the timezone. For example, if MySQL timezone is set to +00:00, then datetime literals will be interpreted as UTC.
I assumed the format string matches the data being passed in, I don't use %e or %m. The %Y is a four digit year. (The list of format elements is in the MySQL documentation, under the DATE_FORMAT function.
Reference: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_str-to-date
If your timestart column is INTEGER or other numeric datatype, representing a number of seconds or some other unit of time since the beginning of an era, you can use the same approach for performance benefits.
In the predicate, reference bare columns from the table, and do any conversions required on the literal side.
If you aren't using MySQL functions to do the conversion to "seconds since Jan 1, 1970 UTC" when rows are inserted (which is really what the TIMESTAMP datatype is doing internally), then I wouldn't recommend using MySQL functions to do the conversion in the query either.
If you're doing the conversion from date and time to an integer type "timestamp" in PHP, then I'd do the inverse conversion in PHP as well, and do the trimming to midnight and the adding of a day in PHP.
In that case, your MySQL query would be of the simple form:
WHERE sd.timestart >= ?
AND sd.timestart < ?
Where you would pass in the appropriate integer values, to compare to the INTEGER timestamp column.
Note that MySQL does provide a function for converting to "seconds since Jan 1 1970 UTC", so if timestart is seconds since Jan 1 1970 UTC, then something like this is valid:
WHERE sd.timestart >= UNIX_TIMESTAMP(STR_TO_DATE( '25 March 2014' , "%e %M %Y"))
AND sd.timestart < UNIX_TIMESTAMP(STR_TO_DATE( '25 March 2014' , "%e %M %Y") + INTERVAL 1 DAY)
BUT... again, be aware of timezone conversion issues; if the MySQL database has a different timezone setting than the web server. If you are going to store "integer", then I wouldn't muck that up with the conversion that MySQL does, which may not be exactly the same as the conversion functions the web server does.
If you store your date as an int timestamp, you can do this
round(sd.timestart/86400)=round(UNIX_TIMESTAMP(NOW())/86400)
This will get everything in your database that is from the same day.
For example:
SELECT id FROM uploads WHERE (approved=0 OR approved is NULL) AND round(uploads.date/86400)<=round(UNIX_TIMESTAMP(NOW())/86400) order by uploads.date DESC LIMIT 20
Will display all the uploads for today and the days before, without showing the future uploads. 86400 is the number of seconds in one day.
THE SITUATION
I pull timestamps formatted in RFC 2822 (Sat, 01 Dec 2012 05:49:45 +0000) and store them in a VARCHAR field in MYSQL. I have a start_date and end_date.
THE GOAL
Search BETWEEN two dates (like start_date BETWEEN '2012-11-01' AND '2012-12-01')
THE CONDITIONS
I want to do this with pure SQL and not do post processing in PHP
THE ACCEPTABLE COMPROMISE
I don't want to, but I will convert and store them as DATETIME by using PHP if needed.
Can anyone help me accomplish my goal (listed above).
Rick
You could convert your string dates do datetime using str_to_date:
select str_to_date('Sat, 01 Dec 2012 05:49:45 +0000','%a, %d %b %Y %T')
If you need to convert also timezone, try this:
set #datestring='Sat, 01 Dec 2012 05:49:45 +0000';
select
CONVERT_TZ(
str_to_date(#datestring,'%a, %d %b %Y %T'),
concat(mid(#datestring, 27, 3), ':', mid(#datestring, 30, 2)),
'+00:00'
)
Store them as a native DATETIME. This is the only sane approach.
Why are you so opposed to using the proper tool for the job?
Storing timestamps as a string is poor use of the database features. Since they were all the same format, they could have easily been converted to a datetime on input.