I have date in this date:
STR_TO_DATE('28-AUG-60','%d-%M-%y')
And when i do insert into table i got:
2060-08-28 00:00:00
What do i expected:
1960-08-28 00:00:00
I know that in MSSQL there is a format RR and its gave you 2 or 4-digit year, 20th century for 00-49 how do i do that in MySQL ?
When is look at documentation i got that it will works with %Y but it doesn't
Thank you !
If you know that all 2-digit years above some value, say '50', should be considered as years in the 1900s and the rest should be considered as years in the 2000s, you can use a CASE expression so that you apply a different date format:
SELECT DATE(STR_TO_DATE(
date,
CASE WHEN RIGHT(date, 2) < ? THEN '%d-%M-%Y' ELSE '%d-%M-%y' END
)) date
FROM tablename;
Change ? to the 2-digit year (like '50') that suits your data.
See the demo.
Two digit years cause a problem, because you don't know what centry they are in. MySQL has this well documented in the second of documentation called 2-Digit Years in Dates.
Basically, the cutoff is 2069 rather than 2050.
If you want the years between 1950 and 1969 to be represented, then you can use:
(case when str_to_date('28-AUG-60', '%d-%M-%y') >= '2050-01-01'
then str_to_date('28-AUG-60', '%d-%M-%y') - interval 100 year
else str_to_date('28-AUG-60', '%d-%M-%y')
end)
You are using wrong year format try use '%Y' (instead of '%y')
select STR_TO_DATE('28-AUG-60','%d-%m-%Y')
Related
I need to use September 1st in a where clause and don't want to hard code the year. Whats the best way to return 9/1/year to use in a between statement?
where p.post_date between '2016-09-01' and DATE_ADD(CURDATE(),INTERVAL 1 DAY)
Looking for a replacement of the '2016-09-01' so that it works again next year and going forward. Also, needs to work for oct, nov and dec, of same year.
You can use month() and day():
select t.*
from t
where month(datecol) = 9 and day(datecol) = 1;
I guess you want get the year/09/01 of current year?
SELECT *
FROM YourTable
WHERE datecol = CONCAT ( YEAR(CURDATE()) , '/09/01')
Basically, you want the previous year when you are before the turning date in the current year and the current one when you are after the turning date.
I would suggest to tell MySQL what date format you are using, to do so, you can use the STR_TO_DATE function.
CASE
WHEN MONTH(CURDATE()) < 9 THEN STR_TO_DATE(CONCAT(YEAR(CURDATE())-1, '-09-01'), '%Y-%m-%d')
ELSE STR_TO_DATE(CONCAT(YEAR(CURDATE()), '-09-01', '%Y-%m-%d'))
END
You can put this in a function/routine and use it wherever you need.
How can I replace the year of a date column with that of the current year?
the following returns NULL
SELECT str_to_date(concat(year(now()), '-',
month(datecolumn), '-' ,day(datecolumn)), '%Y-%M-%D')
FROM TABLE
Khalid's answer is correct most of the time. Leap year messes things up! If you run the proposed query where the value of datecol is '2016-02-29' and the CURRENT_DATE is '2017-01-01', for example, you get null.
An alternate way to do this that handles leap year more gracefully is like this:
SELECT DATE_FORMAT(
MAKEDATE(YEAR(CURRENT_DATE()), DAYOFYEAR(datecol)),
'%Y-%m-%d'
) `date`
FROM t
The value of date here would be 2017-03-01.
Edit/clarification: The problem is that changing the year of '2016-02-29' to 2017, for example, produces '2017-02-29', which is not a valid date. Then, running DATE_FORMAT('2017-02-29', '%Y-%m-%d') results in null. A demo of the problem is here:
http://sqlfiddle.com/#!9/c5358/11
However, after reviewing my answer I realized that I another problem by using MAKEDATE since any date on a leap year after Feb 28 is days+1 for a "normal" year with 365 days. For example, if datecol = '2016-03-01' and the current year were 2017 then the converted date would be '2017-03-02', not '2017-03-01' as desired. A better approach is as follows:
SELECT
DATE_FORMAT(DATE_ADD(datecol, INTERVAL (YEAR(CURRENT_DATE()) - YEAR(datecol)) YEAR), '%Y-%m-%d') `date`
FROM t;
This method turns any Feb 29th into the 28th, and otherwise keeps all other dates exactly as you'd expect them. A demo of the solution is here:
http://sqlfiddle.com/#!9/c5358/12
You can do so
SELECT
CONCAT(YEAR(CURRENT_DATE()),RIGHT(datecol,15)) `date`
FROM t
Demo
Or for date only
SELECT
DATE_FORMAT(
CONCAT(YEAR(CURRENT_DATE()),RIGHT(datecol,15))
,'%Y-%m-%d') `date`
FROM t
Demo 2
I'm trying to query through historical data and I need to return data just from a 1 month period: 2 weeks back and 2 weeks forward,but I need the year to not matter.
So, if I was to make the query today I would want all rows with date between xxxx-06-31 and xxxx-07-27
Thanks in advance for the help!
EDIT:
I've tried two ways. both of which I believe will not work around the new year. One is to use datepart(day) and the other would be to simply take the year off of date and compare.
The best way to think of this problem is to convert your dates to a number between 0 and 365 corresponding to the day in the year. Then simply choosing dates where this difference is less than 14 gives you your two week window.
That will break down at the beginning or end of the year. But simple modular arithmetic gives you the answer.
Fortunately, MySQL has DAYOFYEAR(date), so it's not so complicated:
SELECT * FROM tbl t
WHERE
MOD(DAYOFYEAR(currdate) - DAYOFYEAR(t.the_date) + 365, 365) <= 14
OR MOD(DAYOFYEAR(t.the_date) - DAYOFYEAR(currdate) + 365, 365) <= 14
That extra + 365 is needed since MySQL's MOD will return negative numbers.
This answer doesn't account for leap years correctly. If the current year is not a leap year and the currdate is within 14 days of the end of the year, then you'll miss one day in Jan that you should have included. If you care about that, then you should replace 365 with [the number of days in the year - 1].
Supposed you have a date like this,
create table datelist
(
d date
);
insert into datelist values
('2012-07-01'),
('2011-06-29'),
('2012-07-02'),
('2010-07-05'),
('2012-05-31'),
('2010-06-30');
Try this query below,
SELECT d, date_format(d,'%Y-%b-%d')
FROM datelist
WHERE (MONTH(d) = 6 AND DAYOFMONTH(d) >= 30)
OR (MONTH(d) = 7 AND DAYOFMONTH(d) <= 27)
SQLFiddle Demo
Is it OK if the solution is terribly slow?
SELECT tbl.*
FROM tbl
INNER JOIN (SELECT COALESCE(DATE(CONCAT(yyyy, '-', MONTH(CURRENT_DATE), '-', DAYOFMONTH(CURRENT_DATE)),
DATE(CONCAT(yyyy, '-02-28'))) AS midpoint
FROM (SELECT DISTINCT(YEAR(d)) AS yyyy
FROM tbl) all_years) adjusted
ON tbl.datecol BETWEEN adjusted.midpoint - INTERVAL 2 WEEK
AND
adjusted.midpoint + INTERVAL 2 WEEK;
That computes all midpoints for all years in the data set, and then pulls records +- 2 weeks from any such midpoint, which handles end-of-year wrapping.
The COALESCE handles 02-29 on years without leapday (which MySQL will NULL-ify), forcing it down to 02-28.
WHERE `time` BETWEEN 'Jan 1 %' AND 'Jan 8 %' AND ...
Results
Jan 1 00:33:23
Jan 10 08:52:05
How would I avoid the Jan 10 results?
I have tried a few different combination with %, <=, etc.
Any ideas?
Thanks
WHERE Time >= '1/1/2011' AND Time < '1/9/2011'
Or, if you want results from any year:
WHERE DATEPART( month, Time ) = 1 AND DATEPART( day, Time ) < 9
Currently with this query you confuse the search engine because "between" is designed for use with numbers or dates, while you use it with strings.
There are 2 solutions to your problem:
1) Convert your "time" field to "date" and store the dates as "01-01-2010 00:00" (This is the most healthy solution as you will make the DB aware that is a date field)
2) Try:
WHERE `time` >= 'Jan 1' AND `time` < 'Jan 2'
The second solution may give strange results as it is comparing 2 strings, not 2 dates.
I can't try it for you here, but why don't you try around with the STR_TO_DATE method? You can change your time field to a real date, and then don't need to do that string compare:
WHERE STR_TO_DATE(`time`,'%d,%m,%Y') BETWEEN
'2010-01-01'
AND
'2010-01-09'
also, see http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_str-to-date
Oracle's table server offers a built-in function, TRUNC(timestamp,'DY'). This function converts any timestamp to midnight on the previous Sunday. What's the best way to do this in MySQL?
Oracle also offers TRUNC(timestamp,'MM') to convert a timestamp to midnight on the first day of the month in which it occurs. In MySQL, this one is straightforward:
TIMESTAMP(DATE_FORMAT(timestamp, '%Y-%m-01'))
But this DATE_FORMAT trick won't work for weeks. I'm aware of the WEEK(timestamp) function, but I really don't want week number within the year; this stuff is for multiyear work.
You can use both YEAR(timestamp) and WEEK(timestamp), and use both of the these expressions in the SELECT and the GROUP BY clause.
Not overly elegant, but functional...
And of course you can combine these two date parts in a single expression as well, i.e. something like
SELECT CONCAT(YEAR(timestamp), '/', WEEK(timestamp)), etc...
FROM ...
WHERE ..
GROUP BY CONCAT(YEAR(timestamp), '/', WEEK(timestamp))
Edit: As Martin points out you can also use the YEARWEEK(mysqldatefield) function, although its output is not as eye friendly as the longer formula above.
Edit 2 [3 1/2 years later!]:
YEARWEEK(mysqldatefield) with the optional second argument (mode) set to either 0 or 2 is probably the best way to aggregate by complete weeks (i.e. including for weeks which straddle over January 1st), if that is what is desired. The YEAR() / WEEK() approach initially proposed in this answer has the effect of splitting the aggregated data for such "straddling" weeks in two: one with the former year, one with the new year.
A clean-cut every year, at the cost of having up to two partial weeks, one at either end, is often desired in accounting etc. and for that the YEAR() / WEEK() approach is better.
Figured it out... it's a little cumbersome, but here it is.
FROM_DAYS(TO_DAYS(TIMESTAMP) -MOD(TO_DAYS(TIMESTAMP) -1, 7))
And, if your business rules say your weeks start on Mondays, change the -1 to -2.
Edit
Years have gone by and I've finally gotten around to writing this up.
https://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/
The accepted answer above did not work for me, because it ordered the weeks by alphabetical order, not chronological order:
2012/1
2012/10
2012/11
...
2012/19
2012/2
Here's my solution to count and group by week:
SELECT CONCAT(YEAR(date), '/', WEEK(date)) AS week_name,
YEAR(date), WEEK(date), COUNT(*)
FROM column_name
GROUP BY week_name
ORDER BY YEAR(DATE) ASC, WEEK(date) ASC
Generates:
YEAR/WEEK YEAR WEEK COUNT
2011/51 2011 51 15
2011/52 2011 52 14
2012/1 2012 1 20
2012/2 2012 2 14
2012/3 2012 3 19
2012/4 2012 4 19
You can get the concatenated year and week number (200945) using the YEARWEEK() function. If I understand your goal correctly, that should enable you to group your multi-year data.
If you need the actual timestamp for the start of the week, it's less nice:
DATE_SUB( field, INTERVAL DAYOFWEEK( field ) - 1 DAY )
For monthly ordering, you might consider the LAST_DAY() function - sort would be by last day of the month, but that should be equivalent to sorting by first day of the month ... shouldn't it?
Just ad this in the select :
DATE_FORMAT($yourDate, \'%X %V\') as week
And
group_by(week);
If you need the "week ending" date this will work as well. This will count the number of records for each week. Example: If three work orders were created between (inclusive) 1/2/2010 and 1/8/2010 and 5 were created between (inclusive) 1/9/2010 and 1/16/2010 this would return:
3 1/8/2010
5 1/16/2010
I had to use the extra DATE() function to truncate my datetime field.
SELECT COUNT(*), DATE_ADD( DATE(wo.date_created), INTERVAL (7 - DAYOFWEEK( wo.date_created )) DAY) week_ending
FROM work_order wo
GROUP BY week_ending;
Previous Sunday:
STR_TO_DATE(CONCAT(YEARWEEK(timestamp,2),'0'),'%X%V%w')
Previous Monday:
STR_TO_DATE(CONCAT(YEARWEEK(timestamp,3),'1'),'%x%v%w')
DATE_FORMAT(date,format) reference:
%V - Week (01..53), where Sunday is the first day of the week; WEEK() mode 2; used with %X
%v - Week (01..53), where Monday is the first day of the week; WEEK() mode 3; used with %x
%w - Day of the week (0=Sunday..6=Saturday)
%X - Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V
%x - Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v
I like the week function in MySQL, but in my situation, I wanted to know which week of the month a row was in. I utlized this solution:
where run_date is a timestamp like 2021-02-25 00:00:00
concat (
date_format(run_date, '%Y-%m'),
' wk ',
(week(run_date,1) - ( week(date_format(run_date, '%Y-%m-01')) - 1))
) as formatted_date
This outputs:
2021-02-23 ---> 2021-02 wk 4
2021-02-25 ---> 2021-02 wk 4
2021-02-11 ---> 2021-02 wk 2
2021-03-02 ---> 2021-03 wk 1
The idea behind this is that I want to know (with relative certainty) which week of the month in question did the date occur?
So we concatenate:
date_format(run_date, '%Y-%m') to get 2021-02
then we add the literal text string wk
then we use:
week(run_date, 1) to get the week (1 to start Monday) of this record, (which would be 7 because 02/21/2021 is in the 7th week of the year, and we subtract whatever the week is on the 1st day of this same month - the week() for 2021-02-01 is 5, because it is in the 5th week of the year:
(week(date_format(run_date, '%Y-%m-01'))
Unfortunately, this will start out the counting at 0, which people don't like, so we subtract 1 from the last part of the concatenation result so that the "week" start at 1.
This may be a good option:
SELECT
year(datetime_field) as year_date, week(datetime_field) as week_date
FROM
bd.table
GROUP BY
year_date, week_date;
It would look like this:
'2020', '14'
'2020', '15'
'2020', '16'
'2020', '17'
'2020', '18'