diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index fdf21a50a028b1e26d776d91f375fa60d509813c..24f29b23e87d13f18c943a7442ea8e79e346de41 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -124,12 +124,34 @@ create table t1 select date_format("2004-01-19 10:10:10", "%Y-%m-%d");
 show create table t1;
 Table	Create Table
 t1	CREATE TABLE `t1` (
-  `date_format("2004-01-19 10:10:10", "%Y-%m-%d")` binary(10) default NULL
+  `date_format("2004-01-19 10:10:10", "%Y-%m-%d")` char(10) character set utf8 default NULL
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 select * from t1;
 date_format("2004-01-19 10:10:10", "%Y-%m-%d")
 2004-01-19
 drop table t1;
+set names utf8;
+set LC_TIME_NAMES='fr_FR';
+create table t1 (s1 char(20) character set latin1);
+insert into t1 values (date_format('2004-02-02','%M'));
+select hex(s1) from t1;
+hex(s1)
+66E97672696572
+drop table t1;
+create table t1 (s1 char(20) character set koi8r);
+set LC_TIME_NAMES='ru_RU';
+insert into t1 values (date_format('2004-02-02','%M'));
+insert into t1 values (date_format('2004-02-02','%b'));
+insert into t1 values (date_format('2004-02-02','%W'));
+insert into t1 values (date_format('2004-02-02','%a'));
+select hex(s1), s1 from t1;
+hex(s1)	s1
+E6C5D7D2C1CCD1	Февраля
+E6C5D7	Фев
+F0CFCEC5C4C5CCD8CEC9CB	Понедельник
+F0CEC4	Пнд
+drop table t1;
+set LC_TIME_NAMES='en_US';
 set names koi8r;
 create table t1 (s1 char(1) character set utf8);
 insert into t1 values (_koi8r'ÁÂ');
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index af40121852f37b4b7a05532b2f38fbe3db6bfcde..0b3f9ed2400d4fdd25239de87d619cb83b8615fa 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -93,6 +93,26 @@ show create table t1;
 select * from t1;
 drop table t1;
 
+#
+# Bug#22646 LC_TIME_NAMES: Assignment to non-UTF8 target fails
+#
+set names utf8;
+set LC_TIME_NAMES='fr_FR';
+create table t1 (s1 char(20) character set latin1);
+insert into t1 values (date_format('2004-02-02','%M'));
+select hex(s1) from t1;
+drop table t1;
+create table t1 (s1 char(20) character set koi8r);
+set LC_TIME_NAMES='ru_RU';
+insert into t1 values (date_format('2004-02-02','%M'));
+insert into t1 values (date_format('2004-02-02','%b'));
+insert into t1 values (date_format('2004-02-02','%W'));
+insert into t1 values (date_format('2004-02-02','%a'));
+select hex(s1), s1 from t1;
+drop table t1;
+set LC_TIME_NAMES='en_US';
+
+
 #
 # Bug #2366  	Wrong utf8 behaviour when data is truncated
 #
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index c1bca7afc60ebe37b8f5e756edd2c7a5a1a8c9ce..8334c8ea3fa45c4b597c49e0cefe145afeedd392 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -595,16 +595,10 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
   uint weekday;
   ulong length;
   const char *ptr, *end;
-  MY_LOCALE *locale;
   THD *thd= current_thd;
-  char buf[128];
-  String tmp(buf, sizeof(buf), thd->variables.character_set_results);
-  uint errors= 0;
+  MY_LOCALE *locale= thd->variables.lc_time_names;
 
-  tmp.length(0);
   str->length(0);
-  str->set_charset(&my_charset_bin);
-  locale = thd->variables.lc_time_names;
 
   if (l_time->neg)
     str->append("-", 1);
@@ -618,41 +612,37 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
     {
       switch (*++ptr) {
       case 'M':
-	if (!l_time->month)
-	  return 1;
-	tmp.copy(locale->month_names->type_names[l_time->month-1],
-		   strlen(locale->month_names->type_names[l_time->month-1]),
-		   system_charset_info, tmp.charset(), &errors);
-	str->append(tmp.ptr(), tmp.length());
-	break;
+        if (!l_time->month)
+          return 1;
+        str->append(locale->month_names->type_names[l_time->month-1],
+                    strlen(locale->month_names->type_names[l_time->month-1]),
+                    system_charset_info);
+        break;
       case 'b':
-	if (!l_time->month)
-	  return 1;
-	tmp.copy(locale->ab_month_names->type_names[l_time->month-1],
-		 strlen(locale->ab_month_names->type_names[l_time->month-1]),
-		 system_charset_info, tmp.charset(), &errors);
-	str->append(tmp.ptr(), tmp.length());
-	break;
+        if (!l_time->month)
+          return 1;
+        str->append(locale->ab_month_names->type_names[l_time->month-1],
+                    strlen(locale->ab_month_names->type_names[l_time->month-1]),
+                    system_charset_info);
+        break;
       case 'W':
-	if (type == MYSQL_TIMESTAMP_TIME)
-	  return 1;
-	weekday= calc_weekday(calc_daynr(l_time->year,l_time->month,
-					 l_time->day),0);
-	tmp.copy(locale->day_names->type_names[weekday],
-		 strlen(locale->day_names->type_names[weekday]),
-		 system_charset_info, tmp.charset(), &errors);
-	str->append(tmp.ptr(), tmp.length());
-	break;
+        if (type == MYSQL_TIMESTAMP_TIME)
+          return 1;
+        weekday= calc_weekday(calc_daynr(l_time->year,l_time->month,
+                              l_time->day),0);
+        str->append(locale->day_names->type_names[weekday],
+                    strlen(locale->day_names->type_names[weekday]),
+                    system_charset_info);
+        break;
       case 'a':
-	if (type == MYSQL_TIMESTAMP_TIME)
-	  return 1;
-	weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
-					l_time->day),0);
-	tmp.copy(locale->ab_day_names->type_names[weekday],
-		 strlen(locale->ab_day_names->type_names[weekday]),
-		 system_charset_info, tmp.charset(), &errors);
-	str->append(tmp.ptr(), tmp.length());
-	break;
+        if (type == MYSQL_TIMESTAMP_TIME)
+          return 1;
+        weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
+                             l_time->day),0);
+        str->append(locale->ab_day_names->type_names[weekday],
+                    strlen(locale->ab_day_names->type_names[weekday]),
+                    system_charset_info);
+        break;
       case 'D':
 	if (type == MYSQL_TIMESTAMP_TIME)
 	  return 1;
@@ -1638,8 +1628,9 @@ longlong Item_func_sec_to_time::val_int()
 
 void Item_func_date_format::fix_length_and_dec()
 {
+  THD* thd= current_thd;
   decimals=0;
-  collation.set(&my_charset_bin);
+  collation.set(thd->variables.collation_connection);
   if (args[1]->type() == STRING_ITEM)
   {						// Optimize the normal case
     fixed_length=1;
@@ -1653,17 +1644,14 @@ void Item_func_date_format::fix_length_and_dec()
     args[1]->collation.set(
         get_charset_by_csname(args[1]->collation.collation->csname,
                               MY_CS_BINSORT,MYF(0)), DERIVATION_COERCIBLE);
-    /*
-      The result is a binary string (no reason to use collation->mbmaxlen
-      This is becasue make_date_time() only returns binary strings
-    */
-    max_length= format_length(((Item_string*) args[1])->const_string());
+    max_length= format_length(((Item_string*) args[1])->const_string()) *
+                collation.collation->mbmaxlen;
   }
   else
   {
     fixed_length=0;
-    /* The result is a binary string (no reason to use collation->mbmaxlen */
-    max_length=min(args[1]->max_length,MAX_BLOB_WIDTH) * 10;
+    max_length= min(args[1]->max_length,MAX_BLOB_WIDTH) * 10 * 
+                collation.collation->mbmaxlen;
     set_if_smaller(max_length,MAX_BLOB_WIDTH);
   }
   maybe_null=1;					// If wrong date
@@ -1783,6 +1771,7 @@ String *Item_func_date_format::val_str(String *str)
   date_time_format.format.length= format->length(); 
 
   /* Create the result string */
+  str->set_charset(collation.collation);
   if (!make_date_time(&date_time_format, &l_time,
                       is_time_format ? MYSQL_TIMESTAMP_TIME :
                                        MYSQL_TIMESTAMP_DATE,