Mantis Bugtracker
  

Viewing Issue Advanced Details Jump to Notes ] View Simple ] 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 Platform
Status new   OS
Projection none   OS Version
ETA none Fixed in Version Product Version 4.0.36
  Product Build
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());
+ }
+
   }
 
   /**
Steps To Reproduce
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