简体   繁体   English

夏令时的PHP日期问题

[英]PHP date issues with daylight saving

I've got a very strange bug cropping up in some PHP code I've got. 我在一些PHP代码中出现了一个非常奇怪的错误。 The page is managing student enrolments in courses. 该页面正在管理课程中的学生注册。 On the page is a table of the student's courses, and each row has a number of dates: when they enrolled, when they completed, when they passed the assessment and when they picked up their certificate. 页面上是学生课程的表格,每一行都有很多日期:他们注册的时间,完成的时间,通过评估的时间以及获得证书的时间。

The table data is generated by PHP (drawing the data from the DB), and Javascript actually renders the table. 该表数据是由PHP生成的(从DB中绘制数据),而Javascript实际上是对该表的呈现。 The output from PHP is JS code which looks something like this: PHP的输出是JS代码,看起来像这样:

var e = new Enrolment();
e.contactId = 5801;
e.enrolId = 14834;
e.courseId = 3;
e.dateEnrolled = new Date(1219672800000);
e.dateCompleted = new Date(-1000);  // magic value meaning they haven't completed.
e.resultDate = new Date(1223647200000);
e.certDate = new Date(1223560800000);
e.result = 95;
e.passed = true;
enrolments[14834] = e;

In the database, all the date fields are stored as DATE (not DATETIME ) fields. 在数据库中,所有日期字段都存储为DATE (不是DATETIME )字段。

The bug is that the dates are being displayed as one day off. 错误是日期显示为一天休息。 I would suspect that this has a lot to do with the server being in an area which has daylight saving, whereas here there isn't any (meaning the server time is one hour off). 我怀疑这与服务器位于具有夏令时的区域有很大关系,而这里没有任何东西(这意味着服务器时间减少了一个小时)。 This explains a lot, especially how the data preparation and rendering is being done in two different timezones. 这解释了很多,尤其是如何在两个不同的时区中完成数据准备和呈现。 That is: the server is saying to the client that the person completed at midnight on the 15th August, and the client is interpreting that as 11pm on the 14th and therefore displaying 14th August. 也就是说:服务器正在向客户说该人在8月15日午夜完成工作,而客户则将其解释为14日的11pm,因此显示8月14日。

But here's the confusing part: it's only doing that for the resultDate and certDate fields! 但这是令人困惑的部分:它仅对resultDate和certDate字段执行此操作! I've copied the data to my local server and have found that the production server is actually sending a different timestamp (one which is off by 1 hour) just for those two fields, whereas the dateEnrolled field is the same. 我已将数据复制到本地服务器,发现生产服务器实际上仅针对这两个字段发送了不同的时间戳记(一个时间戳记会减少1小时),而dateEnrolled字段却是相同的。

Here's the output using the exact same code and data from the database: 以下是使用与数据库完全相同的代码和数据的输出:

// local server (timezone GMT+1000)
e.dateEnrolled = new Date(1219672800000);   // 26 Aug 2008 00:00 +10:00
e.dateCompleted = new Date(-1000);
e.resultDate = new Date(1223647200000);     // 11 Oct 2008 00:00 +10:00
e.certDate = new Date(1223560800000);       // 10 Oct 2008 00:00 +10:00

// production server (timezone GMT+1100)
e.dateEnrolled = new Date(1219672800000);   // 26 Aug 2008 00:00 +10:00
e.dateCompleted = new Date(-1000);
e.resultDate = new Date(1223643600000);     // 10 Oct 2008 23:00 +10:00 **
e.certDate = new Date(1223557200000);       // 09 Oct 2008 23:00 +10:00 **

I can understand if this was a problem with Daylight Saving not being accounted for, but notice how the dateEnrolled is the same? 我可以理解这是否是由于不考虑夏令时的问题,但是请注意dateEnrolled的方式是一样的吗?

The PHP code which converts the MySQL date to a unix timestamp is this: 将MySQL日期转换为unix时间戳的PHP代码是这样的:

list ($year, $month, $day) = explode ('-', $mysqlDT);
$timestamp = mktime (0,0,0, $month, $day, $year);

Any ideas about how to fix this? 关于如何解决此问题的任何想法?

Thats because you use mktime which is locale specific. 那是因为您使用的是特定于语言环境的mktime。 That is it will convert it to the number of seconds from 00:00:00 1970-1-1 GMT, and that is offset by 1 hour with one timezone. 也就是说,将其转换成秒数从1970-1-1 00:00:00 GMT,并且由1小时,一个时区偏移。

You should also remember that the javascript does use the same timezone as the browser, not the web page. 您还应该记住,JavaScript确实使用与浏览器相同的时区,而不使用网页。

e.resultDate = new Date(year, month - 1, day);

This will make sure the date is the same for every viewer from every timezone. 这样可以确保每个时区的每个观看者的日期都相同。

Or you can use gmmktime and use the UTC methods in Date. 或者,您可以使用gmmktime并在Date中使用UTC方法。

Ok, I just figured out why it's mucking up one date but not the other. 好的,我只是想出了为什么要取消一个日期而不是另一个日期。 Daylight savings wasn't in effect in August. 夏令时在8月没有生效。 facepalm 面容

  1. always store dates/datetimes in GMT/UTC 始终将日期/日期时间存储在GMT / UTC中
  2. take a good look at the query that retrieves these values, anything different about the ones being adjusted? 仔细查看检索这些值的查询,与要调整的值有何不同?
  3. if not, are they all timestamp or date or datetime? 如果不是,它们都是时间戳记还是日期或日期时间?

It is mosly likely to be day light saving issue. 这很可能是日光节约的问题。 The reason why it doing it only for resultDate and certDate is that dateEnrolled is in August, daylight saving normally begins/ends in late September or early October. 它仅对resultDate和certDate执行此操作的原因是dateEnrolled是在8月,夏令时通常在9月下旬或10月初开始/结束。

使用apache.conf,.htaccess或ini_set()将date.timezone ini设置设置为应用程序的时区。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM