I recently had a problem where our client has a list of events (implemented as a simple Drupal view) and the start/end date fields of the content show properly on the list view but incorrectly on the custom node template we use to display the full node of that event.
For example, there would be a course happening on Feb 3rd. It would show up as such on the View but it would show as Feb 4th on the custom drill down page.
This custom drill down page is something that a team member created as a view but used a Global PHP field in order to accomplish some specific logic on how to display some other data associated with the date rather than a "date" field. Because they used the Global PHP, it didn't behave the same way as the out-of-the-box date field would in a view.
What's worse, is that it only happened for some nodes, and not all of them.
I ended up realizing the following:
When you use date fields out of the box in a Drupal view, you don't have to worry about taking into account the time difference between the server's timezone and the timezone associated with the date field. Drupal takes care of that for you.
The culprit nodes were all created somewhat close to midnight so they were treated as Feb 3rd by the list view but Feb 4th by the custom code because there was no reconcilement of the timezones.
You need to specify the timezone of the database when converting the string to time, and then use the timezone of the field when running the date_format function. See below:
(To understand the importance of the parameters, you can refer to the Drupal API here)
$date_converted = strtotime($date['value'].' '.$date['timezone_db']);
print format_date($date_converted, 'custom', 'j M Y', $date['timezone']);
Through the use of the API page and a wonderful StackExchange article, I was able to reason this out and solve the discrepancy.