How should I use MySQL's FROM UNIXTIME correctly in CDbMigration in Yii 1.x?
I have borrowed solution of converting current time given as timestamp, to MySQL's DateTime field from this answer and when just printing it:
echo 'FROM_UNIXTIME('.$base.')'."\n";
echo 'FROM_UNIXTIME('.$sixDaysLater.')'."\n";
everything seems fine:
FROM_UNIXTIME(1418223600)
FROM_UNIXTIME(1418742000)
But, when I'm trying to use the same technique as a part of my migration:
$this->insert('contents', array
(
'author_id'=>1,
'type'=>5,
'status'=>1,
'category'=>1,
'title'=>'title',
'body'=>'body',
'creation_date'=>'FROM_UNIXTIME('.$base.')',
'modification_date'=>'FROM_UNIXTIME('.$base.')',
'availability_date'=>'FROM_UNIXTIME('.$sixDaysLater.')',
'short'=>'short'
));
This fails -- that is, migration goes fine, but I can see in phpMyAdmin, that related fields for this record has been populated with zeros (0000-00-00 00:00:00), not with the expected value.
What am I missing? Is it, because values in insert are being encoded / escaped?
You can use CDBExpression instead:
new CDbExpression("NOW()");
I mean:
'creation_date'=>new CDbExpression("NOW()")
Or if you want to use FROM UNIXTIME you can do the same.
CDbExpression represents a DB expression that does not need escaping.
Related
I actually get very mad about PHP and SQLite3 and the way some of my strings behave there.
I try to save opening hours but in strings instead of numeric to prevent problem with leading zeros (and still have it now haha... -.-).
Hours and minutes have their own column but when I insert '0x' the zero is gone and whatever x is, is left in the database. :/
Im sure im just missing some little damn part somewhere...
I already checked the INSERT-statement but found nothing at all.
Example for an insert string:
INSERT INTO opening INSERT INTO opening (start_day, end_day, start_hour, start_minute, end_hour, end_minute) VALUES('Montag', 'Freitag', '00', '00', '01', '00')
But the output is:
11|Montag|Freitag|0|0|1|0
Part of the Code:
class Database_Opening_Hours extends SQLite3{
function __construct() {
if(!file_exists("../../data/opening_hours/opening_hours.sqlite")){
$this->open("../../data/opening_hours/opening_hours.sqlite");
$this->exec('CREATE TABLE opening (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, start_day STRING, end_day STRING, start_hour STRING, start_minute STRING, end_hour STRING, end_minute STRING)');
}
else{
$this->open("../../data/opening_hours/opening_hours.sqlite");
}
}
}
$db = new Database_Opening_Hours();
$insert = "INSERT INTO opening (start_day, end_day, start_hour, start_minute, end_hour, end_minute) VALUES('".htmlspecialchars($_GET["start_day"])."','".htmlspecialchars($_GET["end_day"])."','".$start_hour."','".$start_minute."','".$end_hour."','".$end_minute."')";
if($db->exec($insert)){
$db->close();
unset($db);
echo "Insert erfolgreich";
}else{
$db->close();
unset($db);
echo "Nicht wirklich...";
}
Fairly sure that the type of your columns is set to an integer (or any other number type) instead of TEXT.
Make sure to double check the column data type and actually dump the table for us to check if it's really set to TEXT.
This is caused by SQLite using dynamic typing. From the FAQ:
This is a feature, not a bug. SQLite uses dynamic typing. It does not enforce data type constraints. Data of any type can (usually) be inserted into any column. You can put arbitrary length strings into integer columns, floating point numbers in boolean columns, or dates in character columns. The datatype you assign to a column in the CREATE TABLE command does not restrict what data can be put into that column. Every column is able to hold an arbitrary length string.
And from the linked page (emphasis mine):
In order to maximize compatibility between SQLite and other database engines, SQLite supports the concept of "type affinity" on columns. The type affinity of a column is the recommended type for data stored in that column. The important idea here is that the type is recommended, not required. Any column can still store any type of data. It is just that some columns, given the choice, will prefer to use one storage class over another. The preferred storage class for a column is called its "affinity".
So SQLite is dynamically casting your values to integer.
I would suggest combining start_hour and start_minute into start_time (the same for the end_ fields) and storing the value in the format 00:00.
SQLite will store this 'as-is' but is smart enough to recognise a time value and allow you to perform date/time operations:
select time(start_time, '+1 hour') from opening
I had this problem with C/C++ because I did not quote the strings:
insert into test values('aa', 'bb');
use varchar instead of string, I had the same problem then I used varchar(length) and it worked fine
I'm calling strtotime() on a formatted datetime string and for some reason it always returns NOW()...
If my formatted datetime string (stored in the last_seen attribute) is: 2013-06-13 07:13:04
and I write the following code:
echo $user->last_seen;
echo date('F j, Y', strtotime($user->last_seen));
The output I get is:
NOW() January 1, 1970
What on earth is going wrong here??? This is definitely not the expected result. The string is stored in a MySQL database, if that makes any difference.
Edit: by request, the code used to create the attribute in the database is:
$user->last_seen = date('Y-m-d H:i:s');
$user->save;
Edit 2: by request, the code used to pull the users table, with the user we want, is:
$user = User::find($user_id);
(not very helpful, lol).
Edit 3: if I var_dump($user->last_seen) the result is:
object(Laravel\Database\Expression)#40 (1) { ["value":protected]=> string(5) "NOW()" }
Edit 4: If I echo var_dump(strtotime($user->last_seen)) the result is:
bool(false)
Edit 5: this problem was a result of me being an idiot, but some fine debugging was done by everyone who posted. Read the answers if you are interested.
First of all You check the return value of strtotime($user->last_seen)
If strtotime($user->last_seen) returns false then $user->last_seen may be empty or not a valid Date and Time Formats
var_dump(strtotime($user->last_seen))
Your problem is most likely not in the select clause, but lays there where you store your data.
When you are inserting the time in the database, you are probably doing
insert into myTable (fieldname) values ('now()');
instead of
insert into myTable (fieldname) values (now());
So you need to lose the quotes there...
You are NOT storing the time in the database, but the string now() ...
The best thing you could actually do is change the database column type from varchar to DateTime, so even the database knows it's a DateTime. Then you avoid having to cast it back to DateTime in PHP.
Oh dear god.... I'm going to kick myself for this one. I did a project wide Ctrl+F for last_seen and I discovered that in my routing scheme I had this:
Route::filter('before', function() {
if (Auth::check()) {
$user = Auth::user();
$user->last_seen = DB::raw('NOW()');
$user->save();
}
});
Walks away with tail between legs...
usersim interested how do i select a text field form my mysql database, i have a table named users with a text field called "profile_fields" where addition user info is stored. How do i access it in php and make delete it? I want to delete unvalidate people.
PHP code
<?php
//Working connection made before assigned as $connection
$time = time();
$query_unactive_users = "DELETE FROM needed WHERE profile_fields['valid_until'] < $time"; //deletes user if the current time value is higher then the expiring date to validate
mysqli_query($connection , $query_unactive_users);
mysqli_close($connection);
?>
In phpmyadmin the field shows (choosen from a random user row):
a:1:{s:11:"valid_until";i:1370695666;}
Is " ... WHERE profile_fields['valid_until'] ..." the correct way?
Anyway, here's a very fragile solution using your knowledge of the string structure and a bit of SUBSTRING madness:
DELETE FROM needed WHERE SUBSTRING(
profile_fields,
LOCATE('"valid_until";i:', profile_fields) + 16,
LOCATE(';}', profile_fields) - LOCATE('"valid_until";i:', profile_fields) - 16
) < UNIX_TIMESTAMP();
But notice that if you add another "virtual field" after 'valid_until', that will break...
You can't do it in a SQL command in a simple and clean way. However, the string 'a:1:{s:11:"valid_until";i:1370695666;}' is simply a serialized PHP array.
Do this test:
print_r(unserialize('a:1:{s:11:"valid_until";i:1370695666;}'));
The output will be:
Array ( [valid_until] => 1370695666 )
So, if you do the following, you can retrieve your valid_until value:
$arrayProfileData = unserialize('a:1:{s:11:"valid_until";i:1370695666;}');
$validUntil = arrayProfileData['valid_until'];
So, a solution would be to select ALL items in the table, do a foreach loop, unserialize each "profile_fields" field as above, check the timestamp, and store the primary key of each registry to be deleted, in a separate array. At the end of the loop, do a single DELETE operation on all primary keys you stored in the loop. To do that, use implode(',', $arrayPKs).
It's not a very direct route, and depending on the number of registers, it may not be slow, but it's reliable.
Consider rixo's comment: if you can, put the "valid_until" in a separate column. Serializing data can be good for storage of non-regular data, but never use it to store data which you may need to apply SQL filters later.
I have the same problem but a little different from Neil problems (Error when trying to insert date into datetime column),
Neil want to get now date time so he can use CURRENT_TIMESTAMP or GETDATE().
My question is, how if I have string of date like:
$date = '2011-03-29';
then I want to insert into SQL Server database using a stored procedure with PHP.
insert into tbl(date)
values($date)
Can anybody help? Thanks
Just fyi, I have
SQL Server table:
CREATE TABLE tbl
(
date datetime
)
Stored procedure:
create procedure sp_insertdate
(#date datetime)
as
begin
insert into tbl(date) values(#date)
end
PHP code:
<?php
$date = '2011-03-29';
include("con.php");
$query = mssql_init("sp_insertdate");
mssql_bind($query, "#date", &$date, SQLINT4); //sqlint4 for datetime
mssql_execute($query);
?>
The result is 1900-1-1,
I have tried to send the varchar (in php) first then convert to the datetime (in stored procedure) but there is some error.
Really I'm stuck.. any idea for this problem?
I just want to insert string 2011-03-29 into a SQL Server datetime column using a stored procedure from PHP. I'm sorry because I can't speak English fluently
Whenever I've had a problem like this (using mysql), I just had to add the time (midnight) onto the date so that it can recognize it as the datetime that it's expecting. Try this:
$date = '2011-03-29';
$date .= ' 00:00:00';
Then process the rest as you would. This works for mysql, maybe sql-server needs it like this too.
i got answer from my friends,
just put
mssql_bind($query, "#date", &$date, SQLCHAR); //not sqlint4 for datetime but just sqlchar or sqlvarchar
however many thanks to Groovetrain, i can put also
$date='2011-03-29 00:00:00'
then put
mssql_bind($query, "#date", &$date, SQLCHAR,false,false,19); //19 length of date string
I have a table with 12 timestamp columns and 3 other fields.
I can't change the field type on the timestamp columns.
I need to display all 15 fields to the user as m/d/y. Is there a way to format them all at the same time without having to apply DATE_FORMAT to each one?
I'd rather not have to do
SELECT DATE_FORMAT(field, '%c/%e/%y') AS field
for each one if possible.
I'm using mySQL & PHP and I don't care where the conversion happens.
You can write a simple date conversion routine in php such as this:
function mysql2table($date) {
$new = explode("-",$date);
$a=array ($new[2], $new[1], $new[0]);
return $n_date=implode("-", $a);
}
Which I stole from here: http://www.daniweb.com/code/snippet736.html#
Then simply loop through your SQL column results checking if the value is a date and converting it.
Have you considered using a database layer like MDB2 or PDO, which can convert the types for you? MDB2 has a date type, that displays YYYY-MM-DD format but could easily be turned into m/d/y with strftime and strtotime.
An example of using MDB2:
$dsn = "mysql://user#pass/db"; (not sure about DSN format, you might have to poke the MDB2 documentation)
$connection = MDB2::connect ($dsn);
$connection->loadModule ("Extended");
$rows = $connection->getAll ("your query", array ('date', ...), $parameters, array (paramater-types), MDB2_FETCHMODE_OBJECT);
if (MDB2_Driver_Common::isError ($rows)) throw new Exception ("Error!");
else { foreach ($rows as $row) { ...Do something... } }
You can find more documentation about using MDB in this way at MDB2 on InstallationWiki. Also there you'll find a list of MDB2 datatypes and what they are mapped to for display values. Also, Docs for MDB2_Extended will be a good source of info.
Edit: Obviously you'll have to use strftime and strtotime on each row separately. If you switch MDB2_FETCHMODE_OBJECT to MDB2_FETCHMODE_ORDERED or MDB2_FETCHMODE_ASSOC above, you can probably use a foreach loop to run strftime and strtotime on all of the rows that need to be reformatted.
I dont think it is possible, the query doesnt know what columns are until it returns the results, you have to tell it to change the formatting for each datetime.
Matt