dates not properly exchanged between PHP and MySQL

  You are currently not logged in. You can view the forums, but cannot post messages. Log In | Register

16-Jan-12 16:34
This post is in reference to the Build a CMS in an Afternoon forum question regarding exchanging dates between PHP and MySQL:

In a nutshell, the dates I enter on the editArticle.php form for starting and ending the publication of an article are appearing correctly in the MySQL database I have set up. But when I tested editing an already-existing article, these dates come back to the form as 12-31-1969.

(I also have a creationDate property, which is automatically entered as

value="<?php echo date('Y-m-d') ?>"


There is no problem with this date field going to or coming from MySQL.)


I believe this means that the pubStart and pubEnd dates are passed correctly to the database, but when coming out of the database, they are not properly defined.

Here is the code from Article.php for the relevant date fields:


class Article {
public $creationDate = null;
public $pubStart = null;
public $pubEnd = null;

...
}

public function __construct( $data=array() ) {
if ( isset( $data['creationDate'] ) ) $this->creationDate = (int) $data['creationDate'];
if ( isset( $data['pubStart'] ) ) $this->pubStart = (int) $data['pubStart'];
if ( isset( $data['pubEnd'] ) ) $this->pubEnd = (int) $data['pubEnd'];
...
}

public function storeFormValues ( $params ) {

// Store all the parameters
$this->__construct( $params );

// Parse and store the creationDate data
if ( isset($params['creationDate']) ) {
$creationDate = explode ( '-', $params['creationDate'] );

if ( count($creationDate) == 3 ) {
list ( $y, $m, $d ) = $creationDate;
$this->creationDate = mktime ( 0, 0, 0, $m, $d, $y );
}
}

// Parse and store the pubStart date
if ( isset($params['pubStart']) ) {
$pubStart = explode ( '-', $params['pubStart'] );

if ( count($pubStart) == 3 ) {
list ( $y, $m, $d ) = $pubStart;
$this->pubStart = mktime ( 0, 0, 0, $m, $d, $y );
}
}


// Parse and store the pubEnd date
if ( isset($params['pubEnd']) ) {
$pubEnd = explode ( '-', $params['pubEnd'] );

if ( count($pubEnd) == 3 ) {
list ( $y, $m, $d ) = $pubEnd;
$this->pubEnd = mktime ( 0, 0, 0, $m, $d, $y );
}
}
}

public function insert() {

// Does the Article object already have an ID?
if ( !is_null( $this->id ) ) trigger_error ( "Article::insert(): Attempt to insert an Article object that already has its ID property set (to $this->id).", E_USER_ERROR );

// Insert the Article
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "INSERT INTO articles_2 ( creationDate, pubStart, pubEnd, title, summary, content, author ) VALUES ( FROM_UNIXTIME(:creationDate), FROM_UNIXTIME(:pubStart), FROM_UNIXTIME(:pubEnd), :title, :summary, :content, :author )";
$st = $conn->prepare ( $sql );
$st->bindValue( ":creationDate", $this->creationDate, PDO::PARAM_INT );
$st->bindValue( ":pubStart", $this->pubStart, PDO::PARAM_INT );
$st->bindValue( ":pubEnd", $this->pubEnd, PDO::PARAM_INT );
...
}

public function update() {

// Does the Article object have an ID?
if ( is_null( $this->id ) ) trigger_error ( "Article::update(): Attempt to update an Article object that does not have its ID property set.", E_USER_ERROR );

// Update the Article
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "UPDATE articles_2 SET creationDate=FROM_UNIXTIME(:creationDate), pubStart=FROM_UNIXTIME(:pubStart), pubEnd=FROM_UNIXTIME(:pubEnd), title=:title, summary=:summary, content=:content, author=:author WHERE id = :id";
$st = $conn->prepare ( $sql );
$st->bindValue( ":creationDate", $this->creationDate, PDO::PARAM_INT );
$st->bindValue( ":pubStart", $this->pubStart, PDO::PARAM_INT );
$st->bindValue( ":pubEnd", $this->pubEnd, PDO::PARAM_INT );
...
}



and here is the code from the editArticle.php form:



<li>
<label for="creationDate">Article Creation Date</label> <input type="date" name="creationDate" id="creationDate" placeholder="YYYY-MM-DD" required maxlength="10" value="<?php echo date('Y-m-d') ?>" />
</li>

<li>
<label for="pubStart">Publish Start Date</label> <input type="date" name="pubStart" id="pubStart" placeholder="YYYY-MM-DD" required maxlength="10" value="<?php echo $results['article']->pubStart ? date( "Y-m-d", $results['article']->pubStart ) : "" ?>" />
</li>


<li>
<label for="pubEnd">Publish End Date</label> <input type="date" name="pubEnd" id="pubEnd" placeholder="YYYY-MM-DD" required maxlength="10" value="<?php echo $results['article']->pubEnd ? date( "Y-m-d", $results['article']->pubEnd ) : "" ?>" />
</li>



What do I need to do to correct this problem? Any help appreciated.

Best,
Shelley

--
What will we do when the power goes out?
19-Jan-12 23:45
@shelley3: You need to use the MySQL FROM_UNIXTIME() function for all dates and datetimes inside your insert() and update() methods, as is done with the publicationDate field in the original tutorial. You also need to use the corresponding UNIX_TIMESTAMP() function for all dates and datetimes in getById() and getList().

The reason is that the Article class stores dates and datetimes in Unix timestamp format, but MySQL stores them using its own date/datetime formats. You need to call those 2 functions to convert between the 2 formats.

--
Matt Doyle, Elated
3rd Edition of my jQuery Mobile book out now! Learn to build mobile web apps. Free sample chapter: http://store.elated.com/
20-Jan-12 10:10
Thanks so much for your response, Matt.

I used the same code in the cms download (for publicationDate) for my pubStart and pubEnd dates.

This code for "Insert the Article" and "Updates the currrent Article" in the Article.php, says the following:


// Insert the Article
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "INSERT INTO articles ( publicationDate, title, summary, content ) VALUES ( FROM_UNIXTIME(:publicationDate), :title, :summary, :content )";
$st = $conn->prepare ( $sql );
$st->bindValue( ":publicationDate", $this->publicationDate, PDO::PARAM_INT );

// Update the Article
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "UPDATE articles SET publicationDate=FROM_UNIXTIME(:publicationDate), title=:title, summary=:summary, content=:content WHERE id = :id";



So from your instructions, should it actually say:

$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "INSERT INTO articles ( publicationDate, title, summary, content ) VALUES ( MYSQL FROM_UNIXTIME(:publicationDate), :title, :summary, :content )";
$st = $conn->prepare ( $sql );
$st->bindValue( ":publicationDate", $this->publicationDate, PDO::PARAM_INT );

// Update the Article
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "UPDATE articles SET publicationDate=MYSQL FROM_UNIXTIME(:publicationDate), title=:title, summary=:summary, content=:content WHERE id = :id";


The function getList() and the function getById() code does say UNIX_TIMESTAMP(publicationDate) as used in publicationDate.

If I have misinterpreted your directions and it should just be FROM_UNIXTIME, not MYSQL FROM_UNIXTIME, I will go back and make sure I have correctly coded my new pubStart and pubEnd dates.

Thanks again for clarifying the differences between PHP and MySQL date formats and the means to convert them from one format to the other. I am sure this will solve the problem I was having.

Best regards,
Shelley


--
What will we do when the power goes out?
20-Jan-12 13:06
OK, I have just found the answer to my questions above:

From the MySQL 5.5 Reference

11.7. Date and Time Functions

This section describes the functions that can be used to manipulate temporal values. See Section 10.3, “Date and Time Types”, for a description of the range of values each date and time type has and the valid formats in which values may be specified.

FROM_UNIXTIME() is the correct MySQL function wording.
If I am understanding this, UNIXTIME() is the equivalent of the PHP mktime.

From the PHP Manual:
"mktime — Get Unix timestamp for a date"

mktime "returns the Unix timestamp corresponding to the arguments given. This timestamp is a long integer containing the number of seconds between the Unix Epoch (January 1 1970 00:00:00 GMT) and the time specified.

Arguments may be left out in order from right to left; any arguments thus omitted will be set to the current value according to the local date and time"

UNIX_TIMESTAMP function for inserting and updating tells php to insert the mktime parameters into MySQL.

The function storeFormValues ( $params ) tells us that the publicationDate is stored as mktime ( 0, 0, 0, $m, $d, $y ), which is equivalent to the Unix timestamp required by MySQL.

Matt, is this correct?

Shelley

--
What will we do when the power goes out?
23-Jan-12 00:38
@shelley3: No, your insert() method should look like this in your case:


public function insert() {

// Does the Article object already have an ID?
if ( !is_null( $this->id ) ) trigger_error ( "Article::insert(): Attempt to insert an Article object that already has its ID property set (to $this->id).", E_USER_ERROR );

// Insert the Article
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "INSERT INTO articles ( publicationDate, pubStart, pubEnd, title, summary, content ) VALUES ( FROM_UNIXTIME(:publicationDate), FROM_UNIXTIME(:pubStart), FROM_UNIXTIME(:pubEnd), :title, :summary, :content )";
$st = $conn->prepare ( $sql );
$st->bindValue( ":publicationDate", $this->publicationDate, PDO::PARAM_INT );
$st->bindValue( ":pubStart", $this->pubStart, PDO::PARAM_INT );
$st->bindValue( ":pubEnd", $this->pubEnd, PDO::PARAM_INT );
$st->bindValue( ":title", $this->title, PDO::PARAM_STR );
$st->bindValue( ":summary", $this->summary, PDO::PARAM_STR );
$st->bindValue( ":content", $this->content, PDO::PARAM_STR );
$st->execute();
$this->id = $conn->lastInsertId();
$conn = null;
}


Notice the additional calls to FROM_UNIXTIME() for your new date fields.

Same deal for the update() method.

And like I said, you need to wrap UNIX_TIMESTAMP() around your new date fields within getById() and getList() so that the MySQL date values are converted back to Unix timestamps for storage in the class properties.

Make sense?

--
Matt Doyle, Elated
3rd Edition of my jQuery Mobile book out now! Learn to build mobile web apps. Free sample chapter: http://store.elated.com/
25-Jan-12 11:08
Hello Matt,

In reply to your above response (for which I thank you), if you read the partial code I put in my first post, you will see that I am using FROM_UNIXTIME for the inserting and updating the dates.

Here is what I was using (note that ". . . " indicates that there is more code that I haven't included here):



class Article {
public $creationDate = null; //used to be called publicationDate
public $pubStart = null; //new date field
public $pubEnd = null; //new date field

... //more code not included here
}

public function __construct( $data=array() ) {
if ( isset( $data['creationDate'] ) ) $this->creationDate = (int) $data['creationDate'];
if ( isset( $data['pubStart'] ) ) $this->pubStart = (int) $data['pubStart'];
if ( isset( $data['pubEnd'] ) ) $this->pubEnd = (int) $data['pubEnd'];


... //more code not included here
}

public function storeFormValues ( $params ) {

// Store all the parameters
$this->__construct( $params );

// Parse and store the creationDate data
if ( isset($params['creationDate']) ) {
$creationDate = explode ( '-', $params['creationDate'] );

if ( count($creationDate) == 3 ) {
list ( $y, $m, $d ) = $creationDate;
$this->creationDate = mktime ( 0, 0, 0, $m, $d, $y );
}
}

// Parse and store the pubStart date
if ( isset($params['pubStart']) ) {
$pubStart = explode ( '-', $params['pubStart'] );

if ( count($pubStart) == 3 ) {
list ( $y, $m, $d ) = $pubStart;
$this->pubStart = mktime ( 0, 0, 0, $m, $d, $y );
}
}


// Parse and store the pubEnd date
if ( isset($params['pubEnd']) ) {
$pubEnd = explode ( '-', $params['pubEnd'] );

if ( count($pubEnd) == 3 ) {
list ( $y, $m, $d ) = $pubEnd;
$this->pubEnd = mktime ( 0, 0, 0, $m, $d, $y );
}
}
}

public function insert() {

// Does the Article object already have an ID?
if ( !is_null( $this->id ) ) trigger_error ( "Article::insert(): Attempt to insert an Article object that already has its ID property set (to $this->id).", E_USER_ERROR );

// Insert the Article
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "INSERT INTO articles_2 ( creationDate, pubStart, pubEnd, title, summary, content, author ) VALUES ( FROM_UNIXTIME(:creationDate), FROM_UNIXTIME(:pubStart), FROM_UNIXTIME(:pubEnd), :title, :summary, :content, :author )";
$st = $conn->prepare ( $sql );
$st->bindValue( ":creationDate", $this->creationDate, PDO::PARAM_INT );
$st->bindValue( ":pubStart", $this->pubStart, PDO::PARAM_INT );
$st->bindValue( ":pubEnd", $this->pubEnd, PDO::PARAM_INT );

... More code not included here
}

public function update() {

// Does the Article object have an ID?
if ( is_null( $this->id ) ) trigger_error ( "Article::update(): Attempt to update an Article object that does not have its ID property set.", E_USER_ERROR );

// Update the Article
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "UPDATE articles_2 SET creationDate=FROM_UNIXTIME(:creationDate), pubStart=FROM_UNIXTIME(:pubStart), pubEnd=FROM_UNIXTIME(:pubEnd), title=:title, summary=:summary, content=:content, author=:author WHERE id = :id";
$st = $conn->prepare ( $sql );
$st->bindValue( ":creationDate", $this->creationDate, PDO::PARAM_INT );
$st->bindValue( ":pubStart", $this->pubStart, PDO::PARAM_INT );
$st->bindValue( ":pubEnd", $this->pubEnd, PDO::PARAM_INT );

... More code not included here



And, as I mentioned in my first post, the creationDate transfers just fine between mysql and editArticle.php. The creationDate a hidden field on the editArticle form entered as



<?php @ include ("<?php date('Y-m-d'); ?>"); ?>


So if I am entering the FROM_UNIXTIME as I have indicated above, and if this is the correct way to code the dates, then I must have an error in adding and configuring those two new pubStart and pubEnd date fields somewhere in all this.

Sorry to be such a pest. I will work on this more and see if I can get it to work.


Shelley

--
What will we do when the power goes out?
27-Jan-12 00:22
@shelley3: If you insert and retrieve your new fields in exactly the same way as the original publicationDate field then it should work. If it isn't working then there must be a mistake somewhere in your code.

If the dates are being stored in the database OK but retrieved incorrectly then that implies there is a mistake in your getById() and/or getList() methods (which you haven't posted so I can't comment on), or in the way you are converting each date between the object properties and the echo statement in the form template.

Also what is this supposed to do?


<?php @ include ("<?php date('Y-m-d'); ?>"); ?>


include() expects a file path.

Cheers,
Matt

--
Matt Doyle, Elated
3rd Edition of my jQuery Mobile book out now! Learn to build mobile web apps. Free sample chapter: http://store.elated.com/
27-Jan-12 10:05
Hi Matt,

Thanks for your quick response.

Yes, I think I must have an error in the getById() and/or getList() methods as you have suggested because the dates appear correctly in the database. So I will check this code against the tutorial code you provided. (Can't do this 'til the weekend because I'm doing all this on my home local computer & database.)

Regarding the php include statement, that is my error of memory. I didn't use an include statement, it was an echo statement.

Here is what I actually did (from my memory because I don't have access to my code right now):

In the editArticle.php:

<form action="admin.php?action=<?php echo $results['formAction']?>" method="post">
<input type="hidden" name="articleId" value="<?php echo $results['article']->id ?>"/>
<input type="hidden" name="creationDate" value="<?php echo $results['creationDate']->creationDate ?>"/>

// REST OF CODE FOLLOWED



Best regards,
Shelley

--
What will we do when the power goes out?
27-Jan-12 10:09
Addition to my last post:

Oh, and I will also look at the way the dates are converted between the object properties and the echo statement in the form template.


Shelley

--
What will we do when the power goes out?
30-Jan-12 00:14
@shelley3: Your code looks OK, but bear in mind you're storing the creation date in UNIX timestamp format in your hidden field. This may or may not be what you need. I suspect you'd want to use date() to format it in 'Y-m-d' format, like the rest of your date fields.

--
Matt Doyle, Elated
3rd Edition of my jQuery Mobile book out now! Learn to build mobile web apps. Free sample chapter: http://store.elated.com/
01-Feb-12 14:12
I am elated to say that I have fixed my date problem.

The solution was to code the public function storeFormValues ( $params ) correctly. I had previously lumped the extra two date entries into the publicationDate area instead of treating each separately within the function.

Here is the code that is working for me:



public function storeFormValues ( $params ) {

// Store all the parameters
$this->__construct( $params );

// Parse and store the publication (creation) date
if ( isset($params['publicationDate']) ) {
$publicationDate = explode ( '-', $params['publicationDate'] );

if ( count($publicationDate) == 3 ) {
list ( $y, $m, $d ) = $publicationDate;
$this->publicationDate = mktime ( 0, 0, 0, $m, $d, $y );
}
}

// Parse and store the publication start date
if ( isset($params['publicationStart']) ) {
$publicationStart = explode ( '-', $params['publicationStart'] );

if ( count($publicationStart) == 3 ) {
list ( $y, $m, $d ) = $publicationStart;
$this->publicationStart = mktime ( 0, 0, 0, $m, $d, $y );
}
}

// Parse and store the publication end date
if ( isset($params['publicationEnd']) ) {
$publicationEnd = explode ( '-', $params['publicationEnd'] );

if ( count($publicationEnd) == 3 ) {
list ( $y, $m, $d ) = $publicationEnd;
$this->publicationEnd = mktime ( 0, 0, 0, $m, $d, $y );
}
}
}




Thank you, Matt, for all your help with this.

I am now going to work on making it so the article is not viewable to the general audience (I'm thinking these are the listArticle.php, viewArticle.php and homepage.php) until the publicationStart date and that it only appears on the archive.php after the publicationEnd date. Keep your fingers crossed!

Shelley

--
What will we do when the power goes out?
02-Feb-12 23:00
@shelley3: Glad you got it working! Good luck with your next changes. You probably want to limit the articles returned from the database in the call to getList() inside index.php, rather than limiting them in the templates. Similarly, perform the check as to whether to display an article (or not) inside index.php. It's always best to keep functionality out of the template code if possible.

--
Matt Doyle, Elated
3rd Edition of my jQuery Mobile book out now! Learn to build mobile web apps. Free sample chapter: http://store.elated.com/
05-Feb-12 13:41
Thanks, Matt. I'll do that.

shelley

--
What will we do when the power goes out?

 
New posts
Old posts

Follow Elated