Mantis Bugtracker
  

Viewing Issue Simple Details Jump to Notes ] View Advanced ] Issue History ] Print ]
ID Category Severity Reproducibility Date Submitted Last Update
0006012 [Quercus] major always 06-16-16 11:11 06-16-16 11:11
Reporter matthiasblaesing View Status public  
Assigned To
Priority normal Resolution open  
Status new   Product Version 4.0.36
Summary 0006012: [PATCH] Adjust mktime implementation to align with PHP implementation
Description The mktime implementation tries to implement the logic as defined by the reference implementation. This fails for some negative values + spills. The idea of my change: Use a GregorianCalendar from the JDK, in the lentient mode it mimiks mktime better than the current implementation.

------------------ Test.php ------------------
<?php

// Test correct mktime behaviour, it is asumed, that strftime and mktime both
// work in "default" timezone
print "========== Test Spill ========\n";

$tests = array(
    // Testdata: hours, minutes, seconds, month, day, year
    array(22, 21, 1, 4, 21, 2016, "2016-04-21 22:21:01"), // Simple case
    array(30, 0, 0, 4, 21, 2016, "2016-04-22 06:00:00"), // Rollover hour
    array(-1, 0, 0, 4, 21, 2016, "2016-04-20 23:00:00"), // Negative hour
    array(-25, 0, 0, 4, 21, 2016, "2016-04-19 23:00:00"), // Negative hour > 24
    array(2, 67, 0, 4, 21, 2016, "2016-04-21 03:07:00"), // Rollover minute
    array(2, -5, 0, 4, 21, 2016, "2016-04-21 01:55:00"), // Negative minute
    array(2, -125, 0, 4, 21, 2016, "2016-04-20 23:55:00"), // Negative minute > 120
    array(2, 0, 65, 4, 21, 2016, "2016-04-21 02:01:05"), // Rollover second
    array(2, 1, -30, 4, 21, 2016, "2016-04-21 02:00:30"), // Negative minute
    array(2, 1, -150, 4, 21, 2016, "2016-04-21 01:58:30"), // Negative minute > 120
    array(2, 0, 0, 4, 31, 2016, "2016-05-01 02:00:00"), // Rollover day
    array(2, 0, 0, 4, -1, 2016, "2016-03-30 02:00:00"), // Negative day
    array(2, 0, 0, 4, -56, 2016, "2016-02-04 02:00:00"), // Negative day > 30
    array(2, 0, 0, 13, 4, 2016, "2017-01-04 02:00:00"), // Rollover month
    array(2, 0, 0, -1, 4, 2016, "2015-11-04 02:00:00"), // Negative month
    array(2, 0, 0, -13, 4, 2016, "2014-11-04 02:00:00"), // Negative month > 12
    );

foreach($tests as $test) {
    $mktime = mktime($test[0], $test[1], $test[2], $test[3], $test[4], $test[5]);
    $timeString = strftime("%Y-%m-%d %H:%M:%S", $mktime);
    printf("mktime(%d, %d, %d, %d, %d, %d)\t=> Should be: %s -- IS: %s (%s)\n",
            $test[0], $test[1], $test[2], $test[3], $test[4], $test[5],
            $test[6],
            $timeString,
            $timeString == $test[6] ? "OK" : "BROKEN"
            );
}

// gmmktime needs to be tested seperatedly, as strftime can't be used
print "\n========= Test gmmktime ========\n";
// This timestamp is the unixtimestamp for 2016-06-16T17:49:14+00:00: 1466099354
print (gmmktime(17, 49, 14, 6, 16, 2016) == 1466099354 ? 'WORKS' : 'FAILS');
print "\n\n";

------------------ Output for php 7 ------------------
========== Test Spill ========
mktime(22, 21, 1, 4, 21, 2016) => Should be: 2016-04-21 22:21:01 -- IS: 2016-04-21 22:21:01 (OK)
mktime(30, 0, 0, 4, 21, 2016) => Should be: 2016-04-22 06:00:00 -- IS: 2016-04-22 06:00:00 (OK)
mktime(-1, 0, 0, 4, 21, 2016) => Should be: 2016-04-20 23:00:00 -- IS: 2016-04-20 23:00:00 (OK)
mktime(-25, 0, 0, 4, 21, 2016) => Should be: 2016-04-19 23:00:00 -- IS: 2016-04-19 23:00:00 (OK)
mktime(2, 67, 0, 4, 21, 2016) => Should be: 2016-04-21 03:07:00 -- IS: 2016-04-21 03:07:00 (OK)
mktime(2, -5, 0, 4, 21, 2016) => Should be: 2016-04-21 01:55:00 -- IS: 2016-04-21 01:55:00 (OK)
mktime(2, -125, 0, 4, 21, 2016) => Should be: 2016-04-20 23:55:00 -- IS: 2016-04-20 23:55:00 (OK)
mktime(2, 0, 65, 4, 21, 2016) => Should be: 2016-04-21 02:01:05 -- IS: 2016-04-21 02:01:05 (OK)
mktime(2, 1, -30, 4, 21, 2016) => Should be: 2016-04-21 02:00:30 -- IS: 2016-04-21 02:00:30 (OK)
mktime(2, 1, -150, 4, 21, 2016) => Should be: 2016-04-21 01:58:30 -- IS: 2016-04-21 01:58:30 (OK)
mktime(2, 0, 0, 4, 31, 2016) => Should be: 2016-05-01 02:00:00 -- IS: 2016-05-01 02:00:00 (OK)
mktime(2, 0, 0, 4, -1, 2016) => Should be: 2016-03-30 02:00:00 -- IS: 2016-03-30 02:00:00 (OK)
mktime(2, 0, 0, 4, -56, 2016) => Should be: 2016-02-04 02:00:00 -- IS: 2016-02-04 02:00:00 (OK)
mktime(2, 0, 0, 13, 4, 2016) => Should be: 2017-01-04 02:00:00 -- IS: 2017-01-04 02:00:00 (OK)
mktime(2, 0, 0, -1, 4, 2016) => Should be: 2015-11-04 02:00:00 -- IS: 2015-11-04 02:00:00 (OK)
mktime(2, 0, 0, -13, 4, 2016) => Should be: 2014-11-04 02:00:00 -- IS: 2014-11-04 02:00:00 (OK)

========= Test gmmktime ========
WORKS

------------------ Output for quercus with patch ------------------
========== Test Spill ========
mktime(22, 21, 1, 4, 21, 2016) => Should be: 2016-04-21 22:21:01 -- IS: 2016-04-21 22:21:01 (OK)
mktime(30, 0, 0, 4, 21, 2016) => Should be: 2016-04-22 06:00:00 -- IS: 2016-04-22 06:00:00 (OK)
mktime(-1, 0, 0, 4, 21, 2016) => Should be: 2016-04-20 23:00:00 -- IS: 2016-04-20 23:00:00 (OK)
mktime(-25, 0, 0, 4, 21, 2016) => Should be: 2016-04-19 23:00:00 -- IS: 2016-04-19 23:00:00 (OK)
mktime(2, 67, 0, 4, 21, 2016) => Should be: 2016-04-21 03:07:00 -- IS: 2016-04-21 03:07:00 (OK)
mktime(2, -5, 0, 4, 21, 2016) => Should be: 2016-04-21 01:55:00 -- IS: 2016-04-21 01:55:00 (OK)
mktime(2, -125, 0, 4, 21, 2016) => Should be: 2016-04-20 23:55:00 -- IS: 2016-04-20 23:55:00 (OK)
mktime(2, 0, 65, 4, 21, 2016) => Should be: 2016-04-21 02:01:05 -- IS: 2016-04-21 02:01:05 (OK)
mktime(2, 1, -30, 4, 21, 2016) => Should be: 2016-04-21 02:00:30 -- IS: 2016-04-21 02:00:30 (OK)
mktime(2, 1, -150, 4, 21, 2016) => Should be: 2016-04-21 01:58:30 -- IS: 2016-04-21 01:58:30 (OK)
mktime(2, 0, 0, 4, 31, 2016) => Should be: 2016-05-01 02:00:00 -- IS: 2016-05-01 02:00:00 (OK)
mktime(2, 0, 0, 4, -1, 2016) => Should be: 2016-03-30 02:00:00 -- IS: 2016-03-30 02:00:00 (OK)
mktime(2, 0, 0, 4, -56, 2016) => Should be: 2016-02-04 02:00:00 -- IS: 2016-02-04 02:00:00 (OK)
mktime(2, 0, 0, 13, 4, 2016) => Should be: 2017-01-04 02:00:00 -- IS: 2017-01-04 02:00:00 (OK)
mktime(2, 0, 0, -1, 4, 2016) => Should be: 2015-11-04 02:00:00 -- IS: 2015-11-04 02:00:00 (OK)
mktime(2, 0, 0, -13, 4, 2016) => Should be: 2014-11-04 02:00:00 -- IS: 2014-11-04 02:00:00 (OK)

========= Test gmmktime ========
WORKS


------------------ Output for quercus without patch ------------------
========== Test Spill ========
mktime(22, 21, 1, 4, 21, 2016) => Should be: 2016-04-21 22:21:01 -- IS: 2016-04-21 22:21:01 (OK)
mktime(30, 0, 0, 4, 21, 2016) => Should be: 2016-04-22 06:00:00 -- IS: 2016-04-21 06:00:00 (BROKEN)
mktime(-1, 0, 0, 4, 21, 2016) => Should be: 2016-04-20 23:00:00 -- IS: 2016-04-20 23:00:00 (OK)
mktime(-25, 0, 0, 4, 21, 2016) => Should be: 2016-04-19 23:00:00 -- IS: 2016-04-19 23:00:00 (OK)
mktime(2, 67, 0, 4, 21, 2016) => Should be: 2016-04-21 03:07:00 -- IS: 2016-04-21 02:07:00 (BROKEN)
mktime(2, -5, 0, 4, 21, 2016) => Should be: 2016-04-21 01:55:00 -- IS: 2016-04-21 01:55:00 (OK)
mktime(2, -125, 0, 4, 21, 2016) => Should be: 2016-04-20 23:55:00 -- IS: 2016-04-20 23:55:00 (OK)
mktime(2, 0, 65, 4, 21, 2016) => Should be: 2016-04-21 02:01:05 -- IS: 2016-04-21 02:00:05 (BROKEN)
mktime(2, 1, -30, 4, 21, 2016) => Should be: 2016-04-21 02:00:30 -- IS: 2016-04-21 02:00:30 (OK)
mktime(2, 1, -150, 4, 21, 2016) => Should be: 2016-04-21 01:58:30 -- IS: 2016-04-21 01:58:30 (OK)
mktime(2, 0, 0, 4, 31, 2016) => Should be: 2016-05-01 02:00:00 -- IS: 2016-04-01 02:00:00 (BROKEN)
mktime(2, 0, 0, 4, -1, 2016) => Should be: 2016-03-30 02:00:00 -- IS: 2016-03-29 02:00:00 (BROKEN)
mktime(2, 0, 0, 4, -56, 2016) => Should be: 2016-02-04 02:00:00 -- IS: 2016-02-04 02:00:00 (OK)
mktime(2, 0, 0, 13, 4, 2016) => Should be: 2017-01-04 02:00:00 -- IS: 2016-06-04 02:00:00 (BROKEN)
mktime(2, 0, 0, -1, 4, 2016) => Should be: 2015-11-04 02:00:00 -- IS: 2015-11-04 02:00:00 (OK)
mktime(2, 0, 0, -13, 4, 2016) => Should be: 2014-11-04 02:00:00 -- IS: 2014-11-04 02:00:00 (OK)

========= Test gmmktime ========
WORKS



------------------ Patch ------------------
diff --git a/modules/quercus/src/com/caucho/quercus/lib/date/DateModule.java b/modules/quercus/src/com/caucho/quercus/lib/date/DateModule.java
index 21a7ccf..1a78bdf 100644
--- a/modules/quercus/src/com/caucho/quercus/lib/date/DateModule.java
+++ b/modules/quercus/src/com/caucho/quercus/lib/date/DateModule.java
@@ -38,6 +38,8 @@ import com.caucho.quercus.module.AbstractQuercusModule;
 import com.caucho.util.CharBuffer;
 import com.caucho.util.L10N;
 import com.caucho.util.QDate;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -332,18 +334,11 @@ public class DateModule extends AbstractQuercusModule {
                        @Optional() Value dayV,
                        @Optional() Value yearV)
   {
- QDate date = env.getGmtDate();
- long now = env.getCurrentTime();
-
- date.setLocalTime(now);
-
- long gmtNow = date.getGMTTime();
+ GregorianCalendar gc = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
 
- date.setGMTTime(gmtNow);
+ setMktime(gc, hourV, minuteV, secondV, monthV, dayV, yearV);
 
- setMktime(date, hourV, minuteV, secondV, monthV, dayV, yearV);
-
- return date.getGMTTime() / 1000L;
+ return gc.getTimeInMillis() / 1000L;
   }
 
   /**
@@ -907,17 +902,14 @@ public class DateModule extends AbstractQuercusModule {
     if (isDST != -1)
       env.deprecatedArgument("isDST");
 
- long now = env.getCurrentTime();
-
- QDate date = env.getDate();
- date.setGMTTime(now);
+ GregorianCalendar gc = new GregorianCalendar();
 
- setMktime(date, hourV, minuteV, secondV, monthV, dayV, yearV);
+ setMktime(gc, hourV, minuteV, secondV, monthV, dayV, yearV);
 
- return date.getGMTTime() / 1000L;
+ return gc.getTimeInMillis() / 1000L;
   }
 
- private static void setMktime(QDate date,
+ private static void setMktime(Calendar date,
                                 Value hourV,
                                 Value minuteV,
                                 Value secondV,
@@ -925,70 +917,8 @@ public class DateModule extends AbstractQuercusModule {
                                 Value dayV,
                                 Value yearV)
   {
- int yearsToAdd = 0;
- int monthsToAdd = 0;
- int daysToAdd = 0;
-
- int hoursToAdd = 0;
- int minsToAdd = 0;
-
- if (! secondV.isDefault()) {
- int second = secondV.toInt();
-
- if (second < 0) {
- minsToAdd = second / 60 - (second % 60 != 0 ? 1 : 0);
- second = second % 60 + 60;
- }
-
- date.setSecond(second);
- }
-
- if (! minuteV.isDefault()) {
- int minute = minuteV.toInt() + minsToAdd;
-
- if (minute < 0) {
- hoursToAdd = minute / 60 - (minute % 60 != 0 ? 1 : 0);
- minute = minute % 60 + 60;
- }
-
- date.setMinute(minute);
- }
-
- if (! hourV.isDefault()) {
- int hour = hourV.toInt() + hoursToAdd;
-
- if (hour < 0) {
- daysToAdd = hour / 24 - (hour % 24 != 0 ? 1 : 0);
- hour = hour % 24 + 24;
- }
-
- date.setHour(hour);
- }
-
- if (! dayV.isDefault()) {
- int day = dayV.toInt() + daysToAdd;
-
- if (day <= 0) {
- monthsToAdd = day / 30 - 1;
- day = day % 30 + 30;
- }
-
- date.setDayOfMonth(day);
- }
-
- if (! monthV.isDefault()) {
- int month = monthV.toInt() + monthsToAdd;
-
- if (month <= 0) {
- yearsToAdd = month / 12 - 1;
- month = month % 12 + 12;
- }
-
- date.setMonth(month - 1);
- }
-
     if (! yearV.isDefault()) {
- int year = yearV.toInt() + yearsToAdd;
+ int year = yearV.toInt();
 
       if (year >= 1000) {
       }
@@ -1002,8 +932,29 @@ public class DateModule extends AbstractQuercusModule {
         year = 1969;
       }
             
- date.setYear(year);
+ date.set(Calendar.YEAR, year);
+ }
+
+ if (! monthV.isDefault()) {
+ date.set(Calendar.MONTH, monthV.toInt() - 1);
+ }
+
+ if (! dayV.isDefault()) {
+ date.set(Calendar.DAY_OF_MONTH, dayV.toInt());
+ }
+
+ if (! hourV.isDefault()) {
+ date.set(Calendar.HOUR_OF_DAY, hourV.toInt());
     }
+
+ if (! minuteV.isDefault()) {
+ date.set(Calendar.MINUTE, minuteV.toInt());
+ }
+
+ if (! secondV.isDefault()) {
+ date.set(Calendar.SECOND, secondV.toInt());
+ }
+
   }
 
   /**
Additional Information
Attached Files

- Relationships

There are no notes attached to this issue.

- Issue History
Date Modified Username Field Change
06-16-16 11:11 matthiasblaesing New Issue


Mantis 1.0.0rc3[^]
Copyright © 2000 - 2005 Mantis Group
26 total queries executed.
24 unique queries executed.
Powered by Mantis Bugtracker