diff --git a/src/main/java/com/caucho/quercus/lib/date/DateModule.java b/src/main/java/com/caucho/quercus/lib/date/DateModule.java --- a/src/main/java/com/caucho/quercus/lib/date/DateModule.java +++ b/src/main/java/com/caucho/quercus/lib/date/DateModule.java @@ -1329,4 +1329,27 @@ } + /** + * Implements the timezone_transitions_get function for + * WordPress to work. + * + * @param dateTimeZone {@link DateTimeZone} object + * @param timestampBegin optional begin timestamp (currently ignored) + * @param timestampEnd optional end timestamp (currently ignored) + * @return numerically indexed array containing an associative array of the + * next transition, or null on failure + * @author Kaz Nishimura + */ + @ReturnNullAsFalse + public static ArrayValue timezone_transitions_get(DateTimeZone dateTimeZone, + @Optional int timestampBegin, + @Optional int timestampEnd) + { + if (dateTimeZone == null) { + return null; + } + + return dateTimeZone.getTransitions(timestampBegin, timestampEnd); + } + static { addConstant(_constMap, "DATE_ATOM", DateTime.ATOM); @@ -1348,10 +1371,4 @@ return _constMap; } - /* commented out for wordpress-2.8.1 - public static Value timezone_transitions_get(DateTimeZone dateTimeZone) - { - return dateTimeZone.getTransitions(); - } - */ } diff --git a/src/main/java/com/caucho/quercus/lib/date/DateTimeZone.java b/src/main/java/com/caucho/quercus/lib/date/DateTimeZone.java --- a/src/main/java/com/caucho/quercus/lib/date/DateTimeZone.java +++ b/src/main/java/com/caucho/quercus/lib/date/DateTimeZone.java @@ -30,7 +30,12 @@ package com.caucho.quercus.lib.date; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.Locale; import java.util.TimeZone; +import com.caucho.quercus.annotation.Optional; +import com.caucho.quercus.annotation.ReturnNullAsFalse; import com.caucho.quercus.env.ArrayValue; import com.caucho.quercus.env.ArrayValueImpl; @@ -148,11 +153,65 @@ } - /* commented out for wordpress-2.8.1 - public Value getTransitions(@Optional int timestampBegin, - @Optional int timestampEnd) + /** + * Implements the DateTimeZone::getTransitions function for + * WordPress to work. + * + * @param timestampBegin optional begin timestamp (currently ignored) + * @param timestampEnd optional end timestamp (currently ignored) + * @return numerically indexed array containing an associative array of the + * next transition, or null on failure + * @author Kaz Nishimura + */ + @ReturnNullAsFalse + public ArrayValue getTransitions(@Optional int timestampBegin, + @Optional int timestampEnd) { - throw new UnimplementedException("DateTimeZone->getTransitions()"); + // TODO: Handle timestampBegin and timestampEnd. + ArrayValue array = new ArrayValueImpl(); + if (_timeZone.observesDaylightTime()) { + // TODO: Find all past transitions. + Date now = new Date(); + boolean isDST = _timeZone.inDaylightTime(now); + // TODO: Implement a better method. + final long DAY = 86400 * 1000L; + final long MINUTE = 60 * 1000L; + // Rounds down to days. + long time = now.getTime() / DAY * DAY; + long limit = time + 365 * DAY; + Date date = now; + while (time <= limit) { + time += DAY; + date = new Date(time); + if (_timeZone.inDaylightTime(date) != isDST) { + // Goes back one day. + time -= DAY; + break; + } + } + if (time <= limit) { + final DateFormat ISO8601_FORMAT + = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", + Locale.ROOT); + // Assumes transitions occur at zero seconds. + for (;;) { + time += MINUTE; + date = new Date(time); + if (_timeZone.inDaylightTime(date) != isDST) { + break; + } + } + isDST = _timeZone.inDaylightTime(date); + ArrayValue transition = new ArrayValueImpl(); + transition.put("ts", time / 1000); + transition.put("time", ISO8601_FORMAT.format(date)); + transition.put("offset", _timeZone.getOffset(time) / 1000); + transition.put("isdst", isDST ? "1" : ""); + transition.put("abbr", _timeZone.getDisplayName(isDST, + TimeZone.SHORT)); + array.put(transition); + } + } + return array; } - */ protected TimeZone getTimeZone()