Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ language: java
jdk:
- openjdk11
- oraclejdk9
- oraclejdk8
#- oraclejdk8

services:
- mongodb
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
import java.time.LocalDateTime;
import java.time.Year;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.TextStyle;
import java.time.temporal.IsoFields;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

Expand Down Expand Up @@ -115,7 +119,7 @@ public static Memory date_default_timezone_get(Environment env, TraceInfo traceI

public static Memory mktime(Environment env, TraceInfo traceInfo,
int hour, int minute, int second, int month, int day, int year) {
return __mktime(zoneId(date_default_timezone_get(env, traceInfo)), hour, minute, second,
return __mktime(zoneId(env, traceInfo), hour, minute, second,
month, day, year);
}

Expand Down Expand Up @@ -144,6 +148,10 @@ private static ZoneId zoneId(Memory memory) {
return ZoneIdFactory.of(memory.toString());
}

private static ZoneId zoneId(Environment env, TraceInfo traceInfo) {
return zoneId(date_default_timezone_get(env, traceInfo));
}

public static Memory mktime(Environment env, TraceInfo traceInfo,
int hour, int minute, int second, int month, int day) {
return mktime(env, traceInfo, hour, minute, second, month, day, Year.now().getValue());
Expand Down Expand Up @@ -219,7 +227,7 @@ public static Memory gmmktime(Environment env, TraceInfo traceInfo) {
}

public static Memory localtime(Environment env, TraceInfo traceInfo, long time, boolean isAssociative) {
ZoneId zone = zoneId(date_default_timezone_get(env, traceInfo));
ZoneId zone = zoneId(env, traceInfo);

Instant instant = Instant.ofEpochSecond(time);
ZonedDateTime dateTime = instant.atZone(zone);
Expand Down Expand Up @@ -262,6 +270,228 @@ public static Memory time() {
return LongMemory.valueOf(epochSeconds());
}

public static Memory strftime(Environment env, TraceInfo traceInfo, String format) {
return strftime(env, traceInfo, format, epochSeconds());
}

public static Memory strftime(Environment env, TraceInfo traceInfo, String format, long time) {
if (format.isEmpty())
return Memory.FALSE;

StringBuilder buff = strftimeImpl(zonedDateTime(env, traceInfo, time), env.getLocale(), format, new StringBuilder());

return StringMemory.valueOf(buff.toString());
}

private static StringBuilder strftimeImpl(ZonedDateTime date, Locale l, String format, StringBuilder buff) {
for (int i = 0, n = format.length(); i < n; i++) {
char c = format.charAt(i);

if (c == '%' && ++i < n) {
c = format.charAt(i);

switch (c) {
// Days
case 'a': {
buff.append(date.getDayOfWeek().getDisplayName(TextStyle.SHORT, l));
break;
}
case 'A': {
buff.append(date.getDayOfWeek().getDisplayName(TextStyle.FULL, l));
break;
}
case 'd': {
buff.append(String.format(l, TWO_DIGIT_INT, date.getDayOfMonth()));
break;
}
case 'e': {
int dayOfMonth = date.getDayOfMonth();
if (dayOfMonth < 10)
buff.append(' ');

buff.append(dayOfMonth);
break;
}
case 'j': {
buff.append(String.format(l, "%03d", date.getDayOfYear()));
break;
}
case 'u':
case 'w': {
buff.append(date.getDayOfWeek().getValue());
break;
}
// Week
case 'W':
case 'U': {
int week = date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
buff.append(--week);
break;
}
case 'V': {
buff.append(String.format(l, TWO_DIGIT_INT, date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR)));
break;
}
// Month
case 'h':
case 'b': {
buff.append(date.getMonth().getDisplayName(TextStyle.SHORT, l));
break;
}
case 'B': {
buff.append(date.getMonth().getDisplayName(TextStyle.FULL, l));
break;
}
case 'm': {
buff.append(String.format(l, TWO_DIGIT_INT, date.getMonth().getValue()));
break;
}
// Year
case 'C': {
buff.append(date.getYear() / 100);
break;
}
case 'y':
case 'g': {
buff.append(String.format(l, TWO_DIGIT_INT, date.getYear() % 100));
break;
}
case 'G':
case 'Y': {
buff.append(String.format(l, "%04d", date.getYear()));
break;
}
// Time
case 'H': {
buff.append(String.format(l, TWO_DIGIT_INT, date.getHour()));
break;
}
case 'k': {
buff.append(String.format(l, "% 4d", date.getHour()));
break;
}
case 'I': {
int hRem = date.getHour() % 12;
buff.append(String.format(l, TWO_DIGIT_INT, hRem > 0 ? hRem : 12));
break;
}
case 'L': {
int hRem = date.getHour() % 12;
buff.append(String.format(l, "% 2d", hRem > 0 ? hRem : 12));
break;
}
case 'M': {
buff.append(String.format(l, TWO_DIGIT_INT, date.getMinute()));
break;
}
case 'p': {
buff.append(date.getHour() >= 12 ? "PM" : "AM");
break;
}
case 'P': {
buff.append(date.getHour() >= 12 ? "pm" : "am");
break;
}
case 'r': {
strftimeImpl(date, l, "%I:%M:%S %p", buff);
break;
}
case 'R': {
strftimeImpl(date, l, "%H:%M", buff);
break;
}
case 'S': {
buff.append(String.format(l, TWO_DIGIT_INT, date.getSecond()));
break;
}
case 'X':
case 'T': {
strftimeImpl(date, l, "%H:%M:%S", buff);
break;
}
case 'z': {
long hours = Duration.ofSeconds(date.getOffset().getTotalSeconds()).toHours();
String offset = ((hours < 0) ? "-" : "+") + String.format(l, "%02d00", Math.abs(hours));
buff.append(offset);
break;
}
case 'Z': {
ZoneId zone = date.getZone();
if (zone instanceof ZoneOffset) {
buff.append("GMT");
strftimeImpl(date, l, "%z", buff);
} else {
String str = ZoneIdFactory.aliasFor(date);
if (str == null) {
long hours = Duration.ofSeconds(date.getOffset().getTotalSeconds()).toHours();
buff.append(hours < 0 ? '-' : '+')
.append(String.format(l, TWO_DIGIT_INT, Math.abs(hours)));
} else {
buff.append(str);
}
}
break;
}
// Timestamps
case 'c': {
strftimeImpl(date, l, "%a %b %e %H:%M:%S %Y", buff);
break;
}
case 'x':
case 'D': {
strftimeImpl(date, l, "%m/%d/%y", buff);
break;
}
case 'F': {
strftimeImpl(date, l, "%Y-%m-%d", buff);
break;
}
case 's': {
buff.append(date.toEpochSecond());
break;
}
case 'n': {
buff.append('\n');
break;
}
case 't': {
buff.append('\t');
break;
}
case '%': {
buff.append(c);
break;
}
default: {
buff.append('%').append(c);
break;
}
}
} else {
buff.append(c);
}
}

return buff;
}

public static Memory gmstrftime(Environment env, TraceInfo traceInfo, String format, long time) {
if (format.isEmpty())
return Memory.FALSE;

StringBuilder buff = strftimeImpl(Instant.ofEpochSecond(time).atZone(ZONE_GMT), env.getLocale(), format, new StringBuilder());

return StringMemory.valueOf(buff.toString());
}

public static Memory gmstrftime(Environment env, TraceInfo traceInfo, String format) {
return gmstrftime(env, traceInfo, format, epochSeconds());
}

private static ZonedDateTime zonedDateTime(Environment env, TraceInfo traceInfo, long time) {
return Instant.ofEpochSecond(time).atZone(zoneId(env, traceInfo));
}

private static long epochSeconds() {
return System.currentTimeMillis() / 1000;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,54 @@ public void testMkTime() {
public void testTime() {
check("ext/date/time_basic.phpt");
}

@Test
public void testStrftime() {
check("ext/date/strftime/strftime_basic.phpt");
check("ext/date/strftime/strftime_variation3.phpt");
check("ext/date/strftime/strftime_variation4.phpt");
check("ext/date/strftime/strftime_variation5.phpt");
check("ext/date/strftime/strftime_variation6.phpt");
check("ext/date/strftime/strftime_variation7.phpt");
check("ext/date/strftime/strftime_variation8.phpt");
check("ext/date/strftime/strftime_variation9.phpt");
check("ext/date/strftime/strftime_variation10.phpt");
check("ext/date/strftime/strftime_variation11.phpt");
check("ext/date/strftime/strftime_variation12.phpt");
check("ext/date/strftime/strftime_variation13.phpt");
check("ext/date/strftime/strftime_variation14.phpt");
check("ext/date/strftime/strftime_variation15.phpt");
check("ext/date/strftime/strftime_variation16.phpt");
check("ext/date/strftime/strftime_variation17.phpt");
check("ext/date/strftime/strftime_variation18.phpt");
check("ext/date/strftime/strftime_variation19.phpt");
check("ext/date/strftime/strftime_variation20.phpt");
check("ext/date/strftime/strftime_variation21.phpt");
check("ext/date/strftime/strftime_variation22.phpt");
}

@Test
public void testGmStrftime() {
check("ext/date/strftime/gmstrftime_basic.phpt");
check("ext/date/strftime/gmstrftime_variation3.phpt");
check("ext/date/strftime/gmstrftime_variation4.phpt");
check("ext/date/strftime/gmstrftime_variation5.phpt");
check("ext/date/strftime/gmstrftime_variation6.phpt");
check("ext/date/strftime/gmstrftime_variation7.phpt");
check("ext/date/strftime/gmstrftime_variation8.phpt");
check("ext/date/strftime/gmstrftime_variation9.phpt");
check("ext/date/strftime/gmstrftime_variation10.phpt");
check("ext/date/strftime/gmstrftime_variation11.phpt");
check("ext/date/strftime/gmstrftime_variation12.phpt");
check("ext/date/strftime/gmstrftime_variation13.phpt");
check("ext/date/strftime/gmstrftime_variation14.phpt");
check("ext/date/strftime/gmstrftime_variation15.phpt");
check("ext/date/strftime/gmstrftime_variation16.phpt");
check("ext/date/strftime/gmstrftime_variation17.phpt");
check("ext/date/strftime/gmstrftime_variation18.phpt");
check("ext/date/strftime/gmstrftime_variation19.phpt");
check("ext/date/strftime/gmstrftime_variation20.phpt");
check("ext/date/strftime/gmstrftime_variation21.phpt");
check("ext/date/strftime/gmstrftime_variation22.phpt");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--TEST--
Test gmstrftime() function : basic functionality
--FILE--
<?php
/* Prototype : string gmstrftime(string format [, int timestamp])
* Description: Format a GMT/UCT time/date according to locale settings
* Source code: ext/date/php_date.c
* Alias to functions:
*/

echo "*** Testing gmstrftime() : basic functionality ***\n";

// Initialise all required variables
$format = '%b %d %Y %H:%M:%S';
$timestamp = gmmktime(8, 8, 8, 8, 8, 2008);

// Calling gmstrftime() with all possible arguments
var_dump( gmstrftime($format, $timestamp) );

// Calling gmstrftime() with mandatory arguments
var_dump( gmstrftime($format) );

?>
===DONE===
--EXPECTF--
*** Testing gmstrftime() : basic functionality ***
string(20) "Aug 08 2008 08:08:08"
string(%d) "%s %02d %d %02d:%02d:%02d"
===DONE===
Loading