You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2018/03/21 16:48:40 UTC
[1/7] groovy git commit: move datetime extensions to their own module
Repository: groovy
Updated Branches:
refs/heads/master 4abc75487 -> b3c6f0ebd
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-dateutil/src/main/java/org/apache/groovy/dateutil/extensions/DateUtilExtensions.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-dateutil/src/main/java/org/apache/groovy/dateutil/extensions/DateUtilExtensions.java b/subprojects/groovy-dateutil/src/main/java/org/apache/groovy/dateutil/extensions/DateUtilExtensions.java
new file mode 100644
index 0000000..19cf6dd
--- /dev/null
+++ b/subprojects/groovy-dateutil/src/main/java/org/apache/groovy/dateutil/extensions/DateUtilExtensions.java
@@ -0,0 +1,778 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.dateutil.extensions;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyRuntimeException;
+import org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport;
+
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+/**
+ * This class defines new groovy methods which appear on normal JDK
+ * Date and Calendar classes inside the Groovy environment.
+ */
+public class DateUtilExtensions extends DefaultGroovyMethodsSupport {
+
+ /**
+ * Support the subscript operator for a Date.
+ *
+ * @param self a Date
+ * @param field a Calendar field, e.g. MONTH
+ * @return the value for the given field, e.g. FEBRUARY
+ * @see java.util.Calendar
+ * @since 1.5.5
+ */
+ public static int getAt(Date self, int field) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(self);
+ return cal.get(field);
+ }
+
+ /**
+ * Convert a Date to a Calendar.
+ *
+ * @param self a Date
+ * @return a Calendar corresponding to the given Date
+ * @since 1.7.6
+ */
+ public static Calendar toCalendar(Date self) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(self);
+ return cal;
+ }
+
+ /**
+ * Support the subscript operator for a Calendar.
+ *
+ * @param self a Calendar
+ * @param field a Calendar field, e.g. MONTH
+ * @return the value for the given field, e.g. FEBRUARY
+ * @see java.util.Calendar
+ * @since 1.7.3
+ */
+ public static int getAt(Calendar self, int field) {
+ return self.get(field);
+ }
+
+ /**
+ * Support the subscript operator for mutating a Calendar.
+ * Example usage:
+ * <pre>
+ * import static java.util.Calendar.*
+ * def cal = Calendar.instance
+ * cal[DAY_OF_WEEK] = MONDAY
+ * cal[MONTH] = MARCH
+ * println cal.time // A Monday in March
+ * </pre>
+ *
+ * @param self A Calendar
+ * @param field A Calendar field, e.g. MONTH
+ * @param value The value for the given field, e.g. FEBRUARY
+ * @see java.util.Calendar#set(int, int)
+ * @since 1.7.3
+ */
+ public static void putAt(Calendar self, int field, int value) {
+ self.set(field, value);
+ }
+
+ /**
+ * Support the subscript operator for mutating a Date.
+ *
+ * @param self A Date
+ * @param field A Calendar field, e.g. MONTH
+ * @param value The value for the given field, e.g. FEBRUARY
+ * @see #putAt(java.util.Calendar, int, int)
+ * @see java.util.Calendar#set(int, int)
+ * @since 1.7.3
+ */
+ public static void putAt(Date self, int field, int value) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(self);
+ putAt(cal, field, value);
+ self.setTime(cal.getTimeInMillis());
+ }
+
+ /**
+ * Support mutating a Calendar with a Map.
+ * <p>
+ * The map values are the normal values provided as the
+ * second parameter to <code>java.util.Calendar#set(int, int)</code>.
+ * The keys can either be the normal fields values provided as
+ * the first parameter to that method or one of the following Strings:
+ * <table border="1" cellpadding="4">
+ * <caption>Calendar index values</caption>
+ * <tr><td>year</td><td>Calendar.YEAR</td></tr>
+ * <tr><td>month</td><td>Calendar.MONTH</td></tr>
+ * <tr><td>date</td><td>Calendar.DATE</td></tr>
+ * <tr><td>dayOfMonth</td><td>Calendar.DATE</td></tr>
+ * <tr><td>hourOfDay</td><td>Calendar.HOUR_OF_DAY</td></tr>
+ * <tr><td>minute</td><td>Calendar.MINUTE</td></tr>
+ * <tr><td>second</td><td>Calendar.SECOND</td></tr>
+ * </table>
+ * Example usage:
+ * <pre>
+ * import static java.util.Calendar.*
+ * def cal = Calendar.instance
+ * def m = [:]
+ * m[YEAR] = 2010
+ * m[MONTH] = DECEMBER
+ * m[DATE] = 25
+ * cal.set(m)
+ * println cal.time // Christmas 2010
+ *
+ * cal.set(year:2011, month:DECEMBER, date:25)
+ * println cal.time // Christmas 2010
+ * </pre>
+ *
+ * @param self A Calendar
+ * @param updates A Map of Calendar keys and values
+ * @see java.util.Calendar#set(int, int)
+ * @see java.util.Calendar#set(int, int, int, int, int, int)
+ * @since 1.7.3
+ */
+ public static void set(Calendar self, Map<Object, Integer> updates) {
+ for (Map.Entry<Object, Integer> entry : updates.entrySet()) {
+ Object key = entry.getKey();
+ if (key instanceof String) key = CAL_MAP.get(key);
+ if (key instanceof Integer) self.set((Integer) key, entry.getValue());
+ }
+ }
+
+ /**
+ * Legacy alias for copyWith. Will be deprecated and removed in future versions of Groovy.
+ *
+ * @see #copyWith(java.util.Calendar, java.util.Map)
+ * @since 1.7.3
+ */
+ public static Calendar updated(Calendar self, Map<Object, Integer> updates) {
+ Calendar result = (Calendar) self.clone();
+ set(result, updates);
+ return result;
+ }
+
+ /**
+ * Support creating a new Date having similar properties to
+ * an existing Date (which remains unaltered) but with
+ * some fields updated according to a Map of changes.
+ * <p>
+ * Example usage:
+ * <pre>
+ * import static java.util.Calendar.YEAR
+ * def now = Calendar.instance
+ * def nextYear = now[YEAR] + 1
+ * def oneYearFromNow = now.copyWith(year: nextYear)
+ * println now.time
+ * println oneYearFromNow.time
+ * </pre>
+ *
+ * @param self A Calendar
+ * @param updates A Map of Calendar keys and values
+ * @return The newly created Calendar
+ * @see java.util.Calendar#set(int, int)
+ * @see java.util.Calendar#set(int, int, int, int, int, int)
+ * @see #set(java.util.Calendar, java.util.Map)
+ * @since 2.2.0
+ */
+ public static Calendar copyWith(Calendar self, Map<Object, Integer> updates) {
+ Calendar result = (Calendar) self.clone();
+ set(result, updates);
+ return result;
+ }
+
+ /**
+ * Support mutating a Date with a Map.
+ * <p>
+ * The map values are the normal values provided as the
+ * second parameter to <code>java.util.Calendar#set(int, int)</code>.
+ * The keys can either be the normal fields values provided as
+ * the first parameter to that method or one of the following Strings:
+ * <table border="1" cellpadding="4">
+ * <caption>Calendar index values</caption>
+ * <tr><td>year</td><td>Calendar.YEAR</td></tr>
+ * <tr><td>month</td><td>Calendar.MONTH</td></tr>
+ * <tr><td>date</td><td>Calendar.DATE</td></tr>
+ * <tr><td>dayOfMonth</td><td>Calendar.DATE</td></tr>
+ * <tr><td>hourOfDay</td><td>Calendar.HOUR_OF_DAY</td></tr>
+ * <tr><td>minute</td><td>Calendar.MINUTE</td></tr>
+ * <tr><td>second</td><td>Calendar.SECOND</td></tr>
+ * </table>
+ * Example usage:
+ * <pre>
+ * import static java.util.Calendar.YEAR
+ * def date = new Date()
+ * def nextYear = date[YEAR] + 1
+ * date.set(year: nextYear)
+ * println date
+ * </pre>
+ *
+ * @param self A Date
+ * @param updates A Map of Calendar keys and values
+ * @see java.util.Calendar#set(int, int)
+ * @see #set(java.util.Calendar, java.util.Map)
+ * @since 1.7.3
+ */
+ public static void set(Date self, Map<Object, Integer> updates) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(self);
+ set(cal, updates);
+ self.setTime(cal.getTimeInMillis());
+ }
+
+ /**
+ * Legacy alias for copyWith. Will be deprecated and removed in future versions of Groovy.
+ *
+ * @see #copyWith(java.util.Date, java.util.Map)
+ * @since 1.7.3
+ */
+ public static Date updated(Date self, Map<Object, Integer> updates) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(self);
+ set(cal, updates);
+ return cal.getTime();
+ }
+
+ /**
+ * Support creating a new Date having similar properties to
+ * an existing Date (which remains unaltered) but with
+ * some fields updated according to a Map of changes.
+ * <p>
+ * Example usage:
+ * <pre>
+ * import static java.util.Calendar.YEAR
+ * def today = new Date()
+ * def nextYear = today[YEAR] + 1
+ * def oneYearFromNow = today.copyWith(year: nextYear)
+ * println today
+ * println oneYearFromNow
+ * </pre>
+ *
+ * @param self A Date
+ * @param updates A Map of Calendar keys and values
+ * @return The newly created Date
+ * @see java.util.Calendar#set(int, int)
+ * @see #set(java.util.Date, java.util.Map)
+ * @see #copyWith(java.util.Calendar, java.util.Map)
+ * @since 2.2.0
+ */
+ public static Date copyWith(Date self, Map<Object, Integer> updates) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(self);
+ set(cal, updates);
+ return cal.getTime();
+ }
+
+ private static final Map<String, Integer> CAL_MAP = new HashMap<String, Integer>();
+
+ static {
+ CAL_MAP.put("year", Calendar.YEAR);
+ CAL_MAP.put("month", Calendar.MONTH);
+ CAL_MAP.put("date", Calendar.DATE);
+ CAL_MAP.put("dayOfMonth", Calendar.DATE);
+ CAL_MAP.put("hourOfDay", Calendar.HOUR_OF_DAY);
+ CAL_MAP.put("minute", Calendar.MINUTE);
+ CAL_MAP.put("second", Calendar.SECOND);
+ }
+
+ /**
+ * Increment a Date by one day.
+ *
+ * @param self a Date
+ * @return the next days date
+ * @since 1.0
+ */
+ public static Date next(Date self) {
+ return plus(self, 1);
+ }
+
+ /**
+ * Increment a Calendar by one day.
+ *
+ * @param self a Calendar
+ * @return a new Calendar set to the next day
+ * @since 1.8.7
+ */
+ public static Calendar next(Calendar self) {
+ Calendar result = (Calendar) self.clone();
+ result.add(Calendar.DATE, 1);
+ return result;
+ }
+
+ /**
+ * Decrement a Calendar by one day.
+ *
+ * @param self a Calendar
+ * @return a new Calendar set to the previous day
+ * @since 1.8.7
+ */
+ public static Calendar previous(Calendar self) {
+ Calendar result = (Calendar) self.clone();
+ result.add(Calendar.DATE, -1);
+ return result;
+ }
+
+ /**
+ * Increment a java.sql.Date by one day.
+ *
+ * @param self a java.sql.Date
+ * @return the next days date
+ * @since 1.0
+ */
+ public static java.sql.Date next(java.sql.Date self) {
+ return new java.sql.Date(next((Date) self).getTime());
+ }
+
+ /**
+ * Decrement a Date by one day.
+ *
+ * @param self a Date
+ * @return the previous days date
+ * @since 1.0
+ */
+ public static Date previous(Date self) {
+ return minus(self, 1);
+ }
+
+ /**
+ * Decrement a java.sql.Date by one day.
+ *
+ * @param self a java.sql.Date
+ * @return the previous days date
+ * @since 1.0
+ */
+ public static java.sql.Date previous(java.sql.Date self) {
+ return new java.sql.Date(previous((Date) self).getTime());
+ }
+
+ /**
+ * Add a number of days to this date and returns the new date.
+ *
+ * @param self a Date
+ * @param days the number of days to increase
+ * @return the new date
+ * @since 1.0
+ */
+ public static Date plus(Date self, int days) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(self);
+ calendar.add(Calendar.DATE, days);
+ return calendar.getTime();
+ }
+
+ /**
+ * Add a number of days to this date and returns the new date.
+ *
+ * @param self a java.sql.Date
+ * @param days the number of days to increase
+ * @return the new date
+ * @since 1.0
+ */
+ public static java.sql.Date plus(java.sql.Date self, int days) {
+ return new java.sql.Date(plus((Date) self, days).getTime());
+ }
+
+ /**
+ * Add number of days to this Timestamp and returns the new Timestamp object.
+ *
+ * @param self a Timestamp
+ * @param days the number of days to increase
+ * @return the new Timestamp
+ */
+ public static Timestamp plus(Timestamp self, int days) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(self);
+ calendar.add(Calendar.DATE, days);
+ Timestamp ts = new Timestamp(calendar.getTime().getTime());
+ ts.setNanos(self.getNanos());
+ return ts;
+ }
+
+ /**
+ * Subtract a number of days from this date and returns the new date.
+ *
+ * @param self a Date
+ * @param days the number of days to subtract
+ * @return the new date
+ * @since 1.0
+ */
+ public static Date minus(Date self, int days) {
+ return plus(self, -days);
+ }
+
+ /**
+ * Subtract a number of days from this date and returns the new date.
+ *
+ * @param self a java.sql.Date
+ * @param days the number of days to subtract
+ * @return the new date
+ * @since 1.0
+ */
+ public static java.sql.Date minus(java.sql.Date self, int days) {
+ return new java.sql.Date(minus((Date) self, days).getTime());
+ }
+
+ /**
+ * Subtract a number of days from this Timestamp and returns the new Timestamp object.
+ *
+ * @param self a Timestamp
+ * @param days the number of days to subtract
+ * @return the new Timestamp
+ */
+ public static Timestamp minus(Timestamp self, int days) {
+ return plus(self, -days);
+ }
+
+ /**
+ * Subtract another date from this one and return the number of days of the difference.
+ * <p>
+ * Date self = Date then + (Date self - Date then)
+ * <p>
+ * IOW, if self is before then the result is a negative value.
+ *
+ * @param self a Calendar
+ * @param then another Calendar
+ * @return number of days
+ * @since 1.6.0
+ */
+ public static int minus(Calendar self, Calendar then) {
+ Calendar a = self;
+ Calendar b = then;
+
+ boolean swap = a.before(b);
+
+ if (swap) {
+ Calendar t = a;
+ a = b;
+ b = t;
+ }
+
+ int days = 0;
+
+ b = (Calendar) b.clone();
+
+ while (a.get(Calendar.YEAR) > b.get(Calendar.YEAR)) {
+ days += 1 + (b.getActualMaximum(Calendar.DAY_OF_YEAR) - b.get(Calendar.DAY_OF_YEAR));
+ b.set(Calendar.DAY_OF_YEAR, 1);
+ b.add(Calendar.YEAR, 1);
+ }
+
+ days += a.get(Calendar.DAY_OF_YEAR) - b.get(Calendar.DAY_OF_YEAR);
+
+ if (swap) days = -days;
+
+ return days;
+ }
+
+ /**
+ * Subtract another Date from this one and return the number of days of the difference.
+ * <p>
+ * Date self = Date then + (Date self - Date then)
+ * <p>
+ * IOW, if self is before then the result is a negative value.
+ *
+ * @param self a Date
+ * @param then another Date
+ * @return number of days
+ * @since 1.6.0
+ */
+ public static int minus(Date self, Date then) {
+ Calendar a = (Calendar) Calendar.getInstance().clone();
+ a.setTime(self);
+ Calendar b = (Calendar) Calendar.getInstance().clone();
+ b.setTime(then);
+ return minus(a, b);
+ }
+
+ /**
+ * <p>Create a String representation of this date according to the given
+ * format pattern.
+ * <p>
+ * <p>For example, if the system timezone is GMT,
+ * <code>new Date(0).format('MM/dd/yy')</code> would return the string
+ * <code>"01/01/70"</code>. See documentation for {@link java.text.SimpleDateFormat}
+ * for format pattern use.
+ * <p>
+ * <p>Note that a new DateFormat instance is created for every
+ * invocation of this method (for thread safety).
+ *
+ * @param self a Date
+ * @param format the format pattern to use according to {@link java.text.SimpleDateFormat}
+ * @return a string representation of this date.
+ * @see java.text.SimpleDateFormat
+ * @since 1.5.7
+ */
+ public static String format(Date self, String format) {
+ return new SimpleDateFormat(format).format(self);
+ }
+
+ /**
+ * <p>Create a String representation of this date according to the given
+ * format pattern and timezone.
+ * <p>
+ * <p>For example:
+ * <code>
+ * def d = new Date(0)
+ * def tz = TimeZone.getTimeZone('GMT')
+ * println d.format('dd/MMM/yyyy', tz)
+ * </code> would return the string
+ * <code>"01/Jan/1970"</code>. See documentation for {@link java.text.SimpleDateFormat}
+ * for format pattern use.
+ * <p>
+ * <p>Note that a new DateFormat instance is created for every
+ * invocation of this method (for thread safety).
+ *
+ * @param self a Date
+ * @param format the format pattern to use according to {@link java.text.SimpleDateFormat}
+ * @param tz the TimeZone to use
+ * @return a string representation of this date.
+ * @see java.text.SimpleDateFormat
+ * @since 1.8.3
+ */
+ public static String format(Date self, String format, TimeZone tz) {
+ SimpleDateFormat sdf = new SimpleDateFormat(format);
+ sdf.setTimeZone(tz);
+ return sdf.format(self);
+ }
+
+ /**
+ * <p>Return a string representation of the 'day' portion of this date
+ * according to the locale-specific {@link java.text.DateFormat#SHORT} default format.
+ * For an "en_UK" system locale, this would be <code>dd/MM/yy</code>.
+ * <p>
+ * <p>Note that a new DateFormat instance is created for every
+ * invocation of this method (for thread safety).
+ *
+ * @param self a Date
+ * @return a string representation of this date
+ * @see java.text.DateFormat#getDateInstance(int)
+ * @see java.text.DateFormat#SHORT
+ * @since 1.5.7
+ */
+ public static String getDateString(Date self) {
+ return DateFormat.getDateInstance(DateFormat.SHORT).format(self);
+ }
+
+ /**
+ * <p>Return a string representation of the time portion of this date
+ * according to the locale-specific {@link java.text.DateFormat#MEDIUM} default format.
+ * For an "en_UK" system locale, this would be <code>HH:MM:ss</code>.
+ * <p>
+ * <p>Note that a new DateFormat instance is created for every
+ * invocation of this method (for thread safety).
+ *
+ * @param self a Date
+ * @return a string representing the time portion of this date
+ * @see java.text.DateFormat#getTimeInstance(int)
+ * @see java.text.DateFormat#MEDIUM
+ * @since 1.5.7
+ */
+ public static String getTimeString(Date self) {
+ return DateFormat.getTimeInstance(DateFormat.MEDIUM).format(self);
+ }
+
+ /**
+ * <p>Return a string representation of the date and time time portion of
+ * this Date instance, according to the locale-specific format used by
+ * {@link java.text.DateFormat}. This method uses the {@link java.text.DateFormat#SHORT}
+ * preset for the day portion and {@link java.text.DateFormat#MEDIUM} for the time
+ * portion of the output string.
+ * <p>
+ * <p>Note that a new DateFormat instance is created for every
+ * invocation of this method (for thread safety).
+ *
+ * @param self a Date
+ * @return a string representation of this date and time
+ * @see java.text.DateFormat#getDateTimeInstance(int, int)
+ * @since 1.5.7
+ */
+ public static String getDateTimeString(Date self) {
+ return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM).format(self);
+ }
+
+ /**
+ * Common code for {@link #clearTime(java.util.Calendar)} and {@link #clearTime(java.util.Date)}
+ * and {@link #clearTime(java.sql.Date)}
+ *
+ * @param self a Calendar to adjust
+ */
+ private static void clearTimeCommon(final Calendar self) {
+ self.set(Calendar.HOUR_OF_DAY, 0);
+ self.clear(Calendar.MINUTE);
+ self.clear(Calendar.SECOND);
+ self.clear(Calendar.MILLISECOND);
+ }
+
+ /**
+ * Clears the time portion of this Date instance; useful utility where
+ * it makes sense to compare month/day/year only portions of a Date.
+ *
+ * @param self a Date
+ * @return the Date but with the time portion cleared
+ * @since 1.6.7
+ */
+ public static Date clearTime(final Date self) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(self);
+ clearTimeCommon(calendar);
+ self.setTime(calendar.getTime().getTime());
+ return self;
+ }
+
+ /**
+ * Clears the time portion of this java.sql.Date instance; useful utility
+ * where it makes sense to compare month/day/year only portions of a Date.
+ *
+ * @param self a java.sql.Date
+ * @return the java.sql.Date but with the time portion cleared
+ * @since 1.6.7
+ */
+ public static java.sql.Date clearTime(final java.sql.Date self) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(self);
+ clearTimeCommon(calendar);
+ self.setTime(calendar.getTime().getTime());
+ return self;
+ }
+
+ /**
+ * Clears the time portion of this Calendar instance; useful utility
+ * where it makes sense to compare month/day/year only portions of a Calendar.
+ *
+ * @param self a Calendar
+ * @return the Calendar but with the time portion cleared
+ * @since 1.6.7
+ */
+ public static Calendar clearTime(final Calendar self) {
+ clearTimeCommon(self);
+ return self;
+ }
+
+ /**
+ * <p>Shortcut for {@link java.text.SimpleDateFormat} to output a String representation
+ * of this calendar instance. This method respects the Calendar's assigned
+ * {@link java.util.TimeZone}, whereas calling <code>cal.time.format('HH:mm:ss')</code>
+ * would use the system timezone.
+ * <p>Note that Calendar equivalents of <code>date.getDateString()</code>
+ * and variants do not exist because those methods are Locale-dependent.
+ * Although a Calendar may be assigned a {@link java.util.Locale}, that information is
+ * lost and therefore cannot be used to control the default date/time formats
+ * provided by these methods. Instead, the system Locale would always be
+ * used. The alternative is to simply call
+ * {@link java.text.DateFormat#getDateInstance(int, java.util.Locale)} and pass the same Locale
+ * that was used for the Calendar.
+ *
+ * @param self this calendar
+ * @param pattern format pattern
+ * @return String representation of this calendar with the given format.
+ * @see java.text.DateFormat#setTimeZone(java.util.TimeZone)
+ * @see java.text.SimpleDateFormat#format(java.util.Date)
+ * @see #format(java.util.Date, String)
+ * @since 1.6.0
+ */
+ public static String format(Calendar self, String pattern) {
+ SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+ sdf.setTimeZone(self.getTimeZone());
+ return sdf.format(self.getTime());
+ }
+
+ /**
+ * Iterates from this date up to the given date, inclusive,
+ * incrementing by one day each time.
+ *
+ * @param self a Date
+ * @param to another Date to go up to
+ * @param closure the closure to call
+ * @since 2.2
+ */
+ public static void upto(Date self, Date to, Closure closure) {
+ if (self.compareTo(to) <= 0) {
+ for (Date i = (Date) self.clone(); i.compareTo(to) <= 0; i = next(i)) {
+ closure.call(i);
+ }
+ } else
+ throw new GroovyRuntimeException("The argument (" + to +
+ ") to upto() cannot be earlier than the value (" + self + ") it's called on.");
+ }
+
+ /**
+ * Iterates from the date represented by this calendar up to the date represented
+ * by the given calendar, inclusive, incrementing by one day each time.
+ *
+ * @param self a Calendar
+ * @param to another Calendar to go up to
+ * @param closure the closure to call
+ * @since 2.2
+ */
+ public static void upto(Calendar self, Calendar to, Closure closure) {
+ if (self.compareTo(to) <= 0) {
+ for (Calendar i = (Calendar) self.clone(); i.compareTo(to) <= 0; i = next(i)) {
+ closure.call(i);
+ }
+ } else
+ throw new GroovyRuntimeException("The argument (" + to +
+ ") to upto() cannot be earlier than the value (" + self + ") it's called on.");
+ }
+
+ /**
+ * Iterates from this date down to the given date, inclusive,
+ * decrementing by one day each time.
+ *
+ * @param self a Date
+ * @param to another Date to go down to
+ * @param closure the closure to call
+ * @since 2.2
+ */
+ public static void downto(Date self, Date to, Closure closure) {
+ if (self.compareTo(to) >= 0) {
+ for (Date i = (Date) self.clone(); i.compareTo(to) >= 0; i = previous(i)) {
+ closure.call(i);
+ }
+ } else
+ throw new GroovyRuntimeException("The argument (" + to +
+ ") to downto() cannot be later than the value (" + self + ") it's called on.");
+ }
+
+ /**
+ * Iterates from the date represented by this calendar up to the date represented
+ * by the given calendar, inclusive, incrementing by one day each time.
+ *
+ * @param self a Calendar
+ * @param to another Calendar to go down to
+ * @param closure the closure to call
+ * @since 2.2
+ */
+ public static void downto(Calendar self, Calendar to, Closure closure) {
+ if (self.compareTo(to) >= 0) {
+ for (Calendar i = (Calendar) self.clone(); i.compareTo(to) >= 0; i = previous(i)) {
+ closure.call(i);
+ }
+ } else
+ throw new GroovyRuntimeException("The argument (" + to +
+ ") to downto() cannot be later than the value (" + self + ") it's called on.");
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-dateutil/src/spec/doc/working-with-dateutil-types.adoc
----------------------------------------------------------------------
diff --git a/subprojects/groovy-dateutil/src/spec/doc/working-with-dateutil-types.adoc b/subprojects/groovy-dateutil/src/spec/doc/working-with-dateutil-types.adoc
new file mode 100644
index 0000000..9f26972
--- /dev/null
+++ b/subprojects/groovy-dateutil/src/spec/doc/working-with-dateutil-types.adoc
@@ -0,0 +1,54 @@
+//////////////////////////////////////////
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+//////////////////////////////////////////
+
+= Working with legacy Date/Calendar types
+
+The `groovy-dateutil` module supports numerous extensions for working with
+Java's classic `Date` and `Calendar` classes.
+
+You can access the properties of a `Date` or `Calendar` using the normal array index notation
+with the constant field numbers from the `Calendar` class as shown in the following example:
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateUtilTypesTest.groovy[tags=calendar_getAt,indent=0]
+-------------------------------------
+<1> Import the constants
+<2> Setting the calendar's year, month and day of month
+<3> Accessing the calendar's day of week
+
+Groovy supports arithmetic on and iteration between `Date` and `Calendar` instances as shown in the following example:
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateUtilTypesTest.groovy[tags=date_arithmetic,indent=0]
+-------------------------------------
+
+You can parse strings into dates and output dates into formatted strings:
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateUtilTypesTest.groovy[tags=date_parsing,indent=0]
+-------------------------------------
+
+You can also create a new Date or Calendar based on an existing one:
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateUtilTypesTest.groovy[tags=date_copyWith,indent=0]
+-------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-dateutil/src/spec/test/gdk/WorkingWithDateUtilTypesTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-dateutil/src/spec/test/gdk/WorkingWithDateUtilTypesTest.groovy b/subprojects/groovy-dateutil/src/spec/test/gdk/WorkingWithDateUtilTypesTest.groovy
new file mode 100644
index 0000000..7599867
--- /dev/null
+++ b/subprojects/groovy-dateutil/src/spec/test/gdk/WorkingWithDateUtilTypesTest.groovy
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package gdk
+
+class WorkingWithDateUtilTypesTest extends GroovyTestCase {
+
+ void testGetAt() {
+ assertScript '''
+ // tag::calendar_getAt[]
+ import static java.util.Calendar.* // <1>
+
+ def cal = Calendar.instance
+ cal[YEAR] = 2000 // <2>
+ cal[MONTH] = JANUARY // <2>
+ cal[DAY_OF_MONTH] = 1 // <2>
+ assert cal[DAY_OF_WEEK] == SATURDAY // <3>
+ // end::calendar_getAt[]
+ '''
+ }
+
+ void testDateArithmetic() {
+ // tag::date_arithmetic[]
+ def yesterday = new Date() - 1
+ def tomorrow = new Date() + 1
+
+ def diffInDays = tomorrow - yesterday
+ assert diffInDays == 2
+
+ int count = 0
+ yesterday.upto(tomorrow) { count++ }
+ assert count == 3
+ // end::date_arithmetic[]
+ }
+
+ void testDateParsing() {
+ assertScript '''
+ import static java.util.Calendar.*
+
+ // tag::date_parsing[]
+ def orig = '2000-01-01'
+ def newYear = Date.parse('yyyy-MM-dd', orig)
+ assert newYear[DAY_OF_WEEK] == SATURDAY
+ assert newYear.format('yyyy-MM-dd') == orig
+ assert newYear.format('dd/MM/yyyy') == '01/01/2000'
+ // end::date_parsing[]
+ '''
+ }
+
+ void testCopyWith() {
+ assertScript '''
+ import static java.util.Calendar.*
+
+ // tag::date_copyWith[]
+ def newYear = Date.parse('yyyy-MM-dd', '2000-01-01')
+ def newYearsEve = newYear.copyWith(
+ year: 1999,
+ month: DECEMBER,
+ dayOfMonth: 31
+ )
+ assert newYearsEve[DAY_OF_WEEK] == FRIDAY
+ // end::date_copyWith[]
+ '''
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-dateutil/src/test/java/groovy/DateTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-dateutil/src/test/java/groovy/DateTest.groovy b/subprojects/groovy-dateutil/src/test/java/groovy/DateTest.groovy
new file mode 100644
index 0000000..b014f53
--- /dev/null
+++ b/subprojects/groovy-dateutil/src/test/java/groovy/DateTest.groovy
@@ -0,0 +1,327 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy
+
+import java.text.DateFormat
+import java.text.SimpleDateFormat
+
+import static java.util.Calendar.*
+
+class DateTest extends GroovyTestCase {
+ void testCalendarNextPrevious() {
+ TimeZone tz = TimeZone.getTimeZone('GMT+00')
+ Calendar c = getInstance(tz)
+ c[HOUR_OF_DAY] = 6
+ c[YEAR] = 2002
+ c[MONTH] = FEBRUARY
+ c[DATE] = 2
+ c.clearTime()
+ def formatter = new SimpleDateFormat('dd-MMM-yyyy', Locale.US)
+ formatter.calendar.timeZone = tz
+
+ assert formatter.format(c.previous().time) == '01-Feb-2002'
+ assert formatter.format(c.time) == '02-Feb-2002'
+ assert formatter.format(c.next().time) == '03-Feb-2002'
+ def dates = (c.previous()..c.next()).collect{ formatter.format(it.time) }
+ assert dates == ['01-Feb-2002', '02-Feb-2002', '03-Feb-2002']
+ }
+
+ void testDateNextPrevious() {
+ def tz = TimeZone.default
+ def x = new Date()
+ def y = x + 2
+ assert x < y
+ def crossedDaylightSavingBoundary = tz.inDaylightTime(x) ^ tz.inDaylightTime(y)
+ ++x
+ --y
+ if (!crossedDaylightSavingBoundary) assert x == y
+ x += 2
+ assert x > y
+ }
+
+ void testDateRange() {
+ def today = new Date()
+ def later = today + 3
+ def expected = [today, today + 1, today + 2, today + 3]
+ def list = []
+ for (d in today..later) {
+ list << d
+ }
+ assert list == expected
+ }
+
+ void testCalendarIndex() {
+ Calendar c = new GregorianCalendar(2002, FEBRUARY, 2)
+ assert c[MONTH] == FEBRUARY
+ assert c[DAY_OF_WEEK] == SATURDAY
+ }
+
+ void testDateIndex() {
+ Date d = new GregorianCalendar(2002, FEBRUARY, 2).time
+ assert d[MONTH] == FEBRUARY
+ assert d[DAY_OF_WEEK] == SATURDAY
+ }
+
+ void testGDKDateMethods() {
+ Locale defaultLocale = Locale.default
+ TimeZone defaultTZ = TimeZone.default
+ try {
+ Locale locale = Locale.GERMANY
+ Locale.setDefault locale // set this otherwise the test will fail if your locale isn't the same
+ TimeZone.setDefault TimeZone.getTimeZone('Europe/Berlin')
+
+ Date d = new Date(0)
+
+ assertEquals '1970-01-01', d.format('yyyy-MM-dd')
+ assertEquals '01/01/1970', d.format('dd/MM/yyyy', TimeZone.getTimeZone('GMT'))
+ assertEquals DateFormat.getDateInstance(DateFormat.SHORT, locale).format(d), d.dateString
+ assertEquals '01.01.70', d.dateString
+ assertEquals DateFormat.getTimeInstance(DateFormat.MEDIUM, locale).format(d), d.timeString
+ assertEquals '01:00:00', d.timeString
+ assertEquals DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale).format(d), d.dateTimeString
+ } finally {
+ Locale.default = defaultLocale
+ TimeZone.setDefault defaultTZ
+ }
+ }
+
+ void testStaticParse() {
+ TimeZone defaultTZ = TimeZone.default
+ try {
+ TimeZone.setDefault TimeZone.getTimeZone('Etc/GMT')
+
+ Date d = Date.parse('yy/MM/dd hh:mm:ss', '70/01/01 00:00:00')
+
+ assertEquals 0, d.time
+ } finally {
+ TimeZone.setDefault defaultTZ
+ }
+ }
+
+ void testParseWithTimeZone() {
+ TimeZone defaultTZ = TimeZone.default
+ try {
+ TimeZone.default = TimeZone.getTimeZone("GMT+05")
+ def tz = TimeZone.getTimeZone("GMT+03")
+
+ def newYear = Date.parse('yyyy-MM-dd', "2015-01-01", tz)
+
+ assert newYear.toString() == 'Thu Jan 01 02:00:00 GMT+05:00 2015'
+ } finally {
+ TimeZone.default = defaultTZ
+ }
+ }
+
+ void testRoundTrip() {
+ Date d = new Date()
+ String pattern = 'dd MMM yyyy, hh:mm:ss,SSS a z'
+ String out = d.format(pattern)
+
+ Date d2 = Date.parse(pattern, out)
+
+ assertEquals d.time, d2.time
+ }
+
+ void testCalendarTimeZone() {
+ Locale defaultLocale = Locale.default
+ TimeZone defaultTZ = TimeZone.default
+ try {
+ Locale locale = Locale.UK
+ Locale.setDefault locale // set this otherwise the test will fail if your locale isn't the same
+ TimeZone.setDefault TimeZone.getTimeZone('Etc/GMT')
+
+ def offset = 8
+ def notLocalTZ = TimeZone.getTimeZone("GMT-$offset")
+ Calendar cal = Calendar.getInstance(notLocalTZ)
+ def offsetHr = cal.format('HH') as int
+ def hr = cal.time.format('HH') as int
+ if (hr < offset) hr += 24 // if GMT hr has rolled over to next day
+
+ // offset should be 8 hours behind GMT:
+ assertEquals(offset, hr - offsetHr)
+ } finally {
+ Locale.default = defaultLocale
+ TimeZone.setDefault defaultTZ
+ }
+ }
+
+ static SimpleDateFormat f = new SimpleDateFormat('MM/dd/yyyy')
+
+ static java.sql.Date sqlDate(String s) {
+ return new java.sql.Date(f.parse(s).time)
+ }
+
+ void testMinusDates() {
+ assertEquals(10, f.parse("1/11/2007") - f.parse("1/1/2007"))
+ assertEquals(-10, f.parse("1/1/2007") - f.parse("1/11/2007"))
+ assertEquals(375, f.parse("1/11/2008") - f.parse("1/1/2007"))
+ assertEquals(356, f.parse("1/1/2008") - f.parse("1/10/2007"))
+ assertEquals(1, f.parse("7/12/2007") - f.parse("7/11/2007"))
+ assertEquals(0, f.parse("1/1/2007") - f.parse("1/1/2007"))
+ assertEquals(-1, f.parse("12/31/2007") - f.parse("1/1/2008"))
+ assertEquals(365, f.parse("1/1/2008") - f.parse("1/1/2007"))
+ assertEquals(36525, f.parse("1/1/2008") - f.parse("1/1/1908"))
+
+ assertEquals(1, sqlDate("7/12/2007") - f.parse("7/11/2007"))
+ assertEquals(0, sqlDate("1/1/2007") - sqlDate("1/1/2007"))
+ assertEquals(-1, f.parse("12/31/2007") - sqlDate("1/1/2008"))
+ assertEquals(365, sqlDate("1/1/2008") - sqlDate("1/1/2007"))
+ assertEquals(36525, f.parse("1/1/2008") - sqlDate("1/1/1908"))
+
+ Date d = f.parse("7/4/1776");
+ assertEquals(44, (d + 44) - d);
+
+ java.sql.Date sqld = sqlDate("7/4/1776");
+ assertEquals(-4444, (sqld - 4444) - sqld);
+ }
+
+ /** GROOVY-3374 */
+ void testClearTime() {
+ def now = new Date()
+ def calendarNow = Calendar.getInstance()
+
+ now.clearTime()
+ calendarNow.clearTime()
+
+ assert now == calendarNow.time
+
+ assert calendarNow.get(Calendar.HOUR) == 0
+ assert calendarNow.get(Calendar.MINUTE) == 0
+ assert calendarNow.get(Calendar.SECOND) == 0
+ assert calendarNow.get(Calendar.MILLISECOND) == 0
+ }
+
+ /** GROOVY-4789 */
+ void testStaticParseToStringDate() {
+ TimeZone tz = TimeZone.getDefault()
+ try {
+ TimeZone.setDefault(TimeZone.getTimeZone("GMT"))
+
+ Date date = new Date(0)
+ String toStringRepresentation = date.toString()
+
+ assert toStringRepresentation == "Thu Jan 01 00:00:00 GMT 1970"
+ assert date == Date.parseToStringDate(toStringRepresentation)
+ }
+ finally {
+ TimeZone.setDefault(tz)
+ }
+ }
+
+ void test_Upto_Date_ShouldExecuteClosureForEachDayUpToDate() {
+ Date startDate = new Date()
+ List expectedResults = [startDate, startDate + 1, startDate + 2]
+
+ List actualResults = []
+
+ startDate.upto(startDate + 2){
+ actualResults << it
+ }
+
+ assert actualResults == expectedResults
+ }
+
+ void test_upto_Date_ShouldNotAcceptToDatesLessThanStartDate() {
+ Date startDate = new Date()
+ Date toDate = new Date(startDate.getTime() - 1L)
+
+ shouldFail(GroovyRuntimeException) {
+ startDate.upto(toDate){}
+ }
+ }
+
+ void test_downto_Date_ShouldExecuteClosureForEachDayDownToDate() {
+ Date startDate = new Date()
+ List expectedResults = [startDate, startDate - 1, startDate - 2]
+
+ List actualResults = []
+ startDate.downto(startDate - 2){
+ actualResults << it
+ }
+
+ assert actualResults == expectedResults
+ }
+
+ void test_downto_Date_ShouldNotAcceptToDatesGreaterThanStartDate() {
+ Date startDate = new Date()
+ Date toDate = new Date(startDate.getTime() + 1L)
+
+ shouldFail(GroovyRuntimeException) {
+ startDate.downto(toDate){}
+ }
+ }
+
+ void test_upto_Calendar_ShouldExecuteClosureForEachDayUpToDate() {
+ Calendar startDate = Calendar.getInstance()
+ Calendar toDate = startDate.clone()
+ toDate.add(Calendar.DATE, 1)
+ List expectedResults = [startDate, toDate]
+
+ List actualResults = []
+ startDate.upto(toDate){
+ actualResults << it
+ }
+
+ assert actualResults == expectedResults
+ }
+
+ void test_upto_Calendar_ShouldNotAcceptToDatesLessThanStartDate() {
+ Calendar startDate = Calendar.getInstance()
+ Calendar toDate = startDate.clone()
+ toDate.add(Calendar.MILLISECOND, -1)
+
+ shouldFail(GroovyRuntimeException) {
+ startDate.upto(toDate){}
+ }
+ }
+
+ void test_downto_Calendar_ShouldExecuteClosureForEachDayDownToDate() {
+ Calendar startDate = Calendar.getInstance()
+ Calendar toDate = startDate.clone()
+ toDate.add(Calendar.DATE, -1)
+ List expectedResults = [startDate, toDate]
+
+ List actualResults = []
+ startDate.downto(toDate){
+ actualResults << it
+ }
+
+ assert actualResults == expectedResults
+ }
+
+ void test_downto_Calendar_ShouldNotAcceptToDatesGreaterThanStartDate() {
+ Calendar startDate = Calendar.getInstance()
+ Calendar toDate = startDate.clone()
+ toDate.add(Calendar.MILLISECOND, 1)
+
+ shouldFail(GroovyRuntimeException) {
+ startDate.downto(toDate){}
+ }
+ }
+
+ void testCopyWith() {
+ Date febOne1970 = new Date(70, 1, 1)
+ Date aprilSix = febOne1970.copyWith(dayOfMonth: 6, month: Calendar.APRIL)
+ assertEquals '1970-04-06', aprilSix.format('yyyy-MM-dd')
+ Map updates = [:]
+ updates[Calendar.DAY_OF_MONTH] = 4
+ Date aprilFour = aprilSix.copyWith(updates)
+ assertEquals '1970-04-04', aprilFour.format('yyyy-MM-dd')
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-dateutil/src/test/java/org/apache/groovy/dateutil/extensions/DateUtilExtensionsTest.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-dateutil/src/test/java/org/apache/groovy/dateutil/extensions/DateUtilExtensionsTest.java b/subprojects/groovy-dateutil/src/test/java/org/apache/groovy/dateutil/extensions/DateUtilExtensionsTest.java
new file mode 100644
index 0000000..8cecc5b
--- /dev/null
+++ b/subprojects/groovy-dateutil/src/test/java/org/apache/groovy/dateutil/extensions/DateUtilExtensionsTest.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.groovy.dateutil.extensions;
+
+import org.junit.Test;
+
+import java.sql.Timestamp;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+import static org.junit.Assert.assertEquals;
+
+public class DateUtilExtensionsTest {
+ @Test
+ public void plus() throws ParseException {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+ Date dec31 = sdf.parse("20171231");
+ assertEquals("20180101", sdf.format(DateUtilExtensions.plus(dec31, 1)));
+ assertEquals("20180101", sdf.format(DateUtilExtensions.plus(new Timestamp(dec31.getTime()), 1)));
+ }
+
+ @Test
+ public void minus() throws ParseException {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+ Date jan01 = sdf.parse("20180101");
+ assertEquals("20171231", sdf.format(DateUtilExtensions.minus(jan01, 1)));
+ assertEquals("20171231", sdf.format(DateUtilExtensions.minus(new Timestamp(jan01.getTime()), 1)));
+ }
+
+ @Test
+ public void next() throws ParseException {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(sdf.parse("20171231"));
+ assertEquals("20180101", sdf.format(DateUtilExtensions.next(calendar).getTime()));
+ }
+
+ @Test
+ public void previous() throws ParseException {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(sdf.parse("20180101"));
+ assertEquals("20171231", sdf.format(DateUtilExtensions.previous(calendar).getTime()));
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-json/build.gradle
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/build.gradle b/subprojects/groovy-json/build.gradle
index c96a723..c9bf97a 100644
--- a/subprojects/groovy-json/build.gradle
+++ b/subprojects/groovy-json/build.gradle
@@ -20,4 +20,5 @@ dependencies {
compile rootProject
testCompile project(':groovy-test')
testRuntime project(':groovy-ant')
+ testCompile project(':groovy-dateutil')
}
[4/7] groovy git commit: move datetime extensions to their own module
Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/src/spec/doc/working-with-datetime-types.adoc
----------------------------------------------------------------------
diff --git a/src/spec/doc/working-with-datetime-types.adoc b/src/spec/doc/working-with-datetime-types.adoc
deleted file mode 100644
index 6567154..0000000
--- a/src/spec/doc/working-with-datetime-types.adoc
+++ /dev/null
@@ -1,341 +0,0 @@
-//////////////////////////////////////////
-
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
-
-//////////////////////////////////////////
-
-= Working with Date/Time types
-:gdk: http://www.groovy-lang.org/gdk.html[Groovy development kit]
-:java-util-list: http://docs.oracle.com/javase/8/docs/api/java/util/List.html[java.util.List]
-:java-time-types: `java.time` types
-
-Groovy's syntax and extension methods within the {gdk} provide conveniences for using
-the http://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html[Date/Time API
-introduced in Java 8]. This documentation refers to the data types defined by this API as
-"JSR 310 types."
-
-== Formatting and parsing
-
-A common use case when working with date/time types is to convert them to Strings (formatting)
-and from Strings (parsing). Groovy provides these additional formatting methods:
-
-[cols="1,1,1" options="header"]
-|====
-| Method
-| Description
-| Example
-
-| `getDateString()`
-| For `LocalDate` and `LocalDateTime`, formats with
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE[`DateTimeFormatter.ISO_LOCAL_DATE`]
-| `2018-03-10`
-
-|
-| For `OffsetDateTime`, formats with
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_OFFSET_DATE[`DateTimeFormatter.ISO_OFFSET_DATE`]
-| `2018-03-10+04:00`
-
-|
-| For `ZonedDateTime`, formats with
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE[`DateTimeFormatter.ISO_LOCAL_DATE`]
-and appends the `ZoneId` short name
-| `2018-03-10EST`
-
-| `getDateTimeString()`
-| For `LocalDateTime`, formats with
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE_TIME[`DateTimeFormatter.ISO_LOCAL_DATE_TIME`]
-| `2018-03-10T20:30:45`
-
-|
-| For `OffsetDateTime`, formats with
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_OFFSET_DATE_TIME[`DateTimeFormatter.ISO_OFFSET_DATE_TIME`]
-| `2018-03-10T20:30:45+04:00`
-
-|
-| For `ZonedDateTime`, formats with
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE_TIME[`DateTimeFormatter.ISO_LOCAL_DATE_TIME`]
-and appends the `ZoneId` short name
-| `2018-03-10T20:30:45EST`
-
-| `getTimeString()`
-| For `LocalTime` and `LocalDateTime`, formats with
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_TIME[`DateTimeFormatter.ISO_LOCAL_TIME`]
-| `20:30:45`
-
-|
-| For `OffsetTime` and `OffsetDateTime`, formats with
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_OFFSET_TIME[`DateTimeFormatter.ISO_OFFSET_TIME`]
-formatter
-| `20:30:45+04:00`
-
-|
-| For `ZonedDateTime`, formats with
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_TIME[`DateTimeFormatter.ISO_LOCAL_TIME`]
-and appends the `ZoneId` short name
-| `20:30:45EST`
-
-| `format(FormatStyle style)`
-| For `LocalTime` and `OffsetTime`, formats with
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ofLocalizedTime-java.time.format.FormatStyle-[`DateTimeFormatter.ofLocalizedTime(style)`]
-| `4:30 AM` (with style `FormatStyle.SHORT`, e.g.)
-
-|
-| For `LocalDate`, formats with
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ofLocalizedDate-java.time.format.FormatStyle-[`DateTimeFormatter.ofLocalizedDate(style)`]
-| `Saturday, March 10, 2018` (with style `FormatStyle.FULL`, e.g.)
-
-|
-| For `LocalDateTime`, `OffsetDateTime`, and `ZonedDateTime` formats with
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ofLocalizedDateTime-java.time.format.FormatStyle-[`DateTimeFormatter.ofLocalizedDateTime(style)`]
-| `Mar 10, 2019 4:30:45 AM` (with style `FormatStyle.MEDIUM`, e.g.)
-
-| `format(String pattern)`
-| Formats with
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ofPattern-java.lang.String-[`DateTimeFormatter.ofPattern(pattern)`]
-| `03/10/2018` (with pattern `'MM/dd/yyyy', e.g.)
-|====
-
-For parsing, Groovy adds a static `parse` method to many of the JSR 310 types. The method
-takes two arguments: the value to be formatted and the pattern to use. The pattern is
-defined by the
-https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html[`java.time.format.DateTimeFormatter` API].
-As an example:
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=static_parsing,indent=0]
--------------------------------------
-
-Note that these `parse` methods have a different argument ordering than the static
-`parse` method Groovy added to `java.util.Date`.
-This was done to be consistent with the existing `parse` methods of the Date/Time API.
-
-== Manipulating date/time
-
-=== Addition and subtraction
-
-`Temporal` types have `plus` and `minus` methods for adding or subtracting a provided
-`java.time.temporal.TemporalAmount` argument. Because Groovy maps the `+` and `-` operators
-to single-argument methods of these names, a more natural expression syntax can be used to add and subtract.
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=plus_minus_period,indent=0]
--------------------------------------
-
-Groovy provides additional `plus` and `minus` methods that accept an integer argument,
-enabling the above to be rewritten more succinctly:
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=localdate_plus_minus_integer,indent=0]
--------------------------------------
-
-The unit of these integers depends on the JSR 310 type operand. As evident above,
-integers used with `ChronoLocalDate` types like `LocalDate` have a unit of
-https://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoUnit.html#DAYShttp://days[days].
-Integers used with `Year` and `YearMonth` have a unit of
-https://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoUnit.html#YEARS[years] and
-https://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoUnit.html#MONTHS[months], respectively.
-All other types have a unit of
-https://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoUnit.html#SECONDS[seconds],
-such as `LocalTime`, for instance:
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=localtime_plus_minus_integer,indent=0]
--------------------------------------
-
-=== Multiplication and division
-
-The `*` operator can be used to multiply `Period` and `Duration` instances by an
-integer value; the `/` operator can be used to divide `Duration` instances by an integer value.
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=multiply_divide,indent=0]
--------------------------------------
-
-=== Incrementing and decrementing
-
-The `++` and `--` operators can be used increment and decrement date/time values by one unit. Since the JSR 310 types
-are immutable, the operation will create a new instance with the incremented/decremented value and reassign it to the
-reference.
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=next_previous,indent=0]
--------------------------------------
-
-=== Negation
-
-The `Duration` and `Period` types represent a negative or positive length of time.
-These can be negated with the unary `-` operator.
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=duration_negation,indent=0]
--------------------------------------
-
-== Interacting with date/time values
-
-=== Property notation
-
-The
-https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAccessor.html#getLong-java.time.temporal.TemporalField-[`getLong(TemporalField)`]
-method of `TemporalAccessor` types (e.g. `LocalDate`,
-`LocalTime`, `ZonedDateTime`, etc.) and the
-https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAmount.html#get-java.time.temporal.TemporalUnit-[`get(TemporalUnit)`]
-method of `TemporalAmount` types (namely `Period` and `Duration`), can be invoked with
-Groovy's property notation. For example:
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=property_notation,indent=0]
--------------------------------------
-
-=== Ranges, `upto`, and `downto`
-
-The JSR 310 types can be used with the <<core-operators.adoc#_range_operator,range operator>>.
-The following example iterates between today and the `LocalDate` six days from now,
-printing out the day of the week for each iteration. As both range bounds are inclusive,
-this prints all seven days of the week.
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=date_ranges,indent=0]
--------------------------------------
-
-The `upto` method will accomplish the same as the range in the above example.
-The `upto` method iterates from the earlier start value (inclusive) to the later end value
-(also inclusive), calling the closure with the incremented value once per iteration.
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=date_upto_date,indent=0]
--------------------------------------
-
-The `downto` method iterates in the opposite direction, from a later start value
-to an earlier end value.
-
-The unit of iteration for `upto`, `downto`, and ranges is the same as the unit for addition
-and subtraction: `LocalDate` iterates by one day at a time,
-`YearMonth` iterates by one month, `Year` by one year, and everything else by one second.
-Both methods also support an optional a `TemporalUnit` argument to change the unit of
-iteration.
-
-Consider the following example, where March 1st, 2018 is iterated up to March 2nd, 2018
-using an iteration unit of
-https://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoUnit.html#MONTHS[months].
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=date_upto_date_by_months,indent=0]
--------------------------------------
-
-Since the start date is inclusive, the closure is called with date March 1st. The `upto` method
-then increments the date by one month, yielding the date, April 1st. Because this date is _after_ the
-specified end date of March 2nd, the iteration stops immediately, having only called the closure
-once. This behavior is the same for the `downto` method except that the iteration will stop
-as soon as the the value of `end` becomes earlier than the targeted end date.
-
-In short, when iterating with the `upto` or `downto` methods with a custom unit of iteration,
-the current value of iteration will never exceed the end value.
-
-=== Combining date/time values
-
-The left-shift operator (`<<`) can be used to combine two JSR 310 types into an aggregate type.
-For example, a `LocalDate` can be left-shifted into a `LocalTime` to produce a composite
-`LocalDateTime` instance.
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=leftshift_operator,indent=0]
--------------------------------------
-
-The left-shift operator is reflexive; the order of the operands does not matter.
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=leftshift_operator_reflexive,indent=0]
--------------------------------------
-
-=== Creating periods and durations
-
-The right-shift operator (`>>`) produces a value representing the period or duration between the
-operands. For `ChronoLocalDate`, `YearMonth`, and `Year`, the operator yields
-a `Period` instance:
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=rightshift_operator_period,indent=0]
--------------------------------------
-
-The operator produces a `Duration` for the time-aware JSR types:
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=rightshift_operator_duration,indent=0]
--------------------------------------
-
-If the value on the left-hand side of the operator is earlier than the value on the right-hand
-side, the result is positive. If the left-hand side is later than the right-hand side, the
-result is negative:
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=rightshift_operator_negative,indent=0]
--------------------------------------
-
-== Converting between legacy and JSR 310 types
-
-Despite the shortcomings of `Date`, `Calendar`, and `TimeZone` types in the `java.util` package
-they are farily common in Java APIs (at least in those prior to Java 8).
-To accommodate use of such APIs, Groovy provides methods for converting between the
-JSR 310 types and legacy types.
-
-Most JSR types have been fitted with `toDate()` and `toCalendar()` methods for
-converting to relatively equivalent `java.util.Date` and `java.util.Calendar` values.
-Both `ZoneId` and `ZoneOffset` have been given a `toTimeZone()` method for converting to
-`java.util.TimeZone`.
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=todate_tocalendar,indent=0]
--------------------------------------
-
-Note that when converting to a legacy type:
-
-* Nanosecond values are truncated to milliseconds. A `LocalTime`, for example, with a `ChronoUnit.NANOS` value
-of 999,999,999 nanoseconds translates to 999 milliseconds.
-* When converting the "local" types (`LocalDate`, `LocalTime`, and `LocalDateTime`), the time zone of the
-returned `Date` or `Calendar` will be the system default.
-* When converting a time-only type (`LocalTime` or `OffsetTime`), the year/month/day of the `Date` or `Calendar` is set
-to the current date.
-* When converting a date-only type (`LocalDate`), the time value of the `Date` or `Calendar` will be cleared,
-i.e. `00:00:00.000`.
-* When converting an `OffsetDateTime` to a `Calendar`, only the hours and minutes of the `ZoneOffset` convey
-into the corresponding `TimeZone`. Fortunately, Zone Offsets with non-zero seconds are rare.
-
-Groovy has added a number of methods to `Date` and `Calendar`
-for converting into the various JSR 310 types:
-
-[source,groovy]
--------------------------------------
-include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=to_jsr310_types,indent=0]
--------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy
----------------------------------------------------------------------
diff --git a/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy b/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy
deleted file mode 100644
index 99e7f8d..0000000
--- a/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy
+++ /dev/null
@@ -1,222 +0,0 @@
-package gdk
-
-import java.time.*
-import java.time.chrono.JapaneseDate
-import java.time.temporal.ChronoField
-import java.time.temporal.ChronoUnit
-
-class WorkingWithDateTimeTypesTest extends GroovyTestCase {
-
- void testParsing() {
- // tag::static_parsing[]
- def date = LocalDate.parse('Jun 3, 04','MMM d, yy')
- assert date == LocalDate.of(2004, Month.JUNE, 3)
-
- def time = LocalTime.parse('4:45','H:mm')
- assert time == LocalTime.of(4, 45, 0)
-
- def offsetTime = OffsetTime.parse('09:47:51-1234', 'HH:mm:ssZ')
- assert offsetTime == OffsetTime.of(9, 47, 51, 0, ZoneOffset.ofHoursMinutes(-12, -34))
-
- def dateTime = ZonedDateTime.parse('2017/07/11 9:47PM Pacific Standard Time', 'yyyy/MM/dd h:mma zzzz')
- assert dateTime == ZonedDateTime.of(
- LocalDate.of(2017, 7, 11),
- LocalTime.of(21, 47, 0),
- ZoneId.of('America/Los_Angeles')
- )
- // end::static_parsing[]
- }
-
- void testRange() {
- // tag::date_ranges[]
- def start = LocalDate.now()
- def end = start + 6 // 6 days later
- (start..end).each { date ->
- println date.dayOfWeek
- }
- // end::date_ranges[]
- }
-
- void testUptoDownto() {
- // tag::date_upto_date[]
- def start = LocalDate.now()
- def end = start + 6 // 6 days later
- start.upto(end) { date ->
- println date.dayOfWeek
- }
- // end::date_upto_date[]
- }
-
- void testUptoCustomUnit() {
- // tag::date_upto_date_by_months[]
- def start = LocalDate.of(2018, Month.MARCH, 2)
- def end = start + 1 // 1 day later
-
- int iterationCount = 0
- start.upto(end, ChronoUnit.MONTHS) { date ->
- println date
- ++iterationCount
- }
-
- assert iterationCount == 1
- // end::date_upto_date_by_months[]
- }
-
- void testPlusMinusWithTemporalAmounts() {
- // tag::plus_minus_period[]
- def aprilFools = LocalDate.of(2018, Month.APRIL, 1)
-
- def nextAprilFools = aprilFools + Period.ofDays(365) // add 365 days
- assert nextAprilFools.year == 2019
-
- def idesOfMarch = aprilFools - Period.ofDays(17) // subtract 17 days
- assert idesOfMarch.dayOfMonth == 15
- assert idesOfMarch.month == Month.MARCH
- // end::plus_minus_period[]
- }
-
- void testLocalDatePlusMinusInteger() {
- def aprilFools = LocalDate.of(2018, Month.APRIL, 1)
-
- // tag::localdate_plus_minus_integer[]
- def nextAprilFools = aprilFools + 365 // add 365 days
- def idesOfMarch = aprilFools - 17 // subtract 17 days
- // end::localdate_plus_minus_integer[]
-
- assert nextAprilFools.year == 2019
- assert idesOfMarch.dayOfMonth == 15
- assert idesOfMarch.month == Month.MARCH
- }
-
- void testLocalTimePlusMinusInteger() {
- // tag::localtime_plus_minus_integer[]
- def mars = LocalTime.of(12, 34, 56) // 12:34:56 pm
-
- def thirtySecondsToMars = mars - 30 // go back 30 seconds
- assert thirtySecondsToMars.second == 26
- // end::localtime_plus_minus_integer[]
- }
-
- void testNextPrevious() {
- // tag::next_previous[]
- def year = Year.of(2000)
- --year // decrement by one year
- assert year.value == 1999
-
- def offsetTime = OffsetTime.of(0, 0, 0, 0, ZoneOffset.UTC) // 00:00:00.000 UTC
- offsetTime++ // increment by one second
- assert offsetTime.second == 1
- // end::next_previous[]
- }
-
- void testMultiplyDivide() {
- // tag::multiply_divide[]
- def period = Period.ofMonths(1) * 2 // a 1-month period times 2
- assert period.months == 2
-
- def duration = Duration.ofSeconds(10) / 5// a 10-second duration divided by 5
- assert duration.seconds == 2
- // end::multiply_divide[]
- }
-
- void testNegation() {
- // tag::duration_negation[]
- def duration = Duration.ofSeconds(-15)
- def negated = -duration
- assert negated.seconds == 15
- // end::duration_negation[]
- }
-
- void testPropertyNotation() {
- // tag::property_notation[]
- def date = LocalDate.of(2018, Month.MARCH, 12)
- assert date[ChronoField.YEAR] == 2018
- assert date[ChronoField.MONTH_OF_YEAR] == Month.MARCH.value
- assert date[ChronoField.DAY_OF_MONTH] == 12
- assert date[ChronoField.DAY_OF_WEEK] == DayOfWeek.MONDAY.value
-
- def period = Period.ofYears(2).withMonths(4).withDays(6)
- assert period[ChronoUnit.YEARS] == 2
- assert period[ChronoUnit.MONTHS] == 4
- assert period[ChronoUnit.DAYS] == 6
- // end::property_notation[]
- }
-
- void testLeftShift() {
- // tag::leftshift_operator[]
- MonthDay monthDay = Month.JUNE << 3 // June 3rd
- LocalDate date = monthDay << Year.of(2015) // 3-Jun-2015
- LocalDateTime dateTime = date << LocalTime.NOON // 3-Jun-2015 @ 12pm
- OffsetDateTime offsetDateTime = dateTime << ZoneOffset.ofHours(-5) // 3-Jun-2015 @ 12pm UTC-5
- // end::leftshift_operator[]
- // tag::leftshift_operator_reflexive[]
- def year = Year.of(2000)
- def month = Month.DECEMBER
-
- YearMonth a = year << month
- YearMonth b = month << year
- assert a == b
- // end::leftshift_operator_reflexive[]
- }
-
- void testRightShift() {
- // tag::rightshift_operator_period[]
- def newYears = LocalDate.of(2018, Month.JANUARY, 1)
- def aprilFools = LocalDate.of(2018, Month.APRIL, 1)
-
- def period = newYears >> aprilFools
- assert period instanceof Period
- assert period.months == 3
- // end::rightshift_operator_period[]
-
- // tag::rightshift_operator_duration[]
- def duration = LocalTime.NOON >> (LocalTime.NOON + 30)
- assert duration instanceof Duration
- assert duration.seconds == 30
- // end::rightshift_operator_duration[]
-
- // tag::rightshift_operator_negative[]
- def decade = Year.of(2010) >> Year.of(2000)
- assert decade.years == -10
- // end::rightshift_operator_negative[]
- }
-
- void testToDateAndToCalendar() {
- // tag::todate_tocalendar[]
- // LocalDate to java.util.Date
- def valentines = LocalDate.of(2018, Month.FEBRUARY, 14)
- assert valentines.toDate().format('MMMM dd, yyyy') == 'February 14, 2018'
-
- // LocalTime to java.util.Date
- def noon = LocalTime.of(12, 0, 0)
- assert noon.toDate().format('HH:mm:ss') == '12:00:00'
-
- // ZoneId to java.util.TimeZone
- def newYork = ZoneId.of('America/New_York')
- assert newYork.toTimeZone() == TimeZone.getTimeZone('America/New_York')
-
- // ZonedDateTime to java.util.Calendar
- def valAtNoonInNY = ZonedDateTime.of(valentines, noon, newYork)
- assert valAtNoonInNY.toCalendar().getTimeZone().toZoneId() == newYork
- // end::todate_tocalendar[]
- }
-
- void testConvertToJSR310Types() {
- // tag::to_jsr310_types[]
- Date legacy = Date.parse('yyyy-MM-dd HH:mm:ss.SSS', '2010-04-03 10:30:58.999')
-
- assert legacy.toLocalDate() == LocalDate.of(2010, 4, 3)
- assert legacy.toLocalTime() == LocalTime.of(10, 30, 58, 999_000_000) // 999M ns = 999ms
- assert legacy.toOffsetTime().hour == 10
- assert legacy.toYear() == Year.of(2010)
- assert legacy.toMonth() == Month.APRIL
- assert legacy.toDayOfWeek() == DayOfWeek.SATURDAY
- assert legacy.toMonthDay() == MonthDay.of(Month.APRIL, 3)
- assert legacy.toYearMonth() == YearMonth.of(2010, Month.APRIL)
- assert legacy.toLocalDateTime().year == 2010
- assert legacy.toOffsetDateTime().dayOfMonth == 3
- assert legacy.toZonedDateTime().zone == ZoneId.systemDefault()
- // end::to_jsr310_types[]
- }
-
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/src/test/groovy/DateTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/DateTest.groovy b/src/test/groovy/DateTest.groovy
deleted file mode 100644
index 3c2034d..0000000
--- a/src/test/groovy/DateTest.groovy
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy
-
-import java.text.SimpleDateFormat
-
-import static java.util.Calendar.*
-
-class DateTest extends GroovyTestCase {
- void testCalendarNextPrevious() {
- TimeZone tz = TimeZone.getTimeZone('GMT+00')
- Calendar c = getInstance(tz)
- c[HOUR_OF_DAY] = 6
- c[YEAR] = 2002
- c[MONTH] = FEBRUARY
- c[DATE] = 2
- c.clearTime()
- def formatter = new SimpleDateFormat('dd-MMM-yyyy', Locale.US)
- formatter.calendar.timeZone = tz
-
- assert formatter.format(c.previous().time) == '01-Feb-2002'
- assert formatter.format(c.time) == '02-Feb-2002'
- assert formatter.format(c.next().time) == '03-Feb-2002'
- def dates = (c.previous()..c.next()).collect{ formatter.format(it.time) }
- assert dates == ['01-Feb-2002', '02-Feb-2002', '03-Feb-2002']
- }
-
- void testDateNextPrevious() {
- def tz = TimeZone.default
- def x = new Date()
- def y = x + 2
- assert x < y
- def crossedDaylightSavingBoundary = tz.inDaylightTime(x) ^ tz.inDaylightTime(y)
- ++x
- --y
- if (!crossedDaylightSavingBoundary) assert x == y
- x += 2
- assert x > y
- }
-
- void testDateRange() {
- def today = new Date()
- def later = today + 3
- def expected = [today, today + 1, today + 2, today + 3]
- def list = []
- for (d in today..later) {
- list << d
- }
- assert list == expected
- }
-
- void testCalendarIndex() {
- Calendar c = new GregorianCalendar(2002, FEBRUARY, 2)
- assert c[MONTH] == FEBRUARY
- assert c[DAY_OF_WEEK] == SATURDAY
- }
-
- void testDateIndex() {
- Date d = new GregorianCalendar(2002, FEBRUARY, 2).time
- assert d[MONTH] == FEBRUARY
- assert d[DAY_OF_WEEK] == SATURDAY
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/src/test/groovy/DateTimeTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/DateTimeTest.groovy b/src/test/groovy/DateTimeTest.groovy
deleted file mode 100644
index db2e266..0000000
--- a/src/test/groovy/DateTimeTest.groovy
+++ /dev/null
@@ -1,821 +0,0 @@
-package groovy
-
-import java.text.SimpleDateFormat
-import java.time.*
-import java.time.chrono.JapaneseDate
-import java.time.temporal.ChronoField
-import java.time.temporal.ChronoUnit
-
-class DateTimeTest extends GroovyTestCase {
-
- void testDurationPlusMinusPositiveNegative() {
- def duration = Duration.ofSeconds(10)
- def longer = duration + 5
- def shorter = duration - 5
-
- assert longer.seconds == 15
- assert shorter.seconds == 5
- assert (++longer).seconds == 16
- assert (--shorter).seconds == 4
- }
-
- void testInstantPlusMinusPositiveNegative() {
- def epoch = Instant.ofEpochMilli(0)
-
- def twoSecPastEpoch = epoch + 2
- def oneSecPastEpoch = twoSecPastEpoch - 1
-
- assert oneSecPastEpoch.epochSecond == 1
- assert twoSecPastEpoch.epochSecond == 2
- assert (++twoSecPastEpoch).epochSecond == 3
- assert (--oneSecPastEpoch).epochSecond == 0
- }
-
- void testLocalDatePlusMinusPositiveNegative() {
- def epoch = LocalDate.of(1970, Month.JANUARY, 1)
-
- def twoDaysPastEpoch = epoch + 2
- def oneDayPastEpoch = twoDaysPastEpoch - 1
-
- assert oneDayPastEpoch.dayOfMonth == 2
- assert twoDaysPastEpoch.dayOfMonth == 3
- assert (++twoDaysPastEpoch).dayOfMonth == 4
- assert (--oneDayPastEpoch).dayOfMonth == 1
- }
-
- void testLocalDateTimePlusMinusPositiveNegative() {
- def epoch = LocalDateTime.of(1970, Month.JANUARY, 1, 0, 0, 0, 0)
-
- def twoSecsPastEpoch = epoch + 2
- def oneSecPastEpoch = twoSecsPastEpoch - 1
-
- assert oneSecPastEpoch.second == 1
- assert twoSecsPastEpoch.second == 2
- assert (++twoSecsPastEpoch).second == 3
- assert (--oneSecPastEpoch).second == 0
- }
-
- void testLocalTimePlusMinusPositiveNegative() {
- def epoch = LocalTime.of(0, 0, 0, 0)
-
- def twoSecsPastEpoch = epoch + 2
- def oneSecPastEpoch = twoSecsPastEpoch - 1
-
- assert oneSecPastEpoch.second == 1
- assert twoSecsPastEpoch.second == 2
- assert (++twoSecsPastEpoch).second == 3
- assert (--oneSecPastEpoch).second == 0
- }
-
- void testOffsetDateTimePlusMinusPositiveNegative() {
- def epoch = OffsetDateTime.of(LocalDateTime.of(1970, Month.JANUARY, 1, 0, 0, 0, 0),
- ZoneOffset.ofHours(0))
-
- def twoSecsPastEpoch = epoch + 2
- def oneSecPastEpoch = twoSecsPastEpoch - 1
-
- assert oneSecPastEpoch.second == 1
- assert twoSecsPastEpoch.second == 2
- assert (++twoSecsPastEpoch).second == 3
- assert (--oneSecPastEpoch).second == 0
- }
-
- void testOffsetTimePlusMinusPositiveNegative() {
- def epoch = OffsetTime.of(LocalTime.of(0, 0, 0, 0),
- ZoneOffset.ofHours(0))
-
- def twoSecsPastEpoch = epoch + 2
- def oneSecPastEpoch = twoSecsPastEpoch - 1
-
- assert oneSecPastEpoch.second == 1
- assert twoSecsPastEpoch.second == 2
- assert (++twoSecsPastEpoch).second == 3
- assert (--oneSecPastEpoch).second == 0
- }
-
- void testPeriodPlusMinusPositiveNegative() {
- def fortnight = Period.ofDays(14)
-
- def fortnightAndTwoDays = fortnight + 2
- def fortnightAndOneDay = fortnightAndTwoDays - 1
-
- assert fortnightAndOneDay.days == 15
- assert fortnightAndTwoDays.days == 16
- assert (++fortnightAndTwoDays).days == 17
- assert (--fortnightAndOneDay).days == 14
- }
-
- void testYearPlusMinusPositiveNegative() {
- def epoch = Year.of(1970)
-
- def twoYearsAfterEpoch = epoch + 2
- def oneYearAfterEpoch = twoYearsAfterEpoch - 1
-
- assert oneYearAfterEpoch.value == 1971
- assert twoYearsAfterEpoch.value == 1972
- assert (++twoYearsAfterEpoch).value == 1973
- assert (--oneYearAfterEpoch).value == 1970
- }
-
- void testYearMonthPlusMinusPositiveNegative() {
- def epoch = YearMonth.of(1970, Month.JANUARY)
-
- def twoMonthsAfterEpoch = epoch + 2
- def oneMonthAfterEpoch = twoMonthsAfterEpoch - 1
-
- assert oneMonthAfterEpoch.month == Month.FEBRUARY
- assert twoMonthsAfterEpoch.month == Month.MARCH
- assert (++twoMonthsAfterEpoch).month == Month.APRIL
- assert (--oneMonthAfterEpoch).month == Month.JANUARY
- }
-
- void testZonedDateTimePlusMinusPositiveNegative() {
- def epoch = ZonedDateTime.of(LocalDateTime.of(1970, Month.JANUARY, 1, 0, 0, 0, 0),
- ZoneId.systemDefault())
-
- def twoSecsPastEpoch = epoch + 2
- def oneSecPastEpoch = twoSecsPastEpoch - 1
-
- assert oneSecPastEpoch.second == 1
- assert twoSecsPastEpoch.second == 2
- assert (++twoSecsPastEpoch).second == 3
- assert (--oneSecPastEpoch).second == 0
- }
-
- void testDayOfWeekPlusMinus() {
- def mon = DayOfWeek.MONDAY
-
- assert mon + 4 == DayOfWeek.FRIDAY
- assert mon - 4 == DayOfWeek.THURSDAY
- }
-
- void testMonthPlusMinus() {
- def jan = Month.JANUARY
-
- assert jan + 4 == Month.MAY
- assert jan - 4 == Month.SEPTEMBER
- }
-
- void testDurationPositiveNegative() {
- def positiveDuration = Duration.ofSeconds(3)
- assert (-positiveDuration).seconds == -3
-
- def negativeDuration = Duration.ofSeconds(-5)
- assert (+negativeDuration).seconds == 5
- }
-
- void testDurationMultiplyDivide() {
- def duration = Duration.ofSeconds(60)
-
- assert (duration / 2).seconds == 30
- assert (duration * 2).seconds == 120
- }
-
- void testDurationIsPositiveIsNonnegativeIsNonpositive() {
- def pos = Duration.ofSeconds(10)
- assert pos.isPositive() == true
- assert pos.isNonpositive() == false
- assert pos.isNonnegative() == true
-
- def neg = Duration.ofSeconds(-10)
- assert neg.isPositive() == false
- assert neg.isNonpositive() == true
- assert neg.isNonnegative() == false
-
- assert Duration.ZERO.isPositive() == false
- assert Duration.ZERO.isNonpositive() == true
- assert Duration.ZERO.isNonnegative() == true
- }
-
- void testPeriodPositiveNegative() {
- def positivePeriod = Period.of(1,2,3)
- Period madeNegative = -positivePeriod
- assert madeNegative.years == -1 : "All Period fields should be made negative"
- assert madeNegative.months == -2
- assert madeNegative.days == -3
-
- def negativePeriod = Period.of(-1,2,-3)
- Period madePositive = +negativePeriod
- assert madePositive.years == 1 : "Negative Period fields should be made positive"
- assert madePositive.months == 2 : "Positive Period fields should remain positive"
- assert madePositive.days == 3
- }
-
- void testPeriodMultiply() {
- def period = Period.of(1,1,1)
- Period doublePeriod = period * 2
- assert doublePeriod.years == 2
- assert doublePeriod.months == 2
- assert doublePeriod.days == 2
- }
-
- void testPeriodIsPositiveIsNonnegativeIsNonpositive() {
- def pos = Period.ofDays(10)
- assert pos.isPositive() == true
- assert pos.isNonpositive() == false
- assert pos.isNonnegative() == true
-
- def neg = Period.ofDays(-10)
- assert neg.isPositive() == false
- assert neg.isNonpositive() == true
- assert neg.isNonnegative() == false
-
- assert Period.ZERO.isPositive() == false
- assert Period.ZERO.isNonpositive() == true
- assert Period.ZERO.isNonnegative() == true
- }
-
- void testTemporalGetAt() {
- def epoch = Instant.ofEpochMilli(0)
- assert epoch[ChronoField.INSTANT_SECONDS] == 0
- }
-
- void testTemporalAmountGetAt() {
- def duration = Duration.ofHours(10)
- assert duration[ChronoUnit.SECONDS] == 36_000
- }
-
- void testZoneOffsetGetAt() {
- def offset = ZoneOffset.ofTotalSeconds(360)
- assert offset[ChronoField.OFFSET_SECONDS] == 360
- }
-
- void testTemporalRightShift() {
- def epoch = Instant.ofEpochMilli(0)
- def dayAfterEpoch = epoch + (60 * 60 * 24)
- Duration instantDuration = epoch >> dayAfterEpoch
- assert instantDuration == Duration.ofDays(1)
- }
-
- void testLocalDateRightShift() {
- def localDate1 = LocalDate.of(2000, Month.JANUARY, 1)
- def localDate2 = localDate1.plusYears(2)
- Period localDatePeriod = localDate1 >> localDate2
- assert localDatePeriod.years == 2
- }
-
- void testYearRightShift() {
- def year1 = Year.of(2000)
- def year2 = Year.of(2018)
- Period yearPeriod = year1 >> year2
- assert yearPeriod.years == 18
- }
-
- void testYearMonthRightShift() {
- def yearMonth1 = YearMonth.of(2018, Month.JANUARY)
- def yearMonth2 = YearMonth.of(2018, Month.MARCH)
- Period yearMonthPeriod = yearMonth1 >> yearMonth2
- assert yearMonthPeriod.months == 2
- }
-
- void testRightShiftDifferentTypes() {
- try {
- LocalDate.now() >> LocalTime.now()
- fail('Should not be able to use right shift on different Temporal types.')
- } catch (e) {
- assert e instanceof GroovyRuntimeException
- }
- }
-
- void testUptoDifferentTypes() {
- try {
- LocalDate.now().upto(JapaneseDate.now().plus(1, ChronoUnit.MONTHS)) { d -> }
- fail('Cannot use upto() with two different Temporal types.')
- } catch (e) {
- assert e instanceof GroovyRuntimeException
- }
- }
-
- void testDowntoDifferentTypes() {
- try {
- LocalDate.now().downto(JapaneseDate.now().minus(1, ChronoUnit.MONTHS)) { d -> }
- fail('Cannot use downto() with two different argument types.')
- } catch (e) {
- assert e instanceof GroovyRuntimeException
- }
- }
-
- void testUptoSelfWithDefaultUnit() {
- def epoch = Instant.ofEpochMilli(0)
-
- int iterations = 0
- epoch.upto(epoch) {
- ++iterations
- assert it == epoch: 'upto closure should be provided with arg'
- }
- assert iterations == 1: 'Iterating upto same value should call closure once'
- }
-
- void testDowntoSelfWithDefaultUnit() {
- def epoch = Instant.ofEpochMilli(0)
- int iterations = 0
- epoch.downto(epoch) {
- ++iterations
- assert it == epoch: 'downto closure should be provided with arg'
- }
- assert iterations == 1: 'Iterating downto same value should call closure once'
- }
-
- void testUptoWithSecondsDefaultUnit() {
- def epoch = Instant.ofEpochMilli(0)
-
- int iterations = 0
- Instant end = null
- epoch.upto(epoch + 1) {
- ++iterations
- end = it
- }
- assert iterations == 2: 'Iterating upto Temporal+1 value should call closure twice'
- assert end.epochSecond == 1: 'Unexpected upto final value'
- }
-
- void testDowntoWithSecondsDefaultUnit() {
- def epoch = Instant.ofEpochMilli(0)
-
- int iterations = 0
- Instant end = null
- epoch.downto(epoch - 1) {
- ++iterations
- end = it
- }
- assert iterations == 2 : 'Iterating downto Temporal+1 value should call closure twice'
- assert end.epochSecond == -1 : 'Unexpected downto final value'
- }
-
- void testUptoWithYearsDefaultUnit() {
- def endYear = null
- Year.of(1970).upto(Year.of(1971)) { year -> endYear = year }
- assert endYear.value == 1971
- }
-
- void testDowntoWithYearsDefaultUnit() {
- def endYear = null
- Year.of(1971).downto(Year.of(1970)) { year -> endYear = year }
- assert endYear.value == 1970
- }
-
- void testUptoWithMonthsDefaultUnit() {
- def endYearMonth = null
- YearMonth.of(1970, Month.JANUARY).upto(YearMonth.of(1970, Month.FEBRUARY)) { yearMonth ->
- endYearMonth = yearMonth
- }
- assert endYearMonth.month == Month.FEBRUARY
- }
-
- void testDowntoWithMonthsDefaultUnit() {
- def endYearMonth = null
- YearMonth.of(1970, Month.FEBRUARY).downto(YearMonth.of(1970, Month.JANUARY)) { yearMonth ->
- endYearMonth = yearMonth
- }
- assert endYearMonth.month == Month.JANUARY
- }
-
- void testUptoWithDaysDefaultUnit() {
- def endLocalDate = null
- LocalDate.of(1970, Month.JANUARY, 1).upto(LocalDate.of(1970, Month.JANUARY, 2)) { localDate ->
- endLocalDate = localDate
- }
- assert endLocalDate.dayOfMonth == 2
- }
-
- void testDowntoWithDaysDefaultUnit() {
- def endLocalDate = null
- LocalDate.of(1970, Month.JANUARY, 2).downto(LocalDate.of(1970, Month.JANUARY, 1)) { localDate ->
- endLocalDate = localDate
- }
- assert endLocalDate.dayOfMonth == 1
- }
-
- void testUptoWithIllegalReversedArguments() {
- def epoch = Instant.ofEpochMilli(0)
- try {
- epoch.upto(epoch - 1) {
- fail('upto() should fail when passed earlier arg')
- }
- } catch (GroovyRuntimeException e) {
- }
- }
-
- void testDowntoWithIllegalReversedArguments() {
- def epoch = Instant.ofEpochMilli(0)
- try {
- epoch.downto(epoch + 1) {
- fail('downto() should fail when passed earlier arg')
- }
- } catch (GroovyRuntimeException e) {}
- }
-
- void testUptoSelfWithCustomUnit() {
- def today = LocalDate.now()
-
- int iterations = 0
- today.upto(today, ChronoUnit.MONTHS) {
- ++iterations
- assert it == today: 'upto closure should be provided with arg'
- }
- assert iterations == 1: 'Iterating upto same value should call closure once'
- }
-
- void testDowntoSelfWithCustomUnit() {
- def today = LocalDate.now()
-
- int iterations = 0
- today.downto(today, ChronoUnit.MONTHS) {
- ++iterations
- assert it == today: 'downto closure should be provided with arg'
- }
- assert iterations == 1: 'Iterating downto same value should call closure once'
- }
-
- void testUptoWithCustomUnit() {
- LocalDateTime from = LocalDateTime.of(2018, Month.FEBRUARY, 11, 22, 9, 34)
- // one second beyond one iteration
- LocalDateTime to = from.plusDays(1).plusSeconds(1)
-
- int iterations = 0
- LocalDateTime end = null
- from.upto(to, ChronoUnit.DAYS) {
- ++iterations
- end = it
- }
- assert iterations == 2
- assert end.dayOfMonth == 12: "Upto should have iterated by DAYS twice"
- }
-
- void testDowntoWithCustomUnit() {
- LocalDateTime from = LocalDateTime.of(2018, Month.FEBRUARY, 11, 22, 9, 34)
- // one day beyond one iteration
- LocalDateTime to = from.minusYears(1).minusDays(1)
-
- int iterations = 0
- LocalDateTime end = null
- from.downto(to, ChronoUnit.YEARS) {
- ++iterations
- end = it
- }
- assert iterations == 2
- assert end.year == 2017 : "Downto should have iterated by YEARS twice"
- }
-
- void testInstantToDateToCalendar() {
- def epoch = Instant.ofEpochMilli(0).plusNanos(999_999)
-
- def date = epoch.toDate()
- def cal = epoch.toCalendar()
- assert cal.time == date
- def sdf = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss.SSS')
- sdf.timeZone = TimeZone.getTimeZone('GMT')
- assert sdf.format(date) == '1970-01-01 00:00:00.000'
- }
-
- void testLocalDateToDateToCalendar() {
- def ld = LocalDate.of(2018, Month.FEBRUARY, 12)
-
- Calendar cal = ld.toCalendar()
- assert cal.get(Calendar.YEAR) == 2018
- assert cal.get(Calendar.MONTH) == Calendar.FEBRUARY
- assert cal.get(Calendar.DAY_OF_MONTH) == 12
- assert cal.timeZone.getID() == TimeZone.default.getID()
-
- Date date = ld.toDate()
- assert date.format('yyyy-MM-dd') == '2018-02-12'
- }
-
- void testLocalDateTimeToDateToCalendar() {
- def ldt = LocalDateTime.of(2018, Month.FEBRUARY, 12, 22, 26, 30, 123_999_999)
-
- Calendar cal = ldt.toCalendar()
- assert cal.get(Calendar.YEAR) == 2018
- assert cal.get(Calendar.MONTH) == Calendar.FEBRUARY
- assert cal.get(Calendar.DAY_OF_MONTH) == 12
- assert cal.get(Calendar.HOUR_OF_DAY) == 22
- assert cal.get(Calendar.MINUTE) == 26
- assert cal.get(Calendar.SECOND) == 30
- assert cal.get(Calendar.MILLISECOND) == 123
- assert cal.timeZone.getID() == TimeZone.default.getID()
-
- Date date = ldt.toDate()
- assert date.format('yyyy-MM-dd HH:mm:ss.SSS') == '2018-02-12 22:26:30.123'
- }
-
- void testLocalTimeToDateToCalendar() {
- def today = Calendar.instance
- def lt = LocalTime.of(22, 38, 20, 9_999_999)
-
- Calendar cal = lt.toCalendar()
- assert cal.get(Calendar.YEAR) == today.get(Calendar.YEAR) : 'LocalTime.toCalendar() should have current year'
- assert cal.get(Calendar.MONTH) == today.get(Calendar.MONTH) : 'LocalTime.toCalendar() should have current month'
- assert cal.get(Calendar.DAY_OF_MONTH) == today.get(Calendar.DAY_OF_MONTH) : 'LocalTime.toCalendar() should have current day'
- assert cal.get(Calendar.HOUR_OF_DAY) == 22
- assert cal.get(Calendar.MINUTE) == 38
- assert cal.get(Calendar.SECOND) == 20
- assert cal.get(Calendar.MILLISECOND) == 9
- assert cal.timeZone.getID() == TimeZone.default.getID()
-
- Date date = lt.toDate()
- assert date.format('HH:mm:ss.SSS') == '22:38:20.009'
- }
-
- void testOffsetDateTimeToDateToCalendar() {
- def ld = LocalDate.of(2018, Month.FEBRUARY, 12)
- def lt = LocalTime.of(22, 46, 10, 16_000_001)
- def offset = ZoneOffset.ofHours(-5)
- def odt = OffsetDateTime.of(ld, lt, offset)
-
- Calendar cal = odt.toCalendar()
- assert cal.get(Calendar.YEAR) == 2018
- assert cal.get(Calendar.MONTH) == Calendar.FEBRUARY
- assert cal.get(Calendar.DAY_OF_MONTH) == 12
- assert cal.get(Calendar.HOUR_OF_DAY) == 22
- assert cal.get(Calendar.MINUTE) == 46
- assert cal.get(Calendar.SECOND) == 10
- assert cal.get(Calendar.MILLISECOND) == 16
- assert cal.timeZone.getOffset(System.currentTimeMillis()) == -5 * 60 * 60 * 1000
-
- Date date = odt.toDate()
- def sdf = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss.SSS Z')
- sdf.timeZone = cal.timeZone
- assert sdf.format(date) == '2018-02-12 22:46:10.016 -0500'
- }
-
- void testOffsetTimeToDateToCalendar() {
- def lt = LocalTime.of(22, 53, 2, 909_900_009)
- def offset = ZoneOffset.ofHours(-4)
- def ot = OffsetTime.of(lt, offset)
- Calendar today = Calendar.getInstance(TimeZone.getTimeZone('GMT-4'))
-
- Calendar cal = ot.toCalendar()
- assert cal.get(Calendar.YEAR) == today.get(Calendar.YEAR) : 'OffsetTime.toCalendar() should have current year'
- assert cal.get(Calendar.MONTH) == today.get(Calendar.MONTH) : 'OffsetTime.toCalendar() should have current month'
- assert cal.get(Calendar.DAY_OF_MONTH) == today.get(Calendar.DAY_OF_MONTH) : 'OffsetTime.toCalendar() should have current day'
- assert cal.get(Calendar.HOUR_OF_DAY) == 22
- assert cal.get(Calendar.MINUTE) == 53
- assert cal.get(Calendar.SECOND) == 2
- assert cal.get(Calendar.MILLISECOND) == 909
- assert cal.timeZone.getOffset(System.currentTimeMillis()) == -4 * 60 * 60 * 1000
-
- Date date = ot.toDate()
- def sdf = new SimpleDateFormat('HH:mm:ss.SSS Z')
- sdf.timeZone = cal.timeZone
- assert sdf.format(date) == '22:53:02.909 -0400'
- }
-
- void testZonedDateTimeToDateToCalendar() {
- def ldt = LocalDateTime.of(2018, Month.FEBRUARY, 13, 20, 33, 57)
- def zoneId = ZoneId.ofOffset('GMT', ZoneOffset.ofHours(3))
- def zdt = ZonedDateTime.of(ldt, zoneId)
-
- Calendar cal = zdt.toCalendar()
- assert cal.get(Calendar.YEAR) == 2018
- assert cal.get(Calendar.MONTH) == Calendar.FEBRUARY
- assert cal.get(Calendar.DAY_OF_MONTH) == 13
- assert cal.get(Calendar.HOUR_OF_DAY) == 20
- assert cal.get(Calendar.MINUTE) == 33
- assert cal.get(Calendar.SECOND) == 57
- assert cal.get(Calendar.MILLISECOND) == 0
- assert cal.timeZone.getOffset(System.currentTimeMillis()) == 3 * 60 * 60 * 1000
-
- Date date = zdt.toDate()
- def sdf = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss.SSS Z')
- sdf.timeZone = cal.timeZone
- assert sdf.format(date) == '2018-02-13 20:33:57.000 +0300'
- }
-
- void testZoneOffsetExtensionProperties() {
- def offset = ZoneOffset.ofHoursMinutesSeconds(3,4,5)
- assert offset.hours == 3
- assert offset.minutes == 4
- assert offset.seconds == 5
-
- def negOffset = ZoneOffset.ofHoursMinutesSeconds(-1, -2, -3)
- assert negOffset.hours == -1
- assert negOffset.minutes == -2
- assert negOffset.seconds == -3
- }
-
- void testZoneOffsetToZimeZone() {
- TimeZone utcTz = ZoneOffset.UTC.toTimeZone()
- assert utcTz.getID() == 'GMT'
-
- TimeZone noSecsTz = ZoneOffset.ofHoursMinutes(1, 30).toTimeZone()
- assert noSecsTz.getID() == 'GMT+01:30'
-
- TimeZone secsTz = ZoneOffset.ofHoursMinutesSeconds(-4, -15, -30).toTimeZone()
- assert secsTz.getID() == 'GMT-04:15'
- }
-
- void testZoneIdExtensionProperties() {
- def offset = ZoneOffset.ofHours(7)
- def zoneId = ZoneId.ofOffset('GMT', offset)
-
- assert zoneId.offset.totalSeconds == offset.totalSeconds
- assert zoneId.getOffset(Instant.now()).totalSeconds == offset.totalSeconds
- assert zoneId.shortName == 'GMT+07:00'
- assert zoneId.fullName == 'GMT+07:00'
-
- ZoneId ny = ZoneId.of('America/New_York')
- assert ny.getShortName(Locale.US) == 'ET'
- assert ny.getFullName(Locale.US) == 'Eastern Time'
- }
-
- void testZoneIdToTimeZone() {
- ZoneId ny = ZoneId.of('America/New_York')
-
- assert ny.toTimeZone() == TimeZone.getTimeZone(ny)
- }
-
- void testYearExtensionProperties() {
- def year = Year.of(2009)
- assert year.era == 1
- assert year.yearOfEra == 2009
- }
-
- void testDayOfWeekExtensionProperties() {
- assert DayOfWeek.SUNDAY.weekend
- assert DayOfWeek.MONDAY.weekday
- }
-
- void testYear_Month_leftShift() {
- def a = Year.now()
- def b = Month.JULY
-
- YearMonth x = a << b
- YearMonth y = b << a
- assert x == y
- }
-
- void testYear_MonthDay_leftShift() {
- def a = Year.now()
- def b = MonthDay.now()
-
- LocalDate x = a << b
- LocalDate y = b << a
- assert x == y
- }
-
- void testMonthDay_leftShift() {
- LocalDate d = MonthDay.of(Month.FEBRUARY, 13) << 2018
- assert d.year == 2018
- assert d.month == Month.FEBRUARY
- assert d.dayOfMonth == 13
- }
-
- void testMonth_leftShift() {
- MonthDay md = Month.JANUARY << 10
- assert md.month == Month.JANUARY
- assert md.dayOfMonth == 10
- }
-
- void testLocalDate_LocalTime_leftShift() {
- def a = LocalDate.now()
- def b = LocalTime.now()
-
- LocalDateTime x = a << b
- LocalDateTime y = b << a
- assert x == y
- }
-
- void testLocalDate_OffsetTime_leftShift() {
- def a = LocalDate.now()
- def b = OffsetTime.now()
-
- OffsetDateTime x = a << b
- OffsetDateTime y = b << a
- assert x == y
- }
-
- void testLocalDateTime_ZoneOffset_leftShift() {
- def a = LocalDateTime.now()
- def b = ZoneOffset.ofHours(5)
-
- OffsetDateTime x = a << b
- OffsetDateTime y = b << a
- assert x == y
- }
-
- void testLocalDateTime_ZoneId_leftShift() {
- def a = LocalDateTime.now()
- def b = ZoneId.systemDefault()
-
- ZonedDateTime x = a << b
- ZonedDateTime y = b << a
- assert x == y
- }
-
- void testLocalTime_ZoneOffset_leftShift() {
- def a = LocalTime.now()
- def b = ZoneOffset.ofHours(5)
-
- OffsetTime x = a << b
- OffsetTime y = b << a
- assert x == y
- }
-
- void testLocalDateTimeClearTime() {
- def d = LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 9, 10, 100_032))
- d = d.clearTime()
-
- assert d.hour == 0
- assert d.minute == 0
- assert d.second == 0
- assert d.nano == 0
- }
-
- void testOffsetDateTimeClearTime() {
- def offset = ZoneOffset.ofHours(-1)
- def d = OffsetDateTime.of(LocalDate.now(), LocalTime.of(8, 9, 10, 100_032), offset)
- d = d.clearTime()
-
- assert d.hour == 0
- assert d.minute == 0
- assert d.second == 0
- assert d.nano == 0
- assert d.offset == offset : 'cleartTime() should not change offset'
- }
-
- void testZonedDateTimeClearTime() {
- def zone = ZoneId.of('America/New_York')
- def d = ZonedDateTime.of(LocalDate.now(), LocalTime.of(8, 9, 10, 100_032), zone)
- d = d.clearTime()
-
- assert d.hour == 0
- assert d.minute == 0
- assert d.second == 0
- assert d.nano == 0
- assert d.zone == zone : 'cleartTime() should not change zone'
- }
-
- void testFormatByPattern() {
- def zone = ZoneId.of('America/New_York')
- def offset = ZoneOffset.ofHours(2)
-
- LocalDate ld = LocalDate.of(2018, Month.FEBRUARY, 13)
- LocalTime lt = LocalTime.of(3,4,5,6_000_000)
- LocalDateTime ldt = LocalDateTime.of(ld, lt)
- OffsetTime ot = OffsetTime.of(lt, offset)
- OffsetDateTime odt = OffsetDateTime.of(ldt, offset)
- ZonedDateTime zdt = ZonedDateTime.of(ldt, zone)
-
- assert ld.format('yyyy-MM-dd') == '2018-02-13'
- assert lt.format('HH:mm:ss.SSS') == '03:04:05.006'
- assert ldt.format('yyyy-MM-dd HH:mm:ss.SSS') == '2018-02-13 03:04:05.006'
- assert ot.format('HH:mm:ss.SSS Z') == '03:04:05.006 +0200'
- assert odt.format('yyyy-MM-dd HH:mm:ss.SSS Z') == '2018-02-13 03:04:05.006 +0200'
- assert zdt.format('yyyy-MM-dd HH:mm:ss.SSS VV') == '2018-02-13 03:04:05.006 America/New_York'
- }
-
- void testLocalDateParse() {
- LocalDate ld = LocalDate.parse('2018-02-15', 'yyyy-MM-dd')
- assert [ld.year, ld.month, ld.dayOfMonth] == [2018, Month.FEBRUARY, 15]
- }
-
- void testLocalDateTimeParse() {
- LocalDateTime ldt = LocalDateTime.parse('2018-02-15 21:43:03.002', 'yyyy-MM-dd HH:mm:ss.SSS')
- assert [ldt.year, ldt.month, ldt.dayOfMonth] == [2018, Month.FEBRUARY, 15]
- assert [ldt.hour, ldt.minute, ldt.second] == [21, 43, 03]
- assert ldt.nano == 2 * 1e6
- }
-
- void testLocalTimeParse() {
- LocalTime lt = LocalTime.parse('21:43:03.002', 'HH:mm:ss.SSS')
- assert [lt.hour, lt.minute, lt.second] == [21, 43, 03]
- assert lt.nano == 2 * 1e6
- }
-
- void testOffsetDateTimeParse() {
- OffsetDateTime odt = OffsetDateTime.parse('2018-02-15 21:43:03.002 -00', 'yyyy-MM-dd HH:mm:ss.SSS X')
- assert [odt.year, odt.month, odt.dayOfMonth] == [2018, Month.FEBRUARY, 15]
- assert [odt.hour, odt.minute, odt.second] == [21, 43, 03]
- assert odt.nano == 2 * 1e6
- assert odt.offset.totalSeconds == 0
- }
-
- void testOffsetTimeParse() {
- OffsetTime ot = OffsetTime.parse('21:43:03.002 -00', 'HH:mm:ss.SSS X')
- assert [ot.hour, ot.minute, ot.second] == [21, 43, 03]
- assert ot.nano == 2 * 1e6
- assert ot.offset.totalSeconds == 0
- }
-
- void testZonedDateTimeParse() {
- ZonedDateTime zdt = ZonedDateTime.parse('2018-02-15 21:43:03.002 UTC', 'yyyy-MM-dd HH:mm:ss.SSS z')
- assert [zdt.year, zdt.month, zdt.dayOfMonth] == [2018, Month.FEBRUARY, 15]
- assert [zdt.hour, zdt.minute, zdt.second] == [21, 43, 03]
- assert zdt.nano == 2 * 1e6
- }
-
- void testPeriodBetweenYears() {
- def period = Period.between(Year.of(2000), Year.of(2010))
- assert period.years == 10
- assert period.months == 0
- assert period.days == 0
- }
-
- void testPeriodBetweenYearMonths() {
- def period = Period.between(YearMonth.of(2018, Month.MARCH), YearMonth.of(2016, Month.APRIL))
-
- assert period.years == -1
- assert period.months == -11
- assert period.days == 0
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/src/test/java/org/codehaus/groovy/runtime/DateGroovyMethodsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/codehaus/groovy/runtime/DateGroovyMethodsTest.java b/src/test/java/org/codehaus/groovy/runtime/DateGroovyMethodsTest.java
deleted file mode 100644
index c182b12..0000000
--- a/src/test/java/org/codehaus/groovy/runtime/DateGroovyMethodsTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.codehaus.groovy.runtime;
-
-import org.junit.Test;
-
-import java.sql.Timestamp;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.time.*;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.TimeZone;
-
-import static org.junit.Assert.assertEquals;
-
-public class DateGroovyMethodsTest {
- @Test
- public void minus() throws ParseException {
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
- assertEquals("20171231", sdf.format(DateGroovyMethods.minus(sdf.parse("20180101"), 1)));
- }
-
- @Test
- public void plus() throws ParseException {
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
- assertEquals("20180101", sdf.format(DateGroovyMethods.plus(new Timestamp(sdf.parse("20171231").getTime()), 1)));
- }
-
- @Test
- public void next() throws ParseException {
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
- Calendar calendar = Calendar.getInstance();
- calendar.setTime(sdf.parse("20171231"));
- assertEquals("20180101", sdf.format(DateGroovyMethods.next(calendar).getTime()));
- }
-
- @Test
- public void previous() throws ParseException {
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
- Calendar calendar = Calendar.getInstance();
- calendar.setTime(sdf.parse("20180101"));
- assertEquals("20171231", sdf.format(DateGroovyMethods.previous(calendar).getTime()));
- }
-
- @Test
- public void calendarConversionsDefaultTimeZone() throws ParseException {
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss SSS");
- Calendar calendar = Calendar.getInstance();
- calendar.setTime(sdf.parse("20180115 153256 001"));
-
- LocalDate expectedLocalDate = LocalDate.of(2018, Month.JANUARY, 15);
- LocalTime expectedLocalTime = LocalTime.of(15, 32, 56, 1_000_000);
- LocalDateTime expectedLocalDateTime = LocalDateTime.of(expectedLocalDate, expectedLocalTime);
-
- assertEquals("DayOfWeek", DayOfWeek.MONDAY, DateGroovyMethods.toDayOfWeek(calendar));
- assertEquals("Month", Month.JANUARY, DateGroovyMethods.toMonth(calendar));
- assertEquals("MonthDay", MonthDay.of(Month.JANUARY, 15), DateGroovyMethods.toMonthDay(calendar));
- assertEquals("YearMonth", YearMonth.of(2018, Month.JANUARY), DateGroovyMethods.toYearMonth(calendar));
- assertEquals("Year", Year.of(2018), DateGroovyMethods.toYear(calendar));
- assertEquals("LocalDate", expectedLocalDate, DateGroovyMethods.toLocalDate(calendar));
- assertEquals("LocalTime", expectedLocalTime, DateGroovyMethods.toLocalTime(calendar));
- assertEquals("LocalDateTime", expectedLocalDateTime, DateGroovyMethods.toLocalDateTime(calendar));
- assertEquals("OffsetTime", expectedLocalTime, DateGroovyMethods.toOffsetTime(calendar).toLocalTime());
- assertEquals("OffsetDateTime", expectedLocalDateTime,
- DateGroovyMethods.toOffsetDateTime(calendar).toLocalDateTime());
- assertEquals("ZonedDateTime", expectedLocalDateTime,
- DateGroovyMethods.toZonedDateTime(calendar).toLocalDateTime());
- }
-
- @Test
- public void calendarConversionsDifferingTimeZones() throws ParseException {
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss SSS");
- Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC+0"));
- calendar.setTime(sdf.parse("20180115 153256 001"));
- }
-
- @Test
- public void sameCalendarAndDateConvertIdentically() throws ParseException {
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss SSS");
- Date date = sdf.parse("20180115 153256 001");
- Calendar calendar = Calendar.getInstance();
- calendar.setTime(date);
-
- assertEquals("DayOfWeek", DateGroovyMethods.toDayOfWeek(calendar), DateGroovyMethods.toDayOfWeek(date));
- assertEquals("Month", DateGroovyMethods.toMonth(calendar), DateGroovyMethods.toMonth(date));
- assertEquals("MonthDay", DateGroovyMethods.toMonthDay(calendar), DateGroovyMethods.toMonthDay(date));
- assertEquals("YearMonth", DateGroovyMethods.toYearMonth(calendar), DateGroovyMethods.toYearMonth(date));
- assertEquals("Year", DateGroovyMethods.toYear(calendar), DateGroovyMethods.toYear(date));
- assertEquals("LocalDate", DateGroovyMethods.toLocalDate(calendar), DateGroovyMethods.toLocalDate(date));
- assertEquals("LocalTime", DateGroovyMethods.toLocalTime(calendar), DateGroovyMethods.toLocalTime(date));
- assertEquals("LocalDateTime", DateGroovyMethods.toLocalDate(calendar), DateGroovyMethods.toLocalDate(date));
- assertEquals("OffsetTime", DateGroovyMethods.toOffsetTime(calendar), DateGroovyMethods.toOffsetTime(date));
- assertEquals("OffsetDateTime",
- DateGroovyMethods.toOffsetDateTime(calendar), DateGroovyMethods.toOffsetDateTime(date));
- assertEquals("ZonedDateTime",
- DateGroovyMethods.toZonedDateTime(calendar), DateGroovyMethods.toZonedDateTime(date));
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/src/test/org/codehaus/groovy/runtime/DateGDKTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/runtime/DateGDKTest.groovy b/src/test/org/codehaus/groovy/runtime/DateGDKTest.groovy
deleted file mode 100644
index 2c27878..0000000
--- a/src/test/org/codehaus/groovy/runtime/DateGDKTest.groovy
+++ /dev/null
@@ -1,275 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.runtime
-
-import java.text.DateFormat
-import java.text.SimpleDateFormat
-
-/**
- * @author tnichols
- * @author Paul King
- */
-class DateGDKTest extends GroovyTestCase {
-
- void testGDKDateMethods() {
- Locale defaultLocale = Locale.default
- TimeZone defaultTZ = TimeZone.default
- try {
- Locale locale = Locale.GERMANY
- Locale.setDefault locale // set this otherwise the test will fail if your locale isn't the same
- TimeZone.setDefault TimeZone.getTimeZone('Europe/Berlin')
-
- Date d = new Date(0)
-
- assertEquals '1970-01-01', d.format('yyyy-MM-dd')
- assertEquals '01/01/1970', d.format('dd/MM/yyyy', TimeZone.getTimeZone('GMT'))
- assertEquals DateFormat.getDateInstance(DateFormat.SHORT, locale).format(d), d.dateString
- assertEquals '01.01.70', d.dateString
- assertEquals DateFormat.getTimeInstance(DateFormat.MEDIUM, locale).format(d), d.timeString
- assertEquals '01:00:00', d.timeString
- assertEquals DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale).format(d), d.dateTimeString
- } finally {
- Locale.default = defaultLocale
- TimeZone.setDefault defaultTZ
- }
- }
-
- void testStaticParse() {
- TimeZone defaultTZ = TimeZone.default
- try {
- TimeZone.setDefault TimeZone.getTimeZone('Etc/GMT')
-
- Date d = Date.parse('yy/MM/dd hh:mm:ss', '70/01/01 00:00:00')
-
- assertEquals 0, d.time
- } finally {
- TimeZone.setDefault defaultTZ
- }
- }
-
- void testParseWithTimeZone() {
- TimeZone defaultTZ = TimeZone.default
- try {
- TimeZone.default = TimeZone.getTimeZone("GMT+05")
- def tz = TimeZone.getTimeZone("GMT+03")
-
- def newYear = Date.parse('yyyy-MM-dd', "2015-01-01", tz)
-
- assert newYear.toString() == 'Thu Jan 01 02:00:00 GMT+05:00 2015'
- } finally {
- TimeZone.default = defaultTZ
- }
- }
-
- void testRoundTrip() {
- Date d = new Date()
- String pattern = 'dd MMM yyyy, hh:mm:ss,SSS a z'
- String out = d.format(pattern)
-
- Date d2 = Date.parse(pattern, out)
-
- assertEquals d.time, d2.time
- }
-
- void testCalendarTimeZone() {
- Locale defaultLocale = Locale.default
- TimeZone defaultTZ = TimeZone.default
- try {
- Locale locale = Locale.UK
- Locale.setDefault locale // set this otherwise the test will fail if your locale isn't the same
- TimeZone.setDefault TimeZone.getTimeZone('Etc/GMT')
-
- def offset = 8
- def notLocalTZ = TimeZone.getTimeZone("GMT-$offset")
- Calendar cal = Calendar.getInstance(notLocalTZ)
- def offsetHr = cal.format('HH') as int
- def hr = cal.time.format('HH') as int
- if (hr < offset) hr += 24 // if GMT hr has rolled over to next day
-
- // offset should be 8 hours behind GMT:
- assertEquals(offset, hr - offsetHr)
- } finally {
- Locale.default = defaultLocale
- TimeZone.setDefault defaultTZ
- }
- }
-
- static SimpleDateFormat f = new SimpleDateFormat('MM/dd/yyyy')
-
- static java.sql.Date sqlDate(String s) {
- return new java.sql.Date(f.parse(s).time)
- }
-
- void testMinusDates() {
- assertEquals(10, f.parse("1/11/2007") - f.parse("1/1/2007"))
- assertEquals(-10, f.parse("1/1/2007") - f.parse("1/11/2007"))
- assertEquals(375, f.parse("1/11/2008") - f.parse("1/1/2007"))
- assertEquals(356, f.parse("1/1/2008") - f.parse("1/10/2007"))
- assertEquals(1, f.parse("7/12/2007") - f.parse("7/11/2007"))
- assertEquals(0, f.parse("1/1/2007") - f.parse("1/1/2007"))
- assertEquals(-1, f.parse("12/31/2007") - f.parse("1/1/2008"))
- assertEquals(365, f.parse("1/1/2008") - f.parse("1/1/2007"))
- assertEquals(36525, f.parse("1/1/2008") - f.parse("1/1/1908"))
-
- assertEquals(1, sqlDate("7/12/2007") - f.parse("7/11/2007"))
- assertEquals(0, sqlDate("1/1/2007") - sqlDate("1/1/2007"))
- assertEquals(-1, f.parse("12/31/2007") - sqlDate("1/1/2008"))
- assertEquals(365, sqlDate("1/1/2008") - sqlDate("1/1/2007"))
- assertEquals(36525, f.parse("1/1/2008") - sqlDate("1/1/1908"))
-
- Date d = f.parse("7/4/1776");
- assertEquals(44, (d + 44) - d);
-
- java.sql.Date sqld = sqlDate("7/4/1776");
- assertEquals(-4444, (sqld - 4444) - sqld);
- }
-
- /** GROOVY-3374 */
- void testClearTime() {
- def now = new Date()
- def calendarNow = Calendar.getInstance()
-
- now.clearTime()
- calendarNow.clearTime()
-
- assert now == calendarNow.time
-
- assert calendarNow.get(Calendar.HOUR) == 0
- assert calendarNow.get(Calendar.MINUTE) == 0
- assert calendarNow.get(Calendar.SECOND) == 0
- assert calendarNow.get(Calendar.MILLISECOND) == 0
- }
-
- /** GROOVY-4789 */
- void testStaticParseToStringDate() {
- TimeZone tz = TimeZone.getDefault()
- try {
- TimeZone.setDefault(TimeZone.getTimeZone("GMT"))
-
- Date date = new Date(0)
- String toStringRepresentation = date.toString()
-
- assert toStringRepresentation == "Thu Jan 01 00:00:00 GMT 1970"
- assert date == Date.parseToStringDate(toStringRepresentation)
- }
- finally {
- TimeZone.setDefault(tz)
- }
- }
-
- void test_Upto_Date_ShouldExecuteClosureForEachDayUpToDate() {
- Date startDate = new Date()
- List expectedResults = [startDate, startDate + 1, startDate + 2]
-
- List actualResults = []
-
- startDate.upto(startDate + 2){
- actualResults << it
- }
-
- assert actualResults == expectedResults
- }
-
- void test_upto_Date_ShouldNotAcceptToDatesLessThanStartDate() {
- Date startDate = new Date()
- Date toDate = new Date(startDate.getTime() - 1L)
-
- shouldFail(GroovyRuntimeException) {
- startDate.upto(toDate){}
- }
- }
-
- void test_downto_Date_ShouldExecuteClosureForEachDayDownToDate() {
- Date startDate = new Date()
- List expectedResults = [startDate, startDate - 1, startDate - 2]
-
- List actualResults = []
- startDate.downto(startDate - 2){
- actualResults << it
- }
-
- assert actualResults == expectedResults
- }
-
- void test_downto_Date_ShouldNotAcceptToDatesGreaterThanStartDate() {
- Date startDate = new Date()
- Date toDate = new Date(startDate.getTime() + 1L)
-
- shouldFail(GroovyRuntimeException) {
- startDate.downto(toDate){}
- }
- }
-
- void test_upto_Calendar_ShouldExecuteClosureForEachDayUpToDate() {
- Calendar startDate = Calendar.getInstance()
- Calendar toDate = startDate.clone()
- toDate.add(Calendar.DATE, 1)
- List expectedResults = [startDate, toDate]
-
- List actualResults = []
- startDate.upto(toDate){
- actualResults << it
- }
-
- assert actualResults == expectedResults
- }
-
- void test_upto_Calendar_ShouldNotAcceptToDatesLessThanStartDate() {
- Calendar startDate = Calendar.getInstance()
- Calendar toDate = startDate.clone()
- toDate.add(Calendar.MILLISECOND, -1)
-
- shouldFail(GroovyRuntimeException) {
- startDate.upto(toDate){}
- }
- }
-
- void test_downto_Calendar_ShouldExecuteClosureForEachDayDownToDate() {
- Calendar startDate = Calendar.getInstance()
- Calendar toDate = startDate.clone()
- toDate.add(Calendar.DATE, -1)
- List expectedResults = [startDate, toDate]
-
- List actualResults = []
- startDate.downto(toDate){
- actualResults << it
- }
-
- assert actualResults == expectedResults
- }
-
- void test_downto_Calendar_ShouldNotAcceptToDatesGreaterThanStartDate() {
- Calendar startDate = Calendar.getInstance()
- Calendar toDate = startDate.clone()
- toDate.add(Calendar.MILLISECOND, 1)
-
- shouldFail(GroovyRuntimeException) {
- startDate.downto(toDate){}
- }
- }
-
- void testCopyWith() {
- Date febOne1970 = new Date(70, 1, 1)
- Date aprilSix = febOne1970.copyWith(dayOfMonth: 6, month: Calendar.APRIL)
- assertEquals '1970-04-06', aprilSix.format('yyyy-MM-dd')
- Map updates = [:]
- updates[Calendar.DAY_OF_MONTH] = 4
- Date aprilFour = aprilSix.copyWith(updates)
- assertEquals '1970-04-04', aprilFour.format('yyyy-MM-dd')
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-datetime/build.gradle
----------------------------------------------------------------------
diff --git a/subprojects/groovy-datetime/build.gradle b/subprojects/groovy-datetime/build.gradle
new file mode 100644
index 0000000..92326c7
--- /dev/null
+++ b/subprojects/groovy-datetime/build.gradle
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+dependencies {
+ compile rootProject
+ testCompile project(':groovy-test')
+ testCompile project(':groovy-dateutil')
+}
+
+task moduleDescriptor(type: org.codehaus.groovy.gradle.WriteExtensionDescriptorTask) {
+ extensionClasses = 'org.apache.groovy.datetime.extensions.DateTimeExtensions'
+ staticExtensionClasses = 'org.apache.groovy.datetime.extensions.DateTimeStaticExtensions'
+}
+compileJava.dependsOn moduleDescriptor
[2/7] groovy git commit: move datetime extensions to their own module
Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-datetime/src/main/java/org/apache/groovy/datetime/extensions/DateTimeStaticExtensions.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-datetime/src/main/java/org/apache/groovy/datetime/extensions/DateTimeStaticExtensions.java b/subprojects/groovy-datetime/src/main/java/org/apache/groovy/datetime/extensions/DateTimeStaticExtensions.java
new file mode 100644
index 0000000..4b5865f
--- /dev/null
+++ b/subprojects/groovy-datetime/src/main/java/org/apache/groovy/datetime/extensions/DateTimeStaticExtensions.java
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.datetime.extensions;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Period;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * This class defines new static extension methods which appear on normal JDK
+ * Date/Time API (java.time) classes inside the Groovy environment.
+ */
+public class DateTimeStaticExtensions {
+
+ // Static methods only
+ private DateTimeStaticExtensions() {
+ }
+
+ /**
+ * Parse text into a {@link java.time.LocalDate} using the provided pattern.
+ *
+ * @param type placeholder variable used by Groovy categories; ignored for default static methods
+ * @param text String to be parsed to create the date instance
+ * @param pattern pattern used to parse the text
+ * @return a LocalDate representing the parsed text
+ * @throws java.lang.IllegalArgumentException if the pattern is invalid
+ * @throws java.time.format.DateTimeParseException if the text cannot be parsed
+ * @see java.time.format.DateTimeFormatter
+ * @see java.time.LocalDate#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
+ * @since 3.0
+ */
+ public static LocalDate parse(final LocalDate type, CharSequence text, String pattern) {
+ return LocalDate.parse(text, DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Parse text into a {@link java.time.LocalDateTime} using the provided pattern.
+ *
+ * @param type placeholder variable used by Groovy categories; ignored for default static methods
+ * @param text String to be parsed to create the date instance
+ * @param pattern pattern used to parse the text
+ * @return a LocalDateTime representing the parsed text
+ * @throws java.lang.IllegalArgumentException if the pattern is invalid
+ * @throws java.time.format.DateTimeParseException if the text cannot be parsed
+ * @see java.time.format.DateTimeFormatter
+ * @see java.time.LocalDateTime#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
+ * @since 3.0
+ */
+ public static LocalDateTime parse(final LocalDateTime type, CharSequence text, String pattern) {
+ return LocalDateTime.parse(text, DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Parse text into a {@link java.time.LocalTime} using the provided pattern.
+ *
+ * @param type placeholder variable used by Groovy categories; ignored for default static methods
+ * @param text String to be parsed to create the date instance
+ * @param pattern pattern used to parse the text
+ * @return a LocalTime representing the parsed text
+ * @throws java.lang.IllegalArgumentException if the pattern is invalid
+ * @throws java.time.format.DateTimeParseException if the text cannot be parsed
+ * @see java.time.format.DateTimeFormatter
+ * @see java.time.LocalTime#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
+ * @since 3.0
+ */
+ public static LocalTime parse(final LocalTime type, CharSequence text, String pattern) {
+ return LocalTime.parse(text, DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Parse text into a {@link java.time.MonthDay} using the provided pattern.
+ *
+ * @param type placeholder variable used by Groovy categories; ignored for default static methods
+ * @param text String to be parsed to create the date instance
+ * @param pattern pattern used to parse the text
+ * @return a MonthDay representing the parsed text
+ * @throws java.lang.IllegalArgumentException if the pattern is invalid
+ * @throws java.time.format.DateTimeParseException if the text cannot be parsed
+ * @see java.time.format.DateTimeFormatter
+ * @see java.time.MonthDay#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
+ * @since 3.0
+ */
+ public static MonthDay parse(final MonthDay type, CharSequence text, String pattern) {
+ return MonthDay.parse(text, DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Parse text into an {@link java.time.OffsetDateTime} using the provided pattern.
+ *
+ * @param type placeholder variable used by Groovy categories; ignored for default static methods
+ * @param text String to be parsed to create the date instance
+ * @param pattern pattern used to parse the text
+ * @return an OffsetDateTime representing the parsed text
+ * @throws java.lang.IllegalArgumentException if the pattern is invalid
+ * @throws java.time.format.DateTimeParseException if the text cannot be parsed
+ * @see java.time.format.DateTimeFormatter
+ * @see java.time.OffsetDateTime#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
+ * @since 3.0
+ */
+ public static OffsetDateTime parse(final OffsetDateTime type, CharSequence text, String pattern) {
+ return OffsetDateTime.parse(text, DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Parse text into an {@link java.time.OffsetTime} using the provided pattern.
+ *
+ * @param type placeholder variable used by Groovy categories; ignored for default static methods
+ * @param text String to be parsed to create the date instance
+ * @param pattern pattern used to parse the text
+ * @return an OffsetTime representing the parsed text
+ * @throws java.lang.IllegalArgumentException if the pattern is invalid
+ * @throws java.time.format.DateTimeParseException if the text cannot be parsed
+ * @see java.time.format.DateTimeFormatter
+ * @see java.time.OffsetTime#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
+ * @since 3.0
+ */
+ public static OffsetTime parse(final OffsetTime type, CharSequence text, String pattern) {
+ return OffsetTime.parse(text, DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Parse text into a {@link java.time.Year} using the provided pattern.
+ *
+ * @param type placeholder variable used by Groovy categories; ignored for default static methods
+ * @param text String to be parsed to create the date instance
+ * @param pattern pattern used to parse the text
+ * @return a Year representing the parsed text
+ * @throws java.lang.IllegalArgumentException if the pattern is invalid
+ * @throws java.time.format.DateTimeParseException if the text cannot be parsed
+ * @see java.time.format.DateTimeFormatter
+ * @see java.time.Year#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
+ * @since 3.0
+ */
+ public static Year parse(final Year type, CharSequence text, String pattern) {
+ return Year.parse(text, DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Parse text into a {@link java.time.YearMonth} using the provided pattern.
+ *
+ * @param type placeholder variable used by Groovy categories; ignored for default static methods
+ * @param text String to be parsed to create the date instance
+ * @param pattern pattern used to parse the text
+ * @return a YearMonth representing the parsed text
+ * @throws java.lang.IllegalArgumentException if the pattern is invalid
+ * @throws java.time.format.DateTimeParseException if the text cannot be parsed
+ * @see java.time.format.DateTimeFormatter
+ * @see java.time.YearMonth#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
+ * @since 3.0
+ */
+ public static YearMonth parse(final YearMonth type, CharSequence text, String pattern) {
+ return YearMonth.parse(text, DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Parse text into a {@link java.time.ZonedDateTime} using the provided pattern.
+ *
+ * @param type placeholder variable used by Groovy categories; ignored for default static methods
+ * @param text String to be parsed to create the date instance
+ * @param pattern pattern used to parse the text
+ * @return a ZonedDateTime representing the parsed text
+ * @throws java.lang.IllegalArgumentException if the pattern is invalid
+ * @throws java.time.format.DateTimeParseException if the text cannot be parsed
+ * @see java.time.format.DateTimeFormatter
+ * @see java.time.ZonedDateTime#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
+ * @since 3.0
+ */
+ public static ZonedDateTime parse(final ZonedDateTime type, CharSequence text, String pattern) {
+ return ZonedDateTime.parse(text, DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Returns the {@link java.time.ZoneOffset} currently associated with the system default {@link java.time.ZoneId}.
+ *
+ * @param type placeholder variable used by Groovy categories; ignored for default static methods
+ * @return a ZoneOffset
+ * @see java.time.ZoneId#systemDefault()
+ * @since 3.0
+ */
+ public static ZoneOffset systemDefault(final ZoneOffset type) {
+ return DateTimeExtensions.getOffset(ZoneId.systemDefault());
+ }
+
+ /**
+ * Obtains a Period consisting of the number of years between two {@link java.time.Year} instances.
+ * The months and days of the Period will be zero.
+ * The result of this method can be a negative period if the end is before the start.
+ *
+ * @param type placeholder variable used by Groovy categories; ignored for default static methods
+ * @param startInclusive the start {@link java.time.Year}, inclusive, not null
+ * @param endExclusive the end {@link java.time.Year}, exclusive, not null
+ * @return a Period between the years
+ * @see java.time.Period#between(LocalDate, LocalDate)
+ */
+ public static Period between(final Period type, Year startInclusive, Year endExclusive) {
+ MonthDay now = MonthDay.of(Month.JANUARY, 1);
+ return Period.between(
+ DateTimeExtensions.leftShift(startInclusive, now),
+ DateTimeExtensions.leftShift(endExclusive, now))
+ .withDays(0)
+ .withMonths(0);
+ }
+
+ /**
+ * Obtains a Period consisting of the number of years and months between two {@link java.time.YearMonth} instances.
+ * The days of the Period will be zero.
+ * The result of this method can be a negative period if the end is before the start.
+ *
+ * @param type placeholder variable used by Groovy categories; ignored for default static methods
+ * @param startInclusive the start {@link java.time.YearMonth}, inclusive, not null
+ * @param endExclusive the end {@link java.time.YearMonth}, exclusive, not null
+ * @return a Period between the year/months
+ * @see java.time.Period#between(LocalDate, LocalDate)
+ */
+ public static Period between(final Period type, YearMonth startInclusive, YearMonth endExclusive) {
+ int dayOfMonth = 1;
+ return Period.between(
+ DateTimeExtensions.leftShift(startInclusive, dayOfMonth),
+ DateTimeExtensions.leftShift(endExclusive, dayOfMonth))
+ .withDays(0);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-datetime/src/spec/doc/working-with-datetime-types.adoc
----------------------------------------------------------------------
diff --git a/subprojects/groovy-datetime/src/spec/doc/working-with-datetime-types.adoc b/subprojects/groovy-datetime/src/spec/doc/working-with-datetime-types.adoc
new file mode 100644
index 0000000..e4041c4
--- /dev/null
+++ b/subprojects/groovy-datetime/src/spec/doc/working-with-datetime-types.adoc
@@ -0,0 +1,338 @@
+//////////////////////////////////////////
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+//////////////////////////////////////////
+
+= Working with Date/Time types
+
+The `groovy-datetime` module supports numerous extensions for working with
+the http://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html[Date/Time API]
+introduced in Java 8. This documentation refers to the data types defined by this API as
+"JSR 310 types."
+
+== Formatting and parsing
+
+A common use case when working with date/time types is to convert them to Strings (formatting)
+and from Strings (parsing). Groovy provides these additional formatting methods:
+
+[cols="1,1,1" options="header"]
+|====
+| Method
+| Description
+| Example
+
+| `getDateString()`
+| For `LocalDate` and `LocalDateTime`, formats with
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE[`DateTimeFormatter.ISO_LOCAL_DATE`]
+| `2018-03-10`
+
+|
+| For `OffsetDateTime`, formats with
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_OFFSET_DATE[`DateTimeFormatter.ISO_OFFSET_DATE`]
+| `2018-03-10+04:00`
+
+|
+| For `ZonedDateTime`, formats with
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE[`DateTimeFormatter.ISO_LOCAL_DATE`]
+and appends the `ZoneId` short name
+| `2018-03-10EST`
+
+| `getDateTimeString()`
+| For `LocalDateTime`, formats with
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE_TIME[`DateTimeFormatter.ISO_LOCAL_DATE_TIME`]
+| `2018-03-10T20:30:45`
+
+|
+| For `OffsetDateTime`, formats with
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_OFFSET_DATE_TIME[`DateTimeFormatter.ISO_OFFSET_DATE_TIME`]
+| `2018-03-10T20:30:45+04:00`
+
+|
+| For `ZonedDateTime`, formats with
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE_TIME[`DateTimeFormatter.ISO_LOCAL_DATE_TIME`]
+and appends the `ZoneId` short name
+| `2018-03-10T20:30:45EST`
+
+| `getTimeString()`
+| For `LocalTime` and `LocalDateTime`, formats with
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_TIME[`DateTimeFormatter.ISO_LOCAL_TIME`]
+| `20:30:45`
+
+|
+| For `OffsetTime` and `OffsetDateTime`, formats with
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_OFFSET_TIME[`DateTimeFormatter.ISO_OFFSET_TIME`]
+formatter
+| `20:30:45+04:00`
+
+|
+| For `ZonedDateTime`, formats with
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_LOCAL_TIME[`DateTimeFormatter.ISO_LOCAL_TIME`]
+and appends the `ZoneId` short name
+| `20:30:45EST`
+
+| `format(FormatStyle style)`
+| For `LocalTime` and `OffsetTime`, formats with
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ofLocalizedTime-java.time.format.FormatStyle-[`DateTimeFormatter.ofLocalizedTime(style)`]
+| `4:30 AM` (with style `FormatStyle.SHORT`, e.g.)
+
+|
+| For `LocalDate`, formats with
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ofLocalizedDate-java.time.format.FormatStyle-[`DateTimeFormatter.ofLocalizedDate(style)`]
+| `Saturday, March 10, 2018` (with style `FormatStyle.FULL`, e.g.)
+
+|
+| For `LocalDateTime`, `OffsetDateTime`, and `ZonedDateTime` formats with
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ofLocalizedDateTime-java.time.format.FormatStyle-[`DateTimeFormatter.ofLocalizedDateTime(style)`]
+| `Mar 10, 2019 4:30:45 AM` (with style `FormatStyle.MEDIUM`, e.g.)
+
+| `format(String pattern)`
+| Formats with
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ofPattern-java.lang.String-[`DateTimeFormatter.ofPattern(pattern)`]
+| `03/10/2018` (with pattern `'MM/dd/yyyy', e.g.)
+|====
+
+For parsing, Groovy adds a static `parse` method to many of the JSR 310 types. The method
+takes two arguments: the value to be formatted and the pattern to use. The pattern is
+defined by the
+https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html[`java.time.format.DateTimeFormatter` API].
+As an example:
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=static_parsing,indent=0]
+-------------------------------------
+
+Note that these `parse` methods have a different argument ordering than the static
+`parse` method Groovy added to `java.util.Date`.
+This was done to be consistent with the existing `parse` methods of the Date/Time API.
+
+== Manipulating date/time
+
+=== Addition and subtraction
+
+`Temporal` types have `plus` and `minus` methods for adding or subtracting a provided
+`java.time.temporal.TemporalAmount` argument. Because Groovy maps the `+` and `-` operators
+to single-argument methods of these names, a more natural expression syntax can be used to add and subtract.
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=plus_minus_period,indent=0]
+-------------------------------------
+
+Groovy provides additional `plus` and `minus` methods that accept an integer argument,
+enabling the above to be rewritten more succinctly:
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=localdate_plus_minus_integer,indent=0]
+-------------------------------------
+
+The unit of these integers depends on the JSR 310 type operand. As evident above,
+integers used with `ChronoLocalDate` types like `LocalDate` have a unit of
+https://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoUnit.html#DAYShttp://days[days].
+Integers used with `Year` and `YearMonth` have a unit of
+https://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoUnit.html#YEARS[years] and
+https://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoUnit.html#MONTHS[months], respectively.
+All other types have a unit of
+https://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoUnit.html#SECONDS[seconds],
+such as `LocalTime`, for instance:
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=localtime_plus_minus_integer,indent=0]
+-------------------------------------
+
+=== Multiplication and division
+
+The `*` operator can be used to multiply `Period` and `Duration` instances by an
+integer value; the `/` operator can be used to divide `Duration` instances by an integer value.
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=multiply_divide,indent=0]
+-------------------------------------
+
+=== Incrementing and decrementing
+
+The `++` and `--` operators can be used increment and decrement date/time values by one unit. Since the JSR 310 types
+are immutable, the operation will create a new instance with the incremented/decremented value and reassign it to the
+reference.
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=next_previous,indent=0]
+-------------------------------------
+
+=== Negation
+
+The `Duration` and `Period` types represent a negative or positive length of time.
+These can be negated with the unary `-` operator.
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=duration_negation,indent=0]
+-------------------------------------
+
+== Interacting with date/time values
+
+=== Property notation
+
+The
+https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAccessor.html#getLong-java.time.temporal.TemporalField-[`getLong(TemporalField)`]
+method of `TemporalAccessor` types (e.g. `LocalDate`,
+`LocalTime`, `ZonedDateTime`, etc.) and the
+https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAmount.html#get-java.time.temporal.TemporalUnit-[`get(TemporalUnit)`]
+method of `TemporalAmount` types (namely `Period` and `Duration`), can be invoked with
+Groovy's property notation. For example:
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=property_notation,indent=0]
+-------------------------------------
+
+=== Ranges, `upto`, and `downto`
+
+The JSR 310 types can be used with the <<core-operators.adoc#_range_operator,range operator>>.
+The following example iterates between today and the `LocalDate` six days from now,
+printing out the day of the week for each iteration. As both range bounds are inclusive,
+this prints all seven days of the week.
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=date_ranges,indent=0]
+-------------------------------------
+
+The `upto` method will accomplish the same as the range in the above example.
+The `upto` method iterates from the earlier start value (inclusive) to the later end value
+(also inclusive), calling the closure with the incremented value once per iteration.
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=date_upto_date,indent=0]
+-------------------------------------
+
+The `downto` method iterates in the opposite direction, from a later start value
+to an earlier end value.
+
+The unit of iteration for `upto`, `downto`, and ranges is the same as the unit for addition
+and subtraction: `LocalDate` iterates by one day at a time,
+`YearMonth` iterates by one month, `Year` by one year, and everything else by one second.
+Both methods also support an optional a `TemporalUnit` argument to change the unit of
+iteration.
+
+Consider the following example, where March 1st, 2018 is iterated up to March 2nd, 2018
+using an iteration unit of
+https://docs.oracle.com/javase/8/docs/api/java/time/temporal/ChronoUnit.html#MONTHS[months].
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=date_upto_date_by_months,indent=0]
+-------------------------------------
+
+Since the start date is inclusive, the closure is called with date March 1st. The `upto` method
+then increments the date by one month, yielding the date, April 1st. Because this date is _after_ the
+specified end date of March 2nd, the iteration stops immediately, having only called the closure
+once. This behavior is the same for the `downto` method except that the iteration will stop
+as soon as the the value of `end` becomes earlier than the targeted end date.
+
+In short, when iterating with the `upto` or `downto` methods with a custom unit of iteration,
+the current value of iteration will never exceed the end value.
+
+=== Combining date/time values
+
+The left-shift operator (`<<`) can be used to combine two JSR 310 types into an aggregate type.
+For example, a `LocalDate` can be left-shifted into a `LocalTime` to produce a composite
+`LocalDateTime` instance.
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=leftshift_operator,indent=0]
+-------------------------------------
+
+The left-shift operator is reflexive; the order of the operands does not matter.
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=leftshift_operator_reflexive,indent=0]
+-------------------------------------
+
+=== Creating periods and durations
+
+The right-shift operator (`>>`) produces a value representing the period or duration between the
+operands. For `ChronoLocalDate`, `YearMonth`, and `Year`, the operator yields
+a `Period` instance:
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=rightshift_operator_period,indent=0]
+-------------------------------------
+
+The operator produces a `Duration` for the time-aware JSR types:
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=rightshift_operator_duration,indent=0]
+-------------------------------------
+
+If the value on the left-hand side of the operator is earlier than the value on the right-hand
+side, the result is positive. If the left-hand side is later than the right-hand side, the
+result is negative:
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=rightshift_operator_negative,indent=0]
+-------------------------------------
+
+== Converting between legacy and JSR 310 types
+
+Despite the shortcomings of `Date`, `Calendar`, and `TimeZone` types in the `java.util` package
+they are farily common in Java APIs (at least in those prior to Java 8).
+To accommodate use of such APIs, Groovy provides methods for converting between the
+JSR 310 types and legacy types.
+
+Most JSR types have been fitted with `toDate()` and `toCalendar()` methods for
+converting to relatively equivalent `java.util.Date` and `java.util.Calendar` values.
+Both `ZoneId` and `ZoneOffset` have been given a `toTimeZone()` method for converting to
+`java.util.TimeZone`.
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=todate_tocalendar,indent=0]
+-------------------------------------
+
+Note that when converting to a legacy type:
+
+* Nanosecond values are truncated to milliseconds. A `LocalTime`, for example, with a `ChronoUnit.NANOS` value
+of 999,999,999 nanoseconds translates to 999 milliseconds.
+* When converting the "local" types (`LocalDate`, `LocalTime`, and `LocalDateTime`), the time zone of the
+returned `Date` or `Calendar` will be the system default.
+* When converting a time-only type (`LocalTime` or `OffsetTime`), the year/month/day of the `Date` or `Calendar` is set
+to the current date.
+* When converting a date-only type (`LocalDate`), the time value of the `Date` or `Calendar` will be cleared,
+i.e. `00:00:00.000`.
+* When converting an `OffsetDateTime` to a `Calendar`, only the hours and minutes of the `ZoneOffset` convey
+into the corresponding `TimeZone`. Fortunately, Zone Offsets with non-zero seconds are rare.
+
+Groovy has added a number of methods to `Date` and `Calendar`
+for converting into the various JSR 310 types:
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy[tags=to_jsr310_types,indent=0]
+-------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-datetime/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-datetime/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy b/subprojects/groovy-datetime/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy
new file mode 100644
index 0000000..baed5fc
--- /dev/null
+++ b/subprojects/groovy-datetime/src/spec/test/gdk/WorkingWithDateTimeTypesTest.groovy
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package gdk
+
+import java.time.DayOfWeek
+import java.time.Duration
+import java.time.LocalDate
+import java.time.LocalDateTime
+import java.time.LocalTime
+import java.time.Month
+import java.time.MonthDay
+import java.time.OffsetDateTime
+import java.time.OffsetTime
+import java.time.Period
+import java.time.Year
+import java.time.YearMonth
+import java.time.ZoneId
+import java.time.ZoneOffset
+import java.time.ZonedDateTime
+import java.time.temporal.ChronoField
+import java.time.temporal.ChronoUnit
+
+class WorkingWithDateTimeTypesTest extends GroovyTestCase {
+
+ void testParsing() {
+ // tag::static_parsing[]
+ def date = LocalDate.parse('Jun 3, 04', 'MMM d, yy')
+ assert date == LocalDate.of(2004, Month.JUNE, 3)
+
+ def time = LocalTime.parse('4:45', 'H:mm')
+ assert time == LocalTime.of(4, 45, 0)
+
+ def offsetTime = OffsetTime.parse('09:47:51-1234', 'HH:mm:ssZ')
+ assert offsetTime == OffsetTime.of(9, 47, 51, 0, ZoneOffset.ofHoursMinutes(-12, -34))
+
+ def dateTime = ZonedDateTime.parse('2017/07/11 9:47PM Pacific Standard Time', 'yyyy/MM/dd h:mma zzzz')
+ assert dateTime == ZonedDateTime.of(
+ LocalDate.of(2017, 7, 11),
+ LocalTime.of(21, 47, 0),
+ ZoneId.of('America/Los_Angeles')
+ )
+ // end::static_parsing[]
+ }
+
+ void testRange() {
+ // tag::date_ranges[]
+ def start = LocalDate.now()
+ def end = start + 6 // 6 days later
+ (start..end).each { date ->
+ println date.dayOfWeek
+ }
+ // end::date_ranges[]
+ }
+
+ void testUptoDownto() {
+ // tag::date_upto_date[]
+ def start = LocalDate.now()
+ def end = start + 6 // 6 days later
+ start.upto(end) { date ->
+ println date.dayOfWeek
+ }
+ // end::date_upto_date[]
+ }
+
+ void testUptoCustomUnit() {
+ // tag::date_upto_date_by_months[]
+ def start = LocalDate.of(2018, Month.MARCH, 2)
+ def end = start + 1 // 1 day later
+
+ int iterationCount = 0
+ start.upto(end, ChronoUnit.MONTHS) { date ->
+ println date
+ ++iterationCount
+ }
+
+ assert iterationCount == 1
+ // end::date_upto_date_by_months[]
+ }
+
+ void testPlusMinusWithTemporalAmounts() {
+ // tag::plus_minus_period[]
+ def aprilFools = LocalDate.of(2018, Month.APRIL, 1)
+
+ def nextAprilFools = aprilFools + Period.ofDays(365) // add 365 days
+ assert nextAprilFools.year == 2019
+
+ def idesOfMarch = aprilFools - Period.ofDays(17) // subtract 17 days
+ assert idesOfMarch.dayOfMonth == 15
+ assert idesOfMarch.month == Month.MARCH
+ // end::plus_minus_period[]
+ }
+
+ void testLocalDatePlusMinusInteger() {
+ def aprilFools = LocalDate.of(2018, Month.APRIL, 1)
+
+ // tag::localdate_plus_minus_integer[]
+ def nextAprilFools = aprilFools + 365 // add 365 days
+ def idesOfMarch = aprilFools - 17 // subtract 17 days
+ // end::localdate_plus_minus_integer[]
+
+ assert nextAprilFools.year == 2019
+ assert idesOfMarch.dayOfMonth == 15
+ assert idesOfMarch.month == Month.MARCH
+ }
+
+ void testLocalTimePlusMinusInteger() {
+ // tag::localtime_plus_minus_integer[]
+ def mars = LocalTime.of(12, 34, 56) // 12:34:56 pm
+
+ def thirtySecondsToMars = mars - 30 // go back 30 seconds
+ assert thirtySecondsToMars.second == 26
+ // end::localtime_plus_minus_integer[]
+ }
+
+ void testNextPrevious() {
+ // tag::next_previous[]
+ def year = Year.of(2000)
+ --year // decrement by one year
+ assert year.value == 1999
+
+ def offsetTime = OffsetTime.of(0, 0, 0, 0, ZoneOffset.UTC) // 00:00:00.000 UTC
+ offsetTime++ // increment by one second
+ assert offsetTime.second == 1
+ // end::next_previous[]
+ }
+
+ void testMultiplyDivide() {
+ // tag::multiply_divide[]
+ def period = Period.ofMonths(1) * 2 // a 1-month period times 2
+ assert period.months == 2
+
+ def duration = Duration.ofSeconds(10) / 5// a 10-second duration divided by 5
+ assert duration.seconds == 2
+ // end::multiply_divide[]
+ }
+
+ void testNegation() {
+ // tag::duration_negation[]
+ def duration = Duration.ofSeconds(-15)
+ def negated = -duration
+ assert negated.seconds == 15
+ // end::duration_negation[]
+ }
+
+ void testPropertyNotation() {
+ // tag::property_notation[]
+ def date = LocalDate.of(2018, Month.MARCH, 12)
+ assert date[ChronoField.YEAR] == 2018
+ assert date[ChronoField.MONTH_OF_YEAR] == Month.MARCH.value
+ assert date[ChronoField.DAY_OF_MONTH] == 12
+ assert date[ChronoField.DAY_OF_WEEK] == DayOfWeek.MONDAY.value
+
+ def period = Period.ofYears(2).withMonths(4).withDays(6)
+ assert period[ChronoUnit.YEARS] == 2
+ assert period[ChronoUnit.MONTHS] == 4
+ assert period[ChronoUnit.DAYS] == 6
+ // end::property_notation[]
+ }
+
+ void testLeftShift() {
+ // tag::leftshift_operator[]
+ MonthDay monthDay = Month.JUNE << 3 // June 3rd
+ LocalDate date = monthDay << Year.of(2015) // 3-Jun-2015
+ LocalDateTime dateTime = date << LocalTime.NOON // 3-Jun-2015 @ 12pm
+ OffsetDateTime offsetDateTime = dateTime << ZoneOffset.ofHours(-5) // 3-Jun-2015 @ 12pm UTC-5
+ // end::leftshift_operator[]
+ // tag::leftshift_operator_reflexive[]
+ def year = Year.of(2000)
+ def month = Month.DECEMBER
+
+ YearMonth a = year << month
+ YearMonth b = month << year
+ assert a == b
+ // end::leftshift_operator_reflexive[]
+ }
+
+ void testRightShift() {
+ // tag::rightshift_operator_period[]
+ def newYears = LocalDate.of(2018, Month.JANUARY, 1)
+ def aprilFools = LocalDate.of(2018, Month.APRIL, 1)
+
+ def period = newYears >> aprilFools
+ assert period instanceof Period
+ assert period.months == 3
+ // end::rightshift_operator_period[]
+
+ // tag::rightshift_operator_duration[]
+ def duration = LocalTime.NOON >> (LocalTime.NOON + 30)
+ assert duration instanceof Duration
+ assert duration.seconds == 30
+ // end::rightshift_operator_duration[]
+
+ // tag::rightshift_operator_negative[]
+ def decade = Year.of(2010) >> Year.of(2000)
+ assert decade.years == -10
+ // end::rightshift_operator_negative[]
+ }
+
+ void testToDateAndToCalendar() {
+ // tag::todate_tocalendar[]
+ // LocalDate to java.util.Date
+ def valentines = LocalDate.of(2018, Month.FEBRUARY, 14)
+ assert valentines.toDate().format('MMMM dd, yyyy') == 'February 14, 2018'
+
+ // LocalTime to java.util.Date
+ def noon = LocalTime.of(12, 0, 0)
+ assert noon.toDate().format('HH:mm:ss') == '12:00:00'
+
+ // ZoneId to java.util.TimeZone
+ def newYork = ZoneId.of('America/New_York')
+ assert newYork.toTimeZone() == TimeZone.getTimeZone('America/New_York')
+
+ // ZonedDateTime to java.util.Calendar
+ def valAtNoonInNY = ZonedDateTime.of(valentines, noon, newYork)
+ assert valAtNoonInNY.toCalendar().getTimeZone().toZoneId() == newYork
+ // end::todate_tocalendar[]
+ }
+
+ void testConvertToJSR310Types() {
+ // tag::to_jsr310_types[]
+ Date legacy = Date.parse('yyyy-MM-dd HH:mm:ss.SSS', '2010-04-03 10:30:58.999')
+
+ assert legacy.toLocalDate() == LocalDate.of(2010, 4, 3)
+ assert legacy.toLocalTime() == LocalTime.of(10, 30, 58, 999_000_000) // 999M ns = 999ms
+ assert legacy.toOffsetTime().hour == 10
+ assert legacy.toYear() == Year.of(2010)
+ assert legacy.toMonth() == Month.APRIL
+ assert legacy.toDayOfWeek() == DayOfWeek.SATURDAY
+ assert legacy.toMonthDay() == MonthDay.of(Month.APRIL, 3)
+ assert legacy.toYearMonth() == YearMonth.of(2010, Month.APRIL)
+ assert legacy.toLocalDateTime().year == 2010
+ assert legacy.toOffsetDateTime().dayOfMonth == 3
+ assert legacy.toZonedDateTime().zone == ZoneId.systemDefault()
+ // end::to_jsr310_types[]
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-datetime/src/test/java/groovy/DateTimeTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-datetime/src/test/java/groovy/DateTimeTest.groovy b/subprojects/groovy-datetime/src/test/java/groovy/DateTimeTest.groovy
new file mode 100644
index 0000000..bda4a4b
--- /dev/null
+++ b/subprojects/groovy-datetime/src/test/java/groovy/DateTimeTest.groovy
@@ -0,0 +1,851 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy
+
+import java.text.SimpleDateFormat
+import java.time.Duration
+import java.time.Instant
+import java.time.LocalDate
+import java.time.LocalDateTime
+import java.time.LocalTime
+import java.time.MonthDay
+import java.time.OffsetDateTime
+import java.time.OffsetTime
+import java.time.Period
+import java.time.YearMonth
+import java.time.ZoneId
+import java.time.ZoneOffset
+import java.time.ZonedDateTime
+import java.time.chrono.JapaneseDate
+import java.time.temporal.ChronoField
+import java.time.temporal.ChronoUnit
+
+class DateTimeTest extends GroovyTestCase {
+
+ void testDurationPlusMinusPositiveNegative() {
+ def duration = Duration.ofSeconds(10)
+ def longer = duration + 5
+ def shorter = duration - 5
+
+ assert longer.seconds == 15
+ assert shorter.seconds == 5
+ assert (++longer).seconds == 16
+ assert (--shorter).seconds == 4
+ }
+
+ void testInstantPlusMinusPositiveNegative() {
+ def epoch = Instant.ofEpochMilli(0)
+
+ def twoSecPastEpoch = epoch + 2
+ def oneSecPastEpoch = twoSecPastEpoch - 1
+
+ assert oneSecPastEpoch.epochSecond == 1
+ assert twoSecPastEpoch.epochSecond == 2
+ assert (++twoSecPastEpoch).epochSecond == 3
+ assert (--oneSecPastEpoch).epochSecond == 0
+ }
+
+ void testLocalDatePlusMinusPositiveNegative() {
+ def epoch = LocalDate.of(1970, Month.JANUARY, 1)
+
+ def twoDaysPastEpoch = epoch + 2
+ def oneDayPastEpoch = twoDaysPastEpoch - 1
+
+ assert oneDayPastEpoch.dayOfMonth == 2
+ assert twoDaysPastEpoch.dayOfMonth == 3
+ assert (++twoDaysPastEpoch).dayOfMonth == 4
+ assert (--oneDayPastEpoch).dayOfMonth == 1
+ }
+
+ void testLocalDateTimePlusMinusPositiveNegative() {
+ def epoch = LocalDateTime.of(1970, Month.JANUARY, 1, 0, 0, 0, 0)
+
+ def twoSecsPastEpoch = epoch + 2
+ def oneSecPastEpoch = twoSecsPastEpoch - 1
+
+ assert oneSecPastEpoch.second == 1
+ assert twoSecsPastEpoch.second == 2
+ assert (++twoSecsPastEpoch).second == 3
+ assert (--oneSecPastEpoch).second == 0
+ }
+
+ void testLocalTimePlusMinusPositiveNegative() {
+ def epoch = LocalTime.of(0, 0, 0, 0)
+
+ def twoSecsPastEpoch = epoch + 2
+ def oneSecPastEpoch = twoSecsPastEpoch - 1
+
+ assert oneSecPastEpoch.second == 1
+ assert twoSecsPastEpoch.second == 2
+ assert (++twoSecsPastEpoch).second == 3
+ assert (--oneSecPastEpoch).second == 0
+ }
+
+ void testOffsetDateTimePlusMinusPositiveNegative() {
+ def epoch = OffsetDateTime.of(LocalDateTime.of(1970, Month.JANUARY, 1, 0, 0, 0, 0),
+ ZoneOffset.ofHours(0))
+
+ def twoSecsPastEpoch = epoch + 2
+ def oneSecPastEpoch = twoSecsPastEpoch - 1
+
+ assert oneSecPastEpoch.second == 1
+ assert twoSecsPastEpoch.second == 2
+ assert (++twoSecsPastEpoch).second == 3
+ assert (--oneSecPastEpoch).second == 0
+ }
+
+ void testOffsetTimePlusMinusPositiveNegative() {
+ def epoch = OffsetTime.of(LocalTime.of(0, 0, 0, 0),
+ ZoneOffset.ofHours(0))
+
+ def twoSecsPastEpoch = epoch + 2
+ def oneSecPastEpoch = twoSecsPastEpoch - 1
+
+ assert oneSecPastEpoch.second == 1
+ assert twoSecsPastEpoch.second == 2
+ assert (++twoSecsPastEpoch).second == 3
+ assert (--oneSecPastEpoch).second == 0
+ }
+
+ void testPeriodPlusMinusPositiveNegative() {
+ def fortnight = Period.ofDays(14)
+
+ def fortnightAndTwoDays = fortnight + 2
+ def fortnightAndOneDay = fortnightAndTwoDays - 1
+
+ assert fortnightAndOneDay.days == 15
+ assert fortnightAndTwoDays.days == 16
+ assert (++fortnightAndTwoDays).days == 17
+ assert (--fortnightAndOneDay).days == 14
+ }
+
+ void testYearPlusMinusPositiveNegative() {
+ def epoch = Year.of(1970)
+
+ def twoYearsAfterEpoch = epoch + 2
+ def oneYearAfterEpoch = twoYearsAfterEpoch - 1
+
+ assert oneYearAfterEpoch.value == 1971
+ assert twoYearsAfterEpoch.value == 1972
+ assert (++twoYearsAfterEpoch).value == 1973
+ assert (--oneYearAfterEpoch).value == 1970
+ }
+
+ void testYearMonthPlusMinusPositiveNegative() {
+ def epoch = YearMonth.of(1970, Month.JANUARY)
+
+ def twoMonthsAfterEpoch = epoch + 2
+ def oneMonthAfterEpoch = twoMonthsAfterEpoch - 1
+
+ assert oneMonthAfterEpoch.month == Month.FEBRUARY
+ assert twoMonthsAfterEpoch.month == Month.MARCH
+ assert (++twoMonthsAfterEpoch).month == Month.APRIL
+ assert (--oneMonthAfterEpoch).month == Month.JANUARY
+ }
+
+ void testZonedDateTimePlusMinusPositiveNegative() {
+ def epoch = ZonedDateTime.of(LocalDateTime.of(1970, Month.JANUARY, 1, 0, 0, 0, 0),
+ ZoneId.systemDefault())
+
+ def twoSecsPastEpoch = epoch + 2
+ def oneSecPastEpoch = twoSecsPastEpoch - 1
+
+ assert oneSecPastEpoch.second == 1
+ assert twoSecsPastEpoch.second == 2
+ assert (++twoSecsPastEpoch).second == 3
+ assert (--oneSecPastEpoch).second == 0
+ }
+
+ void testDayOfWeekPlusMinus() {
+ def mon = DayOfWeek.MONDAY
+
+ assert mon + 4 == DayOfWeek.FRIDAY
+ assert mon - 4 == DayOfWeek.THURSDAY
+ }
+
+ void testMonthPlusMinus() {
+ def jan = Month.JANUARY
+
+ assert jan + 4 == Month.MAY
+ assert jan - 4 == Month.SEPTEMBER
+ }
+
+ void testDurationPositiveNegative() {
+ def positiveDuration = Duration.ofSeconds(3)
+ assert (-positiveDuration).seconds == -3
+
+ def negativeDuration = Duration.ofSeconds(-5)
+ assert (+negativeDuration).seconds == 5
+ }
+
+ void testDurationMultiplyDivide() {
+ def duration = Duration.ofSeconds(60)
+
+ assert (duration / 2).seconds == 30
+ assert (duration * 2).seconds == 120
+ }
+
+ void testDurationIsPositiveIsNonnegativeIsNonpositive() {
+ def pos = Duration.ofSeconds(10)
+ assert pos.isPositive() == true
+ assert pos.isNonpositive() == false
+ assert pos.isNonnegative() == true
+
+ def neg = Duration.ofSeconds(-10)
+ assert neg.isPositive() == false
+ assert neg.isNonpositive() == true
+ assert neg.isNonnegative() == false
+
+ assert Duration.ZERO.isPositive() == false
+ assert Duration.ZERO.isNonpositive() == true
+ assert Duration.ZERO.isNonnegative() == true
+ }
+
+ void testPeriodPositiveNegative() {
+ def positivePeriod = Period.of(1,2,3)
+ Period madeNegative = -positivePeriod
+ assert madeNegative.years == -1 : "All Period fields should be made negative"
+ assert madeNegative.months == -2
+ assert madeNegative.days == -3
+
+ def negativePeriod = Period.of(-1,2,-3)
+ Period madePositive = +negativePeriod
+ assert madePositive.years == 1 : "Negative Period fields should be made positive"
+ assert madePositive.months == 2 : "Positive Period fields should remain positive"
+ assert madePositive.days == 3
+ }
+
+ void testPeriodMultiply() {
+ def period = Period.of(1,1,1)
+ Period doublePeriod = period * 2
+ assert doublePeriod.years == 2
+ assert doublePeriod.months == 2
+ assert doublePeriod.days == 2
+ }
+
+ void testPeriodIsPositiveIsNonnegativeIsNonpositive() {
+ def pos = Period.ofDays(10)
+ assert pos.isPositive() == true
+ assert pos.isNonpositive() == false
+ assert pos.isNonnegative() == true
+
+ def neg = Period.ofDays(-10)
+ assert neg.isPositive() == false
+ assert neg.isNonpositive() == true
+ assert neg.isNonnegative() == false
+
+ assert Period.ZERO.isPositive() == false
+ assert Period.ZERO.isNonpositive() == true
+ assert Period.ZERO.isNonnegative() == true
+ }
+
+ void testTemporalGetAt() {
+ def epoch = Instant.ofEpochMilli(0)
+ assert epoch[ChronoField.INSTANT_SECONDS] == 0
+ }
+
+ void testTemporalAmountGetAt() {
+ def duration = Duration.ofHours(10)
+ assert duration[ChronoUnit.SECONDS] == 36_000
+ }
+
+ void testZoneOffsetGetAt() {
+ def offset = ZoneOffset.ofTotalSeconds(360)
+ assert offset[ChronoField.OFFSET_SECONDS] == 360
+ }
+
+ void testTemporalRightShift() {
+ def epoch = Instant.ofEpochMilli(0)
+ def dayAfterEpoch = epoch + (60 * 60 * 24)
+ Duration instantDuration = epoch >> dayAfterEpoch
+ assert instantDuration == Duration.ofDays(1)
+ }
+
+ void testLocalDateRightShift() {
+ def localDate1 = LocalDate.of(2000, Month.JANUARY, 1)
+ def localDate2 = localDate1.plusYears(2)
+ Period localDatePeriod = localDate1 >> localDate2
+ assert localDatePeriod.years == 2
+ }
+
+ void testYearRightShift() {
+ def year1 = Year.of(2000)
+ def year2 = Year.of(2018)
+ Period yearPeriod = year1 >> year2
+ assert yearPeriod.years == 18
+ }
+
+ void testYearMonthRightShift() {
+ def yearMonth1 = YearMonth.of(2018, Month.JANUARY)
+ def yearMonth2 = YearMonth.of(2018, Month.MARCH)
+ Period yearMonthPeriod = yearMonth1 >> yearMonth2
+ assert yearMonthPeriod.months == 2
+ }
+
+ void testRightShiftDifferentTypes() {
+ try {
+ LocalDate.now() >> LocalTime.now()
+ fail('Should not be able to use right shift on different Temporal types.')
+ } catch (e) {
+ assert e instanceof GroovyRuntimeException
+ }
+ }
+
+ void testUptoDifferentTypes() {
+ try {
+ LocalDate.now().upto(JapaneseDate.now().plus(1, ChronoUnit.MONTHS)) { d -> }
+ fail('Cannot use upto() with two different Temporal types.')
+ } catch (e) {
+ assert e instanceof GroovyRuntimeException
+ }
+ }
+
+ void testDowntoDifferentTypes() {
+ try {
+ LocalDate.now().downto(JapaneseDate.now().minus(1, ChronoUnit.MONTHS)) { d -> }
+ fail('Cannot use downto() with two different argument types.')
+ } catch (e) {
+ assert e instanceof GroovyRuntimeException
+ }
+ }
+
+ void testUptoSelfWithDefaultUnit() {
+ def epoch = Instant.ofEpochMilli(0)
+
+ int iterations = 0
+ epoch.upto(epoch) {
+ ++iterations
+ assert it == epoch: 'upto closure should be provided with arg'
+ }
+ assert iterations == 1: 'Iterating upto same value should call closure once'
+ }
+
+ void testDowntoSelfWithDefaultUnit() {
+ def epoch = Instant.ofEpochMilli(0)
+ int iterations = 0
+ epoch.downto(epoch) {
+ ++iterations
+ assert it == epoch: 'downto closure should be provided with arg'
+ }
+ assert iterations == 1: 'Iterating downto same value should call closure once'
+ }
+
+ void testUptoWithSecondsDefaultUnit() {
+ def epoch = Instant.ofEpochMilli(0)
+
+ int iterations = 0
+ Instant end = null
+ epoch.upto(epoch + 1) {
+ ++iterations
+ end = it
+ }
+ assert iterations == 2: 'Iterating upto Temporal+1 value should call closure twice'
+ assert end.epochSecond == 1: 'Unexpected upto final value'
+ }
+
+ void testDowntoWithSecondsDefaultUnit() {
+ def epoch = Instant.ofEpochMilli(0)
+
+ int iterations = 0
+ Instant end = null
+ epoch.downto(epoch - 1) {
+ ++iterations
+ end = it
+ }
+ assert iterations == 2 : 'Iterating downto Temporal+1 value should call closure twice'
+ assert end.epochSecond == -1 : 'Unexpected downto final value'
+ }
+
+ void testUptoWithYearsDefaultUnit() {
+ def endYear = null
+ Year.of(1970).upto(Year.of(1971)) { year -> endYear = year }
+ assert endYear.value == 1971
+ }
+
+ void testDowntoWithYearsDefaultUnit() {
+ def endYear = null
+ Year.of(1971).downto(Year.of(1970)) { year -> endYear = year }
+ assert endYear.value == 1970
+ }
+
+ void testUptoWithMonthsDefaultUnit() {
+ def endYearMonth = null
+ YearMonth.of(1970, Month.JANUARY).upto(YearMonth.of(1970, Month.FEBRUARY)) { yearMonth ->
+ endYearMonth = yearMonth
+ }
+ assert endYearMonth.month == Month.FEBRUARY
+ }
+
+ void testDowntoWithMonthsDefaultUnit() {
+ def endYearMonth = null
+ YearMonth.of(1970, Month.FEBRUARY).downto(YearMonth.of(1970, Month.JANUARY)) { yearMonth ->
+ endYearMonth = yearMonth
+ }
+ assert endYearMonth.month == Month.JANUARY
+ }
+
+ void testUptoWithDaysDefaultUnit() {
+ def endLocalDate = null
+ LocalDate.of(1970, Month.JANUARY, 1).upto(LocalDate.of(1970, Month.JANUARY, 2)) { localDate ->
+ endLocalDate = localDate
+ }
+ assert endLocalDate.dayOfMonth == 2
+ }
+
+ void testDowntoWithDaysDefaultUnit() {
+ def endLocalDate = null
+ LocalDate.of(1970, Month.JANUARY, 2).downto(LocalDate.of(1970, Month.JANUARY, 1)) { localDate ->
+ endLocalDate = localDate
+ }
+ assert endLocalDate.dayOfMonth == 1
+ }
+
+ void testUptoWithIllegalReversedArguments() {
+ def epoch = Instant.ofEpochMilli(0)
+ try {
+ epoch.upto(epoch - 1) {
+ fail('upto() should fail when passed earlier arg')
+ }
+ } catch (GroovyRuntimeException e) {
+ }
+ }
+
+ void testDowntoWithIllegalReversedArguments() {
+ def epoch = Instant.ofEpochMilli(0)
+ try {
+ epoch.downto(epoch + 1) {
+ fail('downto() should fail when passed earlier arg')
+ }
+ } catch (GroovyRuntimeException e) {}
+ }
+
+ void testUptoSelfWithCustomUnit() {
+ def today = LocalDate.now()
+
+ int iterations = 0
+ today.upto(today, ChronoUnit.MONTHS) {
+ ++iterations
+ assert it == today: 'upto closure should be provided with arg'
+ }
+ assert iterations == 1: 'Iterating upto same value should call closure once'
+ }
+
+ void testDowntoSelfWithCustomUnit() {
+ def today = LocalDate.now()
+
+ int iterations = 0
+ today.downto(today, ChronoUnit.MONTHS) {
+ ++iterations
+ assert it == today: 'downto closure should be provided with arg'
+ }
+ assert iterations == 1: 'Iterating downto same value should call closure once'
+ }
+
+ void testUptoWithCustomUnit() {
+ LocalDateTime from = LocalDateTime.of(2018, Month.FEBRUARY, 11, 22, 9, 34)
+ // one second beyond one iteration
+ LocalDateTime to = from.plusDays(1).plusSeconds(1)
+
+ int iterations = 0
+ LocalDateTime end = null
+ from.upto(to, ChronoUnit.DAYS) {
+ ++iterations
+ end = it
+ }
+ assert iterations == 2
+ assert end.dayOfMonth == 12: "Upto should have iterated by DAYS twice"
+ }
+
+ void testDowntoWithCustomUnit() {
+ LocalDateTime from = LocalDateTime.of(2018, Month.FEBRUARY, 11, 22, 9, 34)
+ // one day beyond one iteration
+ LocalDateTime to = from.minusYears(1).minusDays(1)
+
+ int iterations = 0
+ LocalDateTime end = null
+ from.downto(to, ChronoUnit.YEARS) {
+ ++iterations
+ end = it
+ }
+ assert iterations == 2
+ assert end.year == 2017 : "Downto should have iterated by YEARS twice"
+ }
+
+ void testInstantToDateToCalendar() {
+ def epoch = Instant.ofEpochMilli(0).plusNanos(999_999)
+
+ def date = epoch.toDate()
+ def cal = epoch.toCalendar()
+ assert cal.time == date
+ def sdf = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss.SSS')
+ sdf.timeZone = TimeZone.getTimeZone('GMT')
+ assert sdf.format(date) == '1970-01-01 00:00:00.000'
+ }
+
+ void testLocalDateToDateToCalendar() {
+ def ld = LocalDate.of(2018, Month.FEBRUARY, 12)
+
+ Calendar cal = ld.toCalendar()
+ assert cal.get(Calendar.YEAR) == 2018
+ assert cal.get(Calendar.MONTH) == Calendar.FEBRUARY
+ assert cal.get(Calendar.DAY_OF_MONTH) == 12
+ assert cal.timeZone.getID() == TimeZone.default.getID()
+
+ Date date = ld.toDate()
+ assert date.format('yyyy-MM-dd') == '2018-02-12'
+ }
+
+ void testLocalDateTimeToDateToCalendar() {
+ def ldt = LocalDateTime.of(2018, Month.FEBRUARY, 12, 22, 26, 30, 123_999_999)
+
+ Calendar cal = ldt.toCalendar()
+ assert cal.get(Calendar.YEAR) == 2018
+ assert cal.get(Calendar.MONTH) == Calendar.FEBRUARY
+ assert cal.get(Calendar.DAY_OF_MONTH) == 12
+ assert cal.get(Calendar.HOUR_OF_DAY) == 22
+ assert cal.get(Calendar.MINUTE) == 26
+ assert cal.get(Calendar.SECOND) == 30
+ assert cal.get(Calendar.MILLISECOND) == 123
+ assert cal.timeZone.getID() == TimeZone.default.getID()
+
+ Date date = ldt.toDate()
+ assert date.format('yyyy-MM-dd HH:mm:ss.SSS') == '2018-02-12 22:26:30.123'
+ }
+
+ void testLocalTimeToDateToCalendar() {
+ def today = Calendar.instance
+ def lt = LocalTime.of(22, 38, 20, 9_999_999)
+
+ Calendar cal = lt.toCalendar()
+ assert cal.get(Calendar.YEAR) == today.get(Calendar.YEAR) : 'LocalTime.toCalendar() should have current year'
+ assert cal.get(Calendar.MONTH) == today.get(Calendar.MONTH) : 'LocalTime.toCalendar() should have current month'
+ assert cal.get(Calendar.DAY_OF_MONTH) == today.get(Calendar.DAY_OF_MONTH) : 'LocalTime.toCalendar() should have current day'
+ assert cal.get(Calendar.HOUR_OF_DAY) == 22
+ assert cal.get(Calendar.MINUTE) == 38
+ assert cal.get(Calendar.SECOND) == 20
+ assert cal.get(Calendar.MILLISECOND) == 9
+ assert cal.timeZone.getID() == TimeZone.default.getID()
+
+ Date date = lt.toDate()
+ assert date.format('HH:mm:ss.SSS') == '22:38:20.009'
+ }
+
+ void testOffsetDateTimeToDateToCalendar() {
+ def ld = LocalDate.of(2018, Month.FEBRUARY, 12)
+ def lt = LocalTime.of(22, 46, 10, 16_000_001)
+ def offset = ZoneOffset.ofHours(-5)
+ def odt = OffsetDateTime.of(ld, lt, offset)
+
+ Calendar cal = odt.toCalendar()
+ assert cal.get(Calendar.YEAR) == 2018
+ assert cal.get(Calendar.MONTH) == Calendar.FEBRUARY
+ assert cal.get(Calendar.DAY_OF_MONTH) == 12
+ assert cal.get(Calendar.HOUR_OF_DAY) == 22
+ assert cal.get(Calendar.MINUTE) == 46
+ assert cal.get(Calendar.SECOND) == 10
+ assert cal.get(Calendar.MILLISECOND) == 16
+ assert cal.timeZone.getOffset(System.currentTimeMillis()) == -5 * 60 * 60 * 1000
+
+ Date date = odt.toDate()
+ def sdf = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss.SSS Z')
+ sdf.timeZone = cal.timeZone
+ assert sdf.format(date) == '2018-02-12 22:46:10.016 -0500'
+ }
+
+ void testOffsetTimeToDateToCalendar() {
+ def lt = LocalTime.of(22, 53, 2, 909_900_009)
+ def offset = ZoneOffset.ofHours(-4)
+ def ot = OffsetTime.of(lt, offset)
+ Calendar today = Calendar.getInstance(TimeZone.getTimeZone('GMT-4'))
+
+ Calendar cal = ot.toCalendar()
+ assert cal.get(Calendar.YEAR) == today.get(Calendar.YEAR) : 'OffsetTime.toCalendar() should have current year'
+ assert cal.get(Calendar.MONTH) == today.get(Calendar.MONTH) : 'OffsetTime.toCalendar() should have current month'
+ assert cal.get(Calendar.DAY_OF_MONTH) == today.get(Calendar.DAY_OF_MONTH) : 'OffsetTime.toCalendar() should have current day'
+ assert cal.get(Calendar.HOUR_OF_DAY) == 22
+ assert cal.get(Calendar.MINUTE) == 53
+ assert cal.get(Calendar.SECOND) == 2
+ assert cal.get(Calendar.MILLISECOND) == 909
+ assert cal.timeZone.getOffset(System.currentTimeMillis()) == -4 * 60 * 60 * 1000
+
+ Date date = ot.toDate()
+ def sdf = new SimpleDateFormat('HH:mm:ss.SSS Z')
+ sdf.timeZone = cal.timeZone
+ assert sdf.format(date) == '22:53:02.909 -0400'
+ }
+
+ void testZonedDateTimeToDateToCalendar() {
+ def ldt = LocalDateTime.of(2018, Month.FEBRUARY, 13, 20, 33, 57)
+ def zoneId = ZoneId.ofOffset('GMT', ZoneOffset.ofHours(3))
+ def zdt = ZonedDateTime.of(ldt, zoneId)
+
+ Calendar cal = zdt.toCalendar()
+ assert cal.get(Calendar.YEAR) == 2018
+ assert cal.get(Calendar.MONTH) == Calendar.FEBRUARY
+ assert cal.get(Calendar.DAY_OF_MONTH) == 13
+ assert cal.get(Calendar.HOUR_OF_DAY) == 20
+ assert cal.get(Calendar.MINUTE) == 33
+ assert cal.get(Calendar.SECOND) == 57
+ assert cal.get(Calendar.MILLISECOND) == 0
+ assert cal.timeZone.getOffset(System.currentTimeMillis()) == 3 * 60 * 60 * 1000
+
+ Date date = zdt.toDate()
+ def sdf = new SimpleDateFormat('yyyy-MM-dd HH:mm:ss.SSS Z')
+ sdf.timeZone = cal.timeZone
+ assert sdf.format(date) == '2018-02-13 20:33:57.000 +0300'
+ }
+
+ void testZoneOffsetExtensionProperties() {
+ def offset = ZoneOffset.ofHoursMinutesSeconds(3,4,5)
+ assert offset.hours == 3
+ assert offset.minutes == 4
+ assert offset.seconds == 5
+
+ def negOffset = ZoneOffset.ofHoursMinutesSeconds(-1, -2, -3)
+ assert negOffset.hours == -1
+ assert negOffset.minutes == -2
+ assert negOffset.seconds == -3
+ }
+
+ void testZoneOffsetToZimeZone() {
+ TimeZone utcTz = ZoneOffset.UTC.toTimeZone()
+ assert utcTz.getID() == 'GMT'
+
+ TimeZone noSecsTz = ZoneOffset.ofHoursMinutes(1, 30).toTimeZone()
+ assert noSecsTz.getID() == 'GMT+01:30'
+
+ TimeZone secsTz = ZoneOffset.ofHoursMinutesSeconds(-4, -15, -30).toTimeZone()
+ assert secsTz.getID() == 'GMT-04:15'
+ }
+
+ void testZoneIdExtensionProperties() {
+ def offset = ZoneOffset.ofHours(7)
+ def zoneId = ZoneId.ofOffset('GMT', offset)
+
+ assert zoneId.offset.totalSeconds == offset.totalSeconds
+ assert zoneId.getOffset(Instant.now()).totalSeconds == offset.totalSeconds
+ assert zoneId.shortName == 'GMT+07:00'
+ assert zoneId.fullName == 'GMT+07:00'
+
+ ZoneId ny = ZoneId.of('America/New_York')
+ assert ny.getShortName(Locale.US) == 'ET'
+ assert ny.getFullName(Locale.US) == 'Eastern Time'
+ }
+
+ void testZoneIdToTimeZone() {
+ ZoneId ny = ZoneId.of('America/New_York')
+
+ assert ny.toTimeZone() == TimeZone.getTimeZone(ny)
+ }
+
+ void testYearExtensionProperties() {
+ def year = Year.of(2009)
+ assert year.era == 1
+ assert year.yearOfEra == 2009
+ }
+
+ void testDayOfWeekExtensionProperties() {
+ assert DayOfWeek.SUNDAY.weekend
+ assert DayOfWeek.MONDAY.weekday
+ }
+
+ void testYear_Month_leftShift() {
+ def a = Year.now()
+ def b = Month.JULY
+
+ YearMonth x = a << b
+ YearMonth y = b << a
+ assert x == y
+ }
+
+ void testYear_MonthDay_leftShift() {
+ def a = Year.now()
+ def b = MonthDay.now()
+
+ LocalDate x = a << b
+ LocalDate y = b << a
+ assert x == y
+ }
+
+ void testMonthDay_leftShift() {
+ LocalDate d = MonthDay.of(Month.FEBRUARY, 13) << 2018
+ assert d.year == 2018
+ assert d.month == Month.FEBRUARY
+ assert d.dayOfMonth == 13
+ }
+
+ void testMonth_leftShift() {
+ MonthDay md = Month.JANUARY << 10
+ assert md.month == Month.JANUARY
+ assert md.dayOfMonth == 10
+ }
+
+ void testLocalDate_LocalTime_leftShift() {
+ def a = LocalDate.now()
+ def b = LocalTime.now()
+
+ LocalDateTime x = a << b
+ LocalDateTime y = b << a
+ assert x == y
+ }
+
+ void testLocalDate_OffsetTime_leftShift() {
+ def a = LocalDate.now()
+ def b = OffsetTime.now()
+
+ OffsetDateTime x = a << b
+ OffsetDateTime y = b << a
+ assert x == y
+ }
+
+ void testLocalDateTime_ZoneOffset_leftShift() {
+ def a = LocalDateTime.now()
+ def b = ZoneOffset.ofHours(5)
+
+ OffsetDateTime x = a << b
+ OffsetDateTime y = b << a
+ assert x == y
+ }
+
+ void testLocalDateTime_ZoneId_leftShift() {
+ def a = LocalDateTime.now()
+ def b = ZoneId.systemDefault()
+
+ ZonedDateTime x = a << b
+ ZonedDateTime y = b << a
+ assert x == y
+ }
+
+ void testLocalTime_ZoneOffset_leftShift() {
+ def a = LocalTime.now()
+ def b = ZoneOffset.ofHours(5)
+
+ OffsetTime x = a << b
+ OffsetTime y = b << a
+ assert x == y
+ }
+
+ void testLocalDateTimeClearTime() {
+ def d = LocalDateTime.of(LocalDate.now(), LocalTime.of(8, 9, 10, 100_032))
+ d = d.clearTime()
+
+ assert d.hour == 0
+ assert d.minute == 0
+ assert d.second == 0
+ assert d.nano == 0
+ }
+
+ void testOffsetDateTimeClearTime() {
+ def offset = ZoneOffset.ofHours(-1)
+ def d = OffsetDateTime.of(LocalDate.now(), LocalTime.of(8, 9, 10, 100_032), offset)
+ d = d.clearTime()
+
+ assert d.hour == 0
+ assert d.minute == 0
+ assert d.second == 0
+ assert d.nano == 0
+ assert d.offset == offset : 'cleartTime() should not change offset'
+ }
+
+ void testZonedDateTimeClearTime() {
+ def zone = ZoneId.of('America/New_York')
+ def d = ZonedDateTime.of(LocalDate.now(), LocalTime.of(8, 9, 10, 100_032), zone)
+ d = d.clearTime()
+
+ assert d.hour == 0
+ assert d.minute == 0
+ assert d.second == 0
+ assert d.nano == 0
+ assert d.zone == zone : 'cleartTime() should not change zone'
+ }
+
+ void testFormatByPattern() {
+ def zone = ZoneId.of('America/New_York')
+ def offset = ZoneOffset.ofHours(2)
+
+ LocalDate ld = LocalDate.of(2018, Month.FEBRUARY, 13)
+ LocalTime lt = LocalTime.of(3,4,5,6_000_000)
+ LocalDateTime ldt = LocalDateTime.of(ld, lt)
+ OffsetTime ot = OffsetTime.of(lt, offset)
+ OffsetDateTime odt = OffsetDateTime.of(ldt, offset)
+ ZonedDateTime zdt = ZonedDateTime.of(ldt, zone)
+
+ assert ld.format('yyyy-MM-dd') == '2018-02-13'
+ assert lt.format('HH:mm:ss.SSS') == '03:04:05.006'
+ assert ldt.format('yyyy-MM-dd HH:mm:ss.SSS') == '2018-02-13 03:04:05.006'
+ assert ot.format('HH:mm:ss.SSS Z') == '03:04:05.006 +0200'
+ assert odt.format('yyyy-MM-dd HH:mm:ss.SSS Z') == '2018-02-13 03:04:05.006 +0200'
+ assert zdt.format('yyyy-MM-dd HH:mm:ss.SSS VV') == '2018-02-13 03:04:05.006 America/New_York'
+ }
+
+ void testLocalDateParse() {
+ LocalDate ld = LocalDate.parse('2018-02-15', 'yyyy-MM-dd')
+ assert [ld.year, ld.month, ld.dayOfMonth] == [2018, Month.FEBRUARY, 15]
+ }
+
+ void testLocalDateTimeParse() {
+ LocalDateTime ldt = LocalDateTime.parse('2018-02-15 21:43:03.002', 'yyyy-MM-dd HH:mm:ss.SSS')
+ assert [ldt.year, ldt.month, ldt.dayOfMonth] == [2018, Month.FEBRUARY, 15]
+ assert [ldt.hour, ldt.minute, ldt.second] == [21, 43, 03]
+ assert ldt.nano == 2 * 1e6
+ }
+
+ void testLocalTimeParse() {
+ LocalTime lt = LocalTime.parse('21:43:03.002', 'HH:mm:ss.SSS')
+ assert [lt.hour, lt.minute, lt.second] == [21, 43, 03]
+ assert lt.nano == 2 * 1e6
+ }
+
+ void testOffsetDateTimeParse() {
+ OffsetDateTime odt = OffsetDateTime.parse('2018-02-15 21:43:03.002 -00', 'yyyy-MM-dd HH:mm:ss.SSS X')
+ assert [odt.year, odt.month, odt.dayOfMonth] == [2018, Month.FEBRUARY, 15]
+ assert [odt.hour, odt.minute, odt.second] == [21, 43, 03]
+ assert odt.nano == 2 * 1e6
+ assert odt.offset.totalSeconds == 0
+ }
+
+ void testOffsetTimeParse() {
+ OffsetTime ot = OffsetTime.parse('21:43:03.002 -00', 'HH:mm:ss.SSS X')
+ assert [ot.hour, ot.minute, ot.second] == [21, 43, 03]
+ assert ot.nano == 2 * 1e6
+ assert ot.offset.totalSeconds == 0
+ }
+
+ void testZonedDateTimeParse() {
+ ZonedDateTime zdt = ZonedDateTime.parse('2018-02-15 21:43:03.002 UTC', 'yyyy-MM-dd HH:mm:ss.SSS z')
+ assert [zdt.year, zdt.month, zdt.dayOfMonth] == [2018, Month.FEBRUARY, 15]
+ assert [zdt.hour, zdt.minute, zdt.second] == [21, 43, 03]
+ assert zdt.nano == 2 * 1e6
+ }
+
+ void testPeriodBetweenYears() {
+ def period = Period.between(Year.of(2000), Year.of(2010))
+ assert period.years == 10
+ assert period.months == 0
+ assert period.days == 0
+ }
+
+ void testPeriodBetweenYearMonths() {
+ def period = Period.between(YearMonth.of(2018, Month.MARCH), YearMonth.of(2016, Month.APRIL))
+
+ assert period.years == -1
+ assert period.months == -11
+ assert period.days == 0
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-datetime/src/test/java/org/apache/groovy/datetime/extensions/DateTimeExtensionsTest.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-datetime/src/test/java/org/apache/groovy/datetime/extensions/DateTimeExtensionsTest.java b/subprojects/groovy-datetime/src/test/java/org/apache/groovy/datetime/extensions/DateTimeExtensionsTest.java
new file mode 100644
index 0000000..4cbb8df
--- /dev/null
+++ b/subprojects/groovy-datetime/src/test/java/org/apache/groovy/datetime/extensions/DateTimeExtensionsTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.groovy.datetime.extensions;
+
+import org.junit.Test;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.MonthDay;
+import java.time.Year;
+import java.time.YearMonth;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import static org.junit.Assert.assertEquals;
+
+public class DateTimeExtensionsTest {
+ @Test
+ public void calendarConversionsDefaultTimeZone() throws ParseException {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss SSS");
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(sdf.parse("20180115 153256 001"));
+
+ LocalDate expectedLocalDate = LocalDate.of(2018, Month.JANUARY, 15);
+ LocalTime expectedLocalTime = LocalTime.of(15, 32, 56, 1_000_000);
+ LocalDateTime expectedLocalDateTime = LocalDateTime.of(expectedLocalDate, expectedLocalTime);
+
+ assertEquals("DayOfWeek", DayOfWeek.MONDAY, DateTimeExtensions.toDayOfWeek(calendar));
+ assertEquals("Month", Month.JANUARY, DateTimeExtensions.toMonth(calendar));
+ assertEquals("MonthDay", MonthDay.of(Month.JANUARY, 15), DateTimeExtensions.toMonthDay(calendar));
+ assertEquals("YearMonth", YearMonth.of(2018, Month.JANUARY), DateTimeExtensions.toYearMonth(calendar));
+ assertEquals("Year", Year.of(2018), DateTimeExtensions.toYear(calendar));
+ assertEquals("LocalDate", expectedLocalDate, DateTimeExtensions.toLocalDate(calendar));
+ assertEquals("LocalTime", expectedLocalTime, DateTimeExtensions.toLocalTime(calendar));
+ assertEquals("LocalDateTime", expectedLocalDateTime, DateTimeExtensions.toLocalDateTime(calendar));
+ assertEquals("OffsetTime", expectedLocalTime, DateTimeExtensions.toOffsetTime(calendar).toLocalTime());
+ assertEquals("OffsetDateTime", expectedLocalDateTime,
+ DateTimeExtensions.toOffsetDateTime(calendar).toLocalDateTime());
+ assertEquals("ZonedDateTime", expectedLocalDateTime,
+ DateTimeExtensions.toZonedDateTime(calendar).toLocalDateTime());
+ }
+
+ @Test
+ public void calendarConversionsDifferingTimeZones() throws ParseException {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss SSS");
+ Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC+0"));
+ calendar.setTime(sdf.parse("20180115 153256 001"));
+ }
+
+ @Test
+ public void sameCalendarAndDateConvertIdentically() throws ParseException {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss SSS");
+ Date date = sdf.parse("20180115 153256 001");
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(date);
+
+ assertEquals("DayOfWeek", DateTimeExtensions.toDayOfWeek(calendar), DateTimeExtensions.toDayOfWeek(date));
+ assertEquals("Month", DateTimeExtensions.toMonth(calendar), DateTimeExtensions.toMonth(date));
+ assertEquals("MonthDay", DateTimeExtensions.toMonthDay(calendar), DateTimeExtensions.toMonthDay(date));
+ assertEquals("YearMonth", DateTimeExtensions.toYearMonth(calendar), DateTimeExtensions.toYearMonth(date));
+ assertEquals("Year", DateTimeExtensions.toYear(calendar), DateTimeExtensions.toYear(date));
+ assertEquals("LocalDate", DateTimeExtensions.toLocalDate(calendar), DateTimeExtensions.toLocalDate(date));
+ assertEquals("LocalTime", DateTimeExtensions.toLocalTime(calendar), DateTimeExtensions.toLocalTime(date));
+ assertEquals("LocalDateTime", DateTimeExtensions.toLocalDate(calendar), DateTimeExtensions.toLocalDate(date));
+ assertEquals("OffsetTime", DateTimeExtensions.toOffsetTime(calendar), DateTimeExtensions.toOffsetTime(date));
+ assertEquals("OffsetDateTime",
+ DateTimeExtensions.toOffsetDateTime(calendar), DateTimeExtensions.toOffsetDateTime(date));
+ assertEquals("ZonedDateTime",
+ DateTimeExtensions.toZonedDateTime(calendar), DateTimeExtensions.toZonedDateTime(date));
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-dateutil/build.gradle
----------------------------------------------------------------------
diff --git a/subprojects/groovy-dateutil/build.gradle b/subprojects/groovy-dateutil/build.gradle
new file mode 100644
index 0000000..296f0fa
--- /dev/null
+++ b/subprojects/groovy-dateutil/build.gradle
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+dependencies {
+ compile rootProject
+ testCompile project(':groovy-test')
+}
+
+task moduleDescriptor(type: org.codehaus.groovy.gradle.WriteExtensionDescriptorTask) {
+ extensionClasses = 'org.apache.groovy.dateutil.extensions.DateUtilExtensions'
+// staticExtensionClasses = 'org.apache.groovy.dateutil.extensions.DateUtilStaticExtensions'
+}
+compileJava.dependsOn moduleDescriptor
[3/7] groovy git commit: move datetime extensions to their own module
Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/subprojects/groovy-datetime/src/main/java/org/apache/groovy/datetime/extensions/DateTimeExtensions.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-datetime/src/main/java/org/apache/groovy/datetime/extensions/DateTimeExtensions.java b/subprojects/groovy-datetime/src/main/java/org/apache/groovy/datetime/extensions/DateTimeExtensions.java
new file mode 100644
index 0000000..9ba6014
--- /dev/null
+++ b/subprojects/groovy-datetime/src/main/java/org/apache/groovy/datetime/extensions/DateTimeExtensions.java
@@ -0,0 +1,2419 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.groovy.datetime.extensions;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyRuntimeException;
+
+import java.time.DateTimeException;
+import java.time.DayOfWeek;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Period;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.ChronoPeriod;
+import java.time.format.DateTimeFormatter;
+import java.time.format.FormatStyle;
+import java.time.format.TextStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+/**
+ * This class defines new Groovy methods which appear on normal JDK
+ * Date/Time API (java.time) classes inside the Groovy environment.
+ * These extensions require JDK 8 or above.
+ */
+public class DateTimeExtensions {
+
+ // Static methods only
+ private DateTimeExtensions() {
+ }
+
+ private static final DateTimeFormatter ZONE_SHORT_FORMATTER = DateTimeFormatter.ofPattern("z");
+
+ /**
+ * For any Temporal subtype that does not use {@link java.time.temporal.ChronoUnit#SECONDS} as the unit for
+ * the upto/downto methods, should have an entry.
+ */
+ private static Map<Class<? extends Temporal>, TemporalUnit> DEFAULT_UNITS = new HashMap<>();
+
+ static {
+ DEFAULT_UNITS.put(ChronoLocalDate.class, DAYS);
+ DEFAULT_UNITS.put(YearMonth.class, MONTHS);
+ DEFAULT_UNITS.put(Year.class, YEARS);
+ }
+
+ /**
+ * A number of extension methods permit a long or int to be provided as a parameter. This method determines
+ * what the unit should be for this number.
+ */
+ private static TemporalUnit defaultUnitFor(Temporal temporal) {
+ return DEFAULT_UNITS.entrySet()
+ .stream()
+ .filter(e -> e.getKey().isAssignableFrom(temporal.getClass()))
+ .findFirst()
+ .map(Map.Entry::getValue)
+ .orElse(ChronoUnit.SECONDS);
+ }
+
+ /**
+ * Truncates a nanosecond value to milliseconds. No rounding.
+ */
+ private static int millisFromNanos(int nanos) {
+ return nanos / 1_000_000;
+ }
+
+ /* ******** java.time.temporal.Temporal extension methods ******** */
+
+ /**
+ * Iterates from this to the {@code to} {@link java.time.temporal.Temporal}, inclusive, incrementing by one
+ * unit each iteration, calling the closure once per iteration. The closure may accept a single
+ * {@link java.time.temporal.Temporal} argument.
+ * <p>
+ * The particular unit incremented by depends on the specific sub-type of {@link java.time.temporal.Temporal}.
+ * Most sub-types use a unit of {@link java.time.temporal.ChronoUnit#SECONDS} except for
+ * <ul>
+ * <li>{@link java.time.chrono.ChronoLocalDate} and its sub-types use {@link java.time.temporal.ChronoUnit#DAYS}.
+ * <li>{@link java.time.YearMonth} uses {@link java.time.temporal.ChronoUnit#MONTHS}.
+ * <li>{@link java.time.Year} uses {@link java.time.temporal.ChronoUnit#YEARS}.
+ * </ul>
+ *
+ * @param from the starting Temporal
+ * @param to the ending Temporal
+ * @param closure the zero or one-argument closure to call
+ * @throws GroovyRuntimeException if this value is later than {@code to}
+ * @throws GroovyRuntimeException if {@code to} is a different type than this
+ * @since 2.5.0
+ */
+ public static void upto(Temporal from, Temporal to, Closure closure) {
+ upto(from, to, defaultUnitFor(from), closure);
+ }
+
+ /**
+ * Iterates from this to the {@code to} {@link java.time.temporal.Temporal}, inclusive, incrementing by one
+ * {@code unit} each iteration, calling the closure once per iteration. The closure may accept a single
+ * {@link java.time.temporal.Temporal} argument.
+ * <p>
+ * If the unit is too large to iterate to the second Temporal exactly, such as iterating from two LocalDateTimes
+ * that are seconds apart using {@java.time.temporal.ChronoUnit#DAYS} as the unit, the iteration will cease
+ * as soon as the current value of the iteration is later than the second Temporal argument. The closure will
+ * not be called with any value later than the {@code to} value.
+ *
+ * @param from the starting Temporal
+ * @param to the ending Temporal
+ * @param unit the TemporalUnit to increment by
+ * @param closure the zero or one-argument closure to call
+ * @throws GroovyRuntimeException if this value is later than {@code to}
+ * @throws GroovyRuntimeException if {@code to} is a different type than this
+ * @since 2.5.0
+ */
+ public static void upto(Temporal from, Temporal to, TemporalUnit unit, Closure closure) {
+ if (isUptoEligible(from, to)) {
+ for (Temporal i = from; isUptoEligible(i, to); i = i.plus(1, unit)) {
+ closure.call(i);
+ }
+ } else {
+ throw new GroovyRuntimeException("The argument (" + to +
+ ") to upto() cannot be earlier than the value (" + from + ") it's called on.");
+ }
+ }
+
+ /**
+ * Returns true if the {@code from} can be iterated up to {@code to}.
+ */
+ private static boolean isUptoEligible(Temporal from, Temporal to) {
+ TemporalAmount amount = rightShift(from, to);
+ if (amount instanceof Period) {
+ return isNonnegative((Period) amount);
+ } else if (amount instanceof Duration) {
+ return isNonnegative((Duration) amount);
+ } else {
+ throw new GroovyRuntimeException("Temporal implementations of "
+ + from.getClass().getCanonicalName() + " are not supported by upto().");
+ }
+ }
+
+ /**
+ * Iterates from this to the {@code to} {@link java.time.temporal.Temporal}, inclusive, decrementing by one
+ * unit each iteration, calling the closure once per iteration. The closure may accept a single
+ * {@link java.time.temporal.Temporal} argument.
+ * <p>
+ * The particular unit decremented by depends on the specific sub-type of {@link java.time.temporal.Temporal}.
+ * Most sub-types use a unit of {@link java.time.temporal.ChronoUnit#SECONDS} except for
+ * <ul>
+ * <li>{@link java.time.chrono.ChronoLocalDate} and its sub-types use {@link java.time.temporal.ChronoUnit#DAYS}.
+ * <li>{@link java.time.YearMonth} uses {@link java.time.temporal.ChronoUnit#MONTHS}.
+ * <li>{@link java.time.Year} uses {@link java.time.temporal.ChronoUnit#YEARS}.
+ * </ul>
+ *
+ * @param from the starting Temporal
+ * @param to the ending Temporal
+ * @param closure the zero or one-argument closure to call
+ * @throws GroovyRuntimeException if this value is earlier than {@code to}
+ * @throws GroovyRuntimeException if {@code to} is a different type than this
+ * @since 2.5.0
+ */
+ public static void downto(Temporal from, Temporal to, Closure closure) {
+ downto(from, to, defaultUnitFor(from), closure);
+ }
+
+ /**
+ * Iterates from this to the {@code to} {@link java.time.temporal.Temporal}, inclusive, decrementing by one
+ * {@code unit} each iteration, calling the closure once per iteration. The closure may accept a single
+ * {@link java.time.temporal.Temporal} argument.
+ * <p>
+ * If the unit is too large to iterate to the second Temporal exactly, such as iterating from two LocalDateTimes
+ * that are seconds apart using {@java.time.temporal.ChronoUnit#DAYS} as the unit, the iteration will cease
+ * as soon as the current value of the iteration is earlier than the second Temporal argument. The closure will
+ * not be called with any value earlier than the {@code to} value.
+ *
+ * @param from the starting Temporal
+ * @param to the ending Temporal
+ * @param unit the TemporalUnit to increment by
+ * @param closure the zero or one-argument closure to call
+ * @throws GroovyRuntimeException if this value is earlier than {@code to}
+ * @throws GroovyRuntimeException if {@code to} is a different type than this
+ * @since 2.5.0
+ */
+ public static void downto(Temporal from, Temporal to, TemporalUnit unit, Closure closure) {
+ if (isDowntoEligible(from, to)) {
+ for (Temporal i = from; isDowntoEligible(i, to); i = i.minus(1, unit)) {
+ closure.call(i);
+ }
+ } else {
+ throw new GroovyRuntimeException("The argument (" + to +
+ ") to downto() cannot be later than the value (" + from + ") it's called on.");
+ }
+ }
+
+ /**
+ * Returns true if the {@code from} can be iterated down to {@code to}.
+ */
+ private static boolean isDowntoEligible(Temporal from, Temporal to) {
+ TemporalAmount amount = rightShift(from, to);
+ if (amount instanceof Period) {
+ return isNonpositive((Period) amount);
+ } else if (amount instanceof Duration) {
+ return isNonpositive((Duration) amount);
+ } else {
+ throw new GroovyRuntimeException("Temporal implementations of "
+ + from.getClass().getCanonicalName() + " are not supported by downto().");
+ }
+ }
+
+ /**
+ * Returns a {@link java.time.Duration} or {@link java.time.Period} between this (inclusive) and the {@code other}
+ * {@link java.time.temporal.Temporal} (exclusive).
+ * <p>
+ * A Period will be returned for types {@link java.time.Year}, {@link java.time.YearMonth}, and
+ * {@link java.time.chrono.ChronoLocalDate}; otherwise, a Duration will be returned.
+ * <p>
+ * Note: if the Temporal is a ChronoLocalDate but not a {@link java.time.LocalDate}, a general
+ * {@link java.time.chrono.ChronoPeriod} will be returned as per the return type of the method
+ * {@link java.time.chrono.ChronoLocalDate#until(ChronoLocalDate)} .
+ *
+ * @param self a Temporal
+ * @param other another Temporal of the same type
+ * @return an TemporalAmount between the two Temporals
+ * @since 2.5.0
+ */
+ public static TemporalAmount rightShift(final Temporal self, Temporal other) {
+ if (!self.getClass().equals(other.getClass())) {
+ throw new GroovyRuntimeException("Temporal arguments must be of the same type.");
+ }
+ switch ((ChronoUnit) defaultUnitFor(self)) {
+ case YEARS:
+ return DateTimeStaticExtensions.between(null, (Year) self, (Year) other);
+ case MONTHS:
+ return DateTimeStaticExtensions.between(null, (YearMonth) self, (YearMonth) other);
+ case DAYS:
+ return ChronoPeriod.between((ChronoLocalDate) self, (ChronoLocalDate) other);
+ default:
+ return Duration.between(self, other);
+ }
+ }
+
+ /* ******** java.time.temporal.TemporalAccessor extension methods ******** */
+
+ /**
+ * Supports the getAt operator; equivalent to calling the
+ * {@link java.time.temporal.TemporalAccessor#getLong(java.time.temporal.TemporalField)} method.
+ *
+ * @param self a TemporalAccessor
+ * @param field a non-null TemporalField
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws UnsupportedTemporalTypeException if the field is not supported
+ * @throws ArithmeticException if numeric overflow occurs
+ * @since 2.5.0
+ */
+ public static long getAt(final TemporalAccessor self, TemporalField field) {
+ return self.getLong(field);
+ }
+
+ /* ******** java.time.temporal.TemporalAmount extension methods ******** */
+
+ /**
+ * Supports the getAt operator; equivalent to calling the
+ * {@link java.time.temporal.TemporalAmount#get(TemporalUnit)} method.
+ *
+ * @param self a TemporalAmount
+ * @param unit a non-null TemporalUnit
+ * @return the value for the field
+ * @throws DateTimeException if a value for the field cannot be obtained
+ * @throws UnsupportedTemporalTypeException if the field is not supported
+ * @throws ArithmeticException if numeric overflow occurs
+ * @since 2.5.0
+ */
+ public static long getAt(final TemporalAmount self, TemporalUnit unit) {
+ return self.get(unit);
+ }
+
+ /* ******** java.time.Duration extension methods ******** */
+
+ /**
+ * Returns a {@link java.time.Duration} that is {@code seconds} seconds longer than this duration.
+ *
+ * @param self a Duration
+ * @param seconds the number of seconds to add
+ * @return a Duration
+ * @since 2.5.0
+ */
+ public static Duration plus(final Duration self, long seconds) {
+ return self.plusSeconds(seconds);
+ }
+
+ /**
+ * Returns a {@link java.time.Duration} that is {@code seconds} seconds shorter that this duration.
+ *
+ * @param self a Duration
+ * @param seconds the number of seconds to subtract
+ * @return a Duration
+ * @since 2.5.0
+ */
+ public static Duration minus(final Duration self, long seconds) {
+ return self.minusSeconds(seconds);
+ }
+
+ /**
+ * Returns a {@link java.time.Duration} that is one second longer than this duration.
+ *
+ * @param self a Duration
+ * @return a Duration
+ * @since 2.5.0
+ */
+ public static Duration next(final Duration self) {
+ return self.plusSeconds(1);
+ }
+
+ /**
+ * Returns a {@link java.time.Duration} that is one second shorter than this duration.
+ *
+ * @param self a Duration
+ * @return a Duration
+ * @since 2.5.0
+ */
+ public static Duration previous(final Duration self) {
+ return self.minusSeconds(1);
+ }
+
+ /**
+ * Supports the unary minus operator; equivalent to calling the {@link Duration#negated()} method.
+ *
+ * @param self a Duration
+ * @return a Duration
+ * @since 2.5.0
+ */
+ public static Duration negative(final Duration self) {
+ return self.negated();
+ }
+
+ /**
+ * Supports the unary plus operator; equivalent to calling the {@link Duration#abs()} method.
+ *
+ * @param self a Duration
+ * @return a Duration
+ * @since 2.5.0
+ */
+ public static Duration positive(final Duration self) {
+ return self.abs();
+ }
+
+ /**
+ * Supports the multiplication operator; equivalent to calling the {@link Duration#multipliedBy(long)} method.
+ *
+ * @param self a Duration
+ * @param scalar the value to multiply by
+ * @return a Duration
+ * @since 2.5.0
+ */
+ public static Duration multiply(final Duration self, long scalar) {
+ return self.multipliedBy(scalar);
+ }
+
+ /**
+ * Supports the division operator; equivalent to calling the {@link Duration#dividedBy(long)} method.
+ *
+ * @param self a Duration
+ * @param scalar the value to divide by
+ * @return a Duration
+ * @since 2.5.0
+ */
+ public static Duration div(final Duration self, long scalar) {
+ return self.dividedBy(scalar);
+ }
+
+ /**
+ * Returns true if this duration is positive, excluding zero.
+ *
+ * @param self a Duration
+ * @return true if positive
+ * @since 2.5.0
+ */
+ public static boolean isPositive(final Duration self) {
+ return !self.isZero() && !self.isNegative();
+ }
+
+ /**
+ * Returns true if this duration is zero or positive.
+ *
+ * @param self a Duration
+ * @return true if nonnegative
+ * @since 2.5.0
+ */
+ public static boolean isNonnegative(final Duration self) {
+ return self.isZero() || !self.isNegative();
+ }
+
+ /**
+ * Returns true if this duration is zero or negative.
+ *
+ * @param self a Duration
+ * @return true if nonpositive
+ * @since 2.5.0
+ */
+ public static boolean isNonpositive(final Duration self) {
+ return self.isZero() || self.isNegative();
+ }
+
+ /* ******** java.time.Instant extension methods ******** */
+
+ /**
+ * Returns an {@link java.time.Instant} that is {@code seconds} seconds after this instant.
+ *
+ * @param self an Instant
+ * @param seconds the number of seconds to add
+ * @return an Instant
+ * @since 2.5.0
+ */
+ public static Instant plus(final Instant self, long seconds) {
+ return self.plusSeconds(seconds);
+ }
+
+ /**
+ * Returns an {@link java.time.Instant} that is {@code seconds} seconds before this instant.
+ *
+ * @param self an Instant
+ * @param seconds the number of seconds to subtract
+ * @return an Instant
+ * @since 2.5.0
+ */
+ public static Instant minus(final Instant self, long seconds) {
+ return self.minusSeconds(seconds);
+ }
+
+ /**
+ * Returns an {@link java.time.Instant} that is one second after this instant.
+ *
+ * @param self an Instant
+ * @return an Instant one second ahead
+ * @since 2.5.0
+ */
+ public static Instant next(final Instant self) {
+ return plus(self, 1);
+ }
+
+ /**
+ * Returns an {@link java.time.Instant} that one second before this instant.
+ *
+ * @param self an Instant
+ * @return an Instant one second behind
+ * @since 2.5.0
+ */
+ public static Instant previous(final Instant self) {
+ return minus(self, 1);
+ }
+
+ /**
+ * Returns a generally equivalent {@link java.util.Date} according the number of milliseconds since the epoch,
+ * adjusted into the system default time zone.
+ *
+ * @param self an Instant
+ * @return a Date
+ * @since 2.5.0
+ */
+ public static Date toDate(final Instant self) {
+ return new Date(self.toEpochMilli());
+ }
+
+ /**
+ * Returns a generally equivalent {@link java.util.Calendar} in the GMT time zone, truncated to milliseconds.
+ *
+ * @param self an Instant
+ * @return a Calendar
+ * @since 2.5.0
+ */
+ public static Calendar toCalendar(final Instant self) {
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+ cal.setTime(toDate(self));
+ return cal;
+ }
+
+ /* ******** java.time.LocalDate extension methods ******** */
+
+ /**
+ * Formats this date with the provided {@link java.time.format.DateTimeFormatter} pattern.
+ *
+ * @param self a LocalDate
+ * @param pattern the formatting pattern
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String format(final LocalDate self, String pattern) {
+ return self.format(DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Formats this date in the provided, localized {@link java.time.format.FormatStyle}.
+ *
+ * @param self a LocalDate
+ * @param dateStyle the FormatStyle
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String format(final LocalDate self, FormatStyle dateStyle) {
+ return self.format(DateTimeFormatter.ofLocalizedDate(dateStyle));
+ }
+
+ /**
+ * Formats this date with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE} formatter.
+ *
+ * @param self a LocalDate
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String getDateString(final LocalDate self) {
+ return self.format(DateTimeFormatter.ISO_LOCAL_DATE);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDate} that is {@code days} days after this date.
+ *
+ * @param self a LocalDate
+ * @param days the number of days to add
+ * @return a LocalDate
+ * @since 2.5.0
+ */
+ public static LocalDate plus(final LocalDate self, long days) {
+ return self.plusDays(days);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDate} that is {@code days} days before this date.
+ *
+ * @param self a LocalDate
+ * @param days the number of days to subtract
+ * @return a LocalDate
+ * @since 2.5.0
+ */
+ public static LocalDate minus(final LocalDate self, long days) {
+ return self.minusDays(days);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDate} one day after this date.
+ *
+ * @param self a LocalDate
+ * @return the next day
+ * @since 2.5.0
+ */
+ public static LocalDate next(final LocalDate self) {
+ return plus(self, 1);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDate} one day before this date.
+ *
+ * @param self a LocalDate
+ * @return the previous day
+ * @since 2.5.0
+ */
+ public static LocalDate previous(final LocalDate self) {
+ return minus(self, 1);
+ }
+
+ /**
+ * Returns a {@link java.time.Period} equivalent to the time between this date (inclusive)
+ * and the provided {@link java.time.LocalDate} (exclusive).
+ *
+ * @param self a LocalDate
+ * @param other another LocalDate
+ * @return a Period representing the time between the two LocalDates
+ * @since 2.5.0
+ */
+ public static Period rightShift(final LocalDate self, LocalDate other) {
+ return Period.between(self, other);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDateTime} from this date and the provided {@link java.time.LocalTime}.
+ *
+ * @param self a LocalDate
+ * @param time a LocalTime
+ * @return a LocalDateTime
+ * @since 2.5.0
+ */
+ public static LocalDateTime leftShift(final LocalDate self, LocalTime time) {
+ return LocalDateTime.of(self, time);
+ }
+
+ /**
+ * Returns a {@link java.time.OffsetDateTime} from this date and the provided {@link java.time.OffsetTime}.
+ *
+ * @param self a LocalDate
+ * @param time an OffsetTime
+ * @return an OffsetDateTime
+ * @since 2.5.0
+ */
+ public static OffsetDateTime leftShift(final LocalDate self, OffsetTime time) {
+ return time.atDate(self);
+ }
+
+ /**
+ * Returns an equivalent instance of {@link java.util.Date}.
+ * The time portion of the returned date is cleared.
+ *
+ * @param self a LocalDate
+ * @return a java.util.Date
+ * @since 2.5.0
+ */
+ public static Date toDate(final LocalDate self) {
+ return toCalendar(self).getTime();
+ }
+
+ /**
+ * Returns an equivalent instance of {@link java.util.Calendar}.
+ * The time portion of the returned calendar is cleared and the time zone is the current system default.
+ *
+ * @param self a LocalDate
+ * @return a java.util.Calendar
+ * @since 2.5.0
+ */
+ public static Calendar toCalendar(final LocalDate self) {
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.DATE, self.getDayOfMonth());
+ cal.set(Calendar.MONTH, self.getMonthValue() - 1);
+ cal.set(Calendar.YEAR, self.getYear());
+ clearTimeCommon(cal);
+ return cal;
+ }
+
+ /* duplicated with DateUtilExtensions utility method but we don't want the modules to depend on one another */
+ private static void clearTimeCommon(final Calendar self) {
+ self.set(Calendar.HOUR_OF_DAY, 0);
+ self.clear(Calendar.MINUTE);
+ self.clear(Calendar.SECOND);
+ self.clear(Calendar.MILLISECOND);
+ }
+
+ /* ******** java.time.LocalDateTime extension methods ******** */
+
+ /**
+ * Formats this date/time with the provided {@link java.time.format.DateTimeFormatter} pattern.
+ *
+ * @param self a LocalDateTime
+ * @param pattern the formatting pattern
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String format(final LocalDateTime self, String pattern) {
+ return self.format(DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Formats this date/time in the provided, localized {@link java.time.format.FormatStyle}.
+ *
+ * @param self a LocalDateTime
+ * @param dateTimeStyle the FormatStyle
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String format(final LocalDateTime self, FormatStyle dateTimeStyle) {
+ return self.format(DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle));
+ }
+
+ /**
+ * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE_TIME} formatter.
+ *
+ * @param self a LocalDateTime
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String getDateTimeString(final LocalDateTime self) {
+ return self.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
+ }
+
+ /**
+ * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE} formatter.
+ *
+ * @param self a LocalDateTime
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String getDateString(final LocalDateTime self) {
+ return self.format(DateTimeFormatter.ISO_LOCAL_DATE);
+ }
+
+ /**
+ * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_TIME} formatter.
+ *
+ * @param self a LocalDateTime
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String getTimeString(final LocalDateTime self) {
+ return self.format(DateTimeFormatter.ISO_LOCAL_TIME);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDateTime} with the time portion cleared.
+ *
+ * @param self a LocalDateTime
+ * @return a LocalDateTime
+ * @since 2.5.0
+ */
+ public static LocalDateTime clearTime(final LocalDateTime self) {
+ return self.truncatedTo(DAYS);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDateTime} that is {@code seconds} seconds after this date/time.
+ *
+ * @param self a LocalDateTime
+ * @param seconds the number of seconds to add
+ * @return a LocalDateTime
+ * @since 2.5.0
+ */
+ public static LocalDateTime plus(final LocalDateTime self, long seconds) {
+ return self.plusSeconds(seconds);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDateTime} that is {@code seconds} seconds before this date/time.
+ *
+ * @param self a LocalDateTime
+ * @param seconds the number of seconds to subtract
+ * @return a LocalDateTime
+ * @since 2.5.0
+ */
+ public static LocalDateTime minus(final LocalDateTime self, long seconds) {
+ return self.minusSeconds(seconds);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDateTime} that is one second after this date/time.
+ *
+ * @param self a LocalDateTime
+ * @return a LocalDateTime
+ * @since 2.5.0
+ */
+ public static LocalDateTime next(final LocalDateTime self) {
+ return plus(self, 1);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDateTime} that is one second before this date/time.
+ *
+ * @param self a LocalDateTime
+ * @return a LocalDateTime
+ * @since 2.5.0
+ */
+ public static LocalDateTime previous(final LocalDateTime self) {
+ return minus(self, 1);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetDateTime} of this date/time and the provided {@link java.time.ZoneOffset}.
+ *
+ * @param self a LocalDateTime
+ * @param offset a ZoneOffset
+ * @return an OffsetDateTime
+ * @since 2.5.0
+ */
+ public static OffsetDateTime leftShift(final LocalDateTime self, ZoneOffset offset) {
+ return OffsetDateTime.of(self, offset);
+ }
+
+ /**
+ * Returns a {@link java.time.OffsetDateTime} of this date/time and the provided {@link java.time.ZoneId}.
+ *
+ * @param self a LocalDateTime
+ * @param zone a ZoneId
+ * @return a ZonedDateTime
+ * @since 2.5.0
+ */
+ public static ZonedDateTime leftShift(final LocalDateTime self, ZoneId zone) {
+ return ZonedDateTime.of(self, zone);
+ }
+
+ /**
+ * Returns a generally equivalent instance of {@link java.util.Date}.
+ * The time value of the returned date is truncated to milliseconds.
+ *
+ * @param self a LocalDateTime
+ * @return a java.util.Date
+ * @since 2.5.0
+ */
+ public static Date toDate(final LocalDateTime self) {
+ return toCalendar(self).getTime();
+ }
+
+ /**
+ * Returns a generally equivalent instance of {@link java.util.Calendar}.
+ * The time value of the returned calendar is truncated to milliseconds and the
+ * time zone is the current system default.
+ *
+ * @param self a LocalDateTime
+ * @return a java.util.Calendar
+ * @since 2.5.0
+ */
+ public static Calendar toCalendar(final LocalDateTime self) {
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.DATE, self.getDayOfMonth());
+ cal.set(Calendar.MONTH, self.getMonthValue() - 1);
+ cal.set(Calendar.YEAR, self.getYear());
+ cal.set(Calendar.HOUR_OF_DAY, self.getHour());
+ cal.set(Calendar.MINUTE, self.getMinute());
+ cal.set(Calendar.SECOND, self.getSecond());
+ cal.set(Calendar.MILLISECOND, millisFromNanos(self.getNano()));
+ return cal;
+ }
+
+ /* ******** java.time.LocalTime extension methods ******** */
+
+ /**
+ * Formats this time with the provided {@link java.time.format.DateTimeFormatter} pattern.
+ *
+ * @param self a LocalDateTime
+ * @param pattern the formatting pattern
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String format(final LocalTime self, String pattern) {
+ return self.format(DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Formats this time in the provided, localized {@link java.time.format.FormatStyle}.
+ *
+ * @param self a LocalTime
+ * @param timeStyle the FormatStyle
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String format(final LocalTime self, FormatStyle timeStyle) {
+ return self.format(DateTimeFormatter.ofLocalizedTime(timeStyle));
+ }
+
+ /**
+ * Formats this time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_TIME} formatter.
+ *
+ * @param self a LocalTime
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String getTimeString(final LocalTime self) {
+ return self.format(DateTimeFormatter.ISO_LOCAL_TIME);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalTime} that is {@code seconds} seconds after this time.
+ *
+ * @param self a LocalTime
+ * @param seconds the number of seconds to add
+ * @return a LocalTime
+ * @since 2.5.0
+ */
+ public static LocalTime plus(final LocalTime self, long seconds) {
+ return self.plusSeconds(seconds);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalTime} that is {@code seconds} seconds before this time.
+ *
+ * @param self a LocalTime
+ * @param seconds the number of seconds to subtract
+ * @return a LocalTime
+ * @since 2.5.0
+ */
+ public static LocalTime minus(final LocalTime self, long seconds) {
+ return self.minusSeconds(seconds);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalTime} that is one second after this time.
+ *
+ * @param self a LocalTime
+ * @return a LocalTime
+ * @since 2.5.0
+ */
+ public static LocalTime next(final LocalTime self) {
+ return plus(self, 1);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalTime} that is one second before this time.
+ *
+ * @param self a LocalTime
+ * @return a LocalTime
+ * @since 2.5.0
+ */
+ public static LocalTime previous(final LocalTime self) {
+ return minus(self, 1);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDateTime} of this time and the provided {@link java.time.LocalDate}.
+ *
+ * @param self a LocalTime
+ * @param date a LocalDate
+ * @return a LocalDateTime
+ * @since 2.5.0
+ */
+ public static LocalDateTime leftShift(final LocalTime self, LocalDate date) {
+ return LocalDateTime.of(date, self);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetTime} of this time and the provided {@link java.time.ZoneOffset}.
+ *
+ * @param self a LocalTime
+ * @param offset a ZoneOffset
+ * @return an OffsetTime
+ * @since 2.5.0
+ */
+ public static OffsetTime leftShift(final LocalTime self, ZoneOffset offset) {
+ return OffsetTime.of(self, offset);
+ }
+
+ /**
+ * Returns a generally equivalent instance of {@link java.util.Date}. The day-month-year value of the
+ * returned date is today and the time is truncated to milliseconds.
+ *
+ * @param self a LocalTime
+ * @return a java.util.Date
+ * @since 2.5.0
+ */
+ public static Date toDate(final LocalTime self) {
+ return toCalendar(self).getTime();
+ }
+
+ /**
+ * Returns a generally equivalent instance of {@link java.util.Calendar}. The day-month-year value of the
+ * returned calendar is today, the time is truncated to milliseconds, and the time zone is the current
+ * system default.
+ *
+ * @param self a LocalTime
+ * @return a java.util.Calendar
+ * @since 2.5.0
+ */
+ public static Calendar toCalendar(final LocalTime self) {
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.HOUR_OF_DAY, self.getHour());
+ cal.set(Calendar.MINUTE, self.getMinute());
+ cal.set(Calendar.SECOND, self.getSecond());
+ cal.set(Calendar.MILLISECOND, millisFromNanos(self.getNano()));
+ return cal;
+ }
+
+ /* ******** java.time.MonthDay extension methods ******** */
+
+ /**
+ * Returns a {@link java.time.LocalDate} of this month/day and the provided year.
+ *
+ * @param self a MonthDay
+ * @param year a year
+ * @return a LocalDate
+ * @since 2.5.0
+ */
+ public static LocalDate leftShift(final MonthDay self, int year) {
+ return self.atYear(year);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDate} of this month/day and the provided {@link java.time.Year}.
+ *
+ * @param self a MonthDay
+ * @param year a Year
+ * @return a LocalDate
+ * @since 2.5.0
+ */
+ public static LocalDate leftShift(final MonthDay self, Year year) {
+ return year.atMonthDay(self);
+ }
+
+ /* ******** java.time.OffsetDateTime extension methods ******** */
+
+ /**
+ * Formats this date/time with the provided {@link java.time.format.DateTimeFormatter} pattern.
+ *
+ * @param self an OffsetDateTime
+ * @param pattern the formatting pattern
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String format(final OffsetDateTime self, String pattern) {
+ return self.format(DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Formats this date/time in the provided, localized {@link java.time.format.FormatStyle}.
+ *
+ * @param self an OffsetDateTime
+ * @param dateTimeStyle the FormatStyle
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String format(final OffsetDateTime self, FormatStyle dateTimeStyle) {
+ return self.format(DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle));
+ }
+
+ /**
+ * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_OFFSET_DATE_TIME} formatter.
+ *
+ * @param self an OffsetDateTime
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String getDateTimeString(final OffsetDateTime self) {
+ return self.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+ }
+
+ /**
+ * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_OFFSET_DATE} formatter.
+ *
+ * @param self an OffsetDateTime
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String getDateString(final OffsetDateTime self) {
+ return self.format(DateTimeFormatter.ISO_OFFSET_DATE);
+ }
+
+ /**
+ * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_OFFSET_TIME} formatter.
+ *
+ * @param self an OffsetDateTime
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String getTimeString(final OffsetDateTime self) {
+ return self.format(DateTimeFormatter.ISO_OFFSET_TIME);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetDateTime} with the time portion cleared.
+ *
+ * @param self an OffsetDateTime
+ * @return an OffsetDateTime
+ * @since 2.5.0
+ */
+ public static OffsetDateTime clearTime(final OffsetDateTime self) {
+ return self.truncatedTo(DAYS);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetDateTime} that is {@code seconds} seconds after this date/time.
+ *
+ * @param self an OffsetDateTime
+ * @param seconds the number of seconds to add
+ * @return an OffsetDateTime
+ * @since 2.5.0
+ */
+ public static OffsetDateTime plus(final OffsetDateTime self, long seconds) {
+ return self.plusSeconds(seconds);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetDateTime} that is {@code seconds} seconds before this date/time.
+ *
+ * @param self an OffsetDateTime
+ * @param seconds the number of seconds to subtract
+ * @return an OffsetDateTime
+ * @since 2.5.0
+ */
+ public static OffsetDateTime minus(final OffsetDateTime self, long seconds) {
+ return self.minusSeconds(seconds);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetDateTime} one second after this date/time.
+ *
+ * @param self an OffsetDateTime
+ * @return an OffsetDateTime
+ * @since 2.5.0
+ */
+ public static OffsetDateTime next(final OffsetDateTime self) {
+ return plus(self, 1);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetDateTime} one second before this date/time.
+ *
+ * @param self an OffsetDateTime
+ * @return an OffsetDateTime
+ * @since 2.5.0
+ */
+ public static OffsetDateTime previous(final OffsetDateTime self) {
+ return minus(self, 1);
+ }
+
+ /**
+ * Returns a generally equivalent instance of {@link java.util.Date}.
+ * The time value of the returned date is truncated to milliseconds and will be
+ * adjusted to the current system default time zone.
+ *
+ * @param self an OffsetDateTime
+ * @return a java.util.Date
+ * @since 2.5.0
+ */
+ public static Date toDate(final OffsetDateTime self) {
+ return toCalendar(self).getTime();
+ }
+
+ /**
+ * Returns a generally equivalent instance of {@link java.util.Calendar}.
+ * The time value of the returned calendar is truncated to milliseconds and the time zone
+ * is based on the offset of this date/time.
+ *
+ * @param self an OffsetDateTime
+ * @return a java.util.Calendar
+ * @since 2.5.0
+ */
+ public static Calendar toCalendar(final OffsetDateTime self) {
+ return toCalendar(self.toZonedDateTime());
+ }
+
+ /* ******** java.time.OffsetTime extension methods ******** */
+
+ /**
+ * Formats this time with the provided {@link java.time.format.DateTimeFormatter} pattern.
+ *
+ * @param self an OffsetTime
+ * @param pattern the formatting pattern
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String format(final OffsetTime self, String pattern) {
+ return self.format(DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Formats this time in the provided, localized {@link java.time.format.FormatStyle}.
+ *
+ * @param self an OffsetTime
+ * @param timeStyle the FormatStyle
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String format(final OffsetTime self, FormatStyle timeStyle) {
+ return self.format(DateTimeFormatter.ofLocalizedTime(timeStyle));
+ }
+
+ /**
+ * Formats this time with the {@link java.time.format.DateTimeFormatter#ISO_OFFSET_TIME} formatter.
+ *
+ * @param self an OffsetTime
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String getTimeString(final OffsetTime self) {
+ return self.format(DateTimeFormatter.ISO_OFFSET_TIME);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetTime} that is {@code seconds} seconds after this time.
+ *
+ * @param self an OffsetTime
+ * @param seconds the number of seconds to add
+ * @return an OffsetTime
+ * @since 2.5.0
+ */
+ public static OffsetTime plus(final OffsetTime self, long seconds) {
+ return self.plusSeconds(seconds);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetTime} that is {@code seconds} seconds before this time.
+ *
+ * @param self an OffsetTime
+ * @param seconds the number of seconds to subtract
+ * @return an OffsetTime
+ * @since 2.5.0
+ */
+ public static OffsetTime minus(final OffsetTime self, long seconds) {
+ return self.minusSeconds(seconds);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetTime} that is one second after this time.
+ *
+ * @param self an OffsetTime
+ * @return an OffsetTime
+ * @since 2.5.0
+ */
+ public static OffsetTime next(final OffsetTime self) {
+ return plus(self, 1);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetTime} that is one second before this time.
+ *
+ * @param self an OffsetTime
+ * @return an OffsetTime
+ * @since 2.5.0
+ */
+ public static OffsetTime previous(final OffsetTime self) {
+ return minus(self, 1);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetDateTime} of this time and the provided {@link java.time.LocalDate}.
+ *
+ * @param self an OffsetTime
+ * @param date a LocalDate
+ * @return an OffsetDateTime
+ * @since 2.5.0
+ */
+ public static OffsetDateTime leftShift(final OffsetTime self, LocalDate date) {
+ return OffsetDateTime.of(date, self.toLocalTime(), self.getOffset());
+ }
+
+ /**
+ * Returns a generally equivalent instance of {@link java.util.Date}.
+ * The time value of the returned date is truncated to milliseconds and will be
+ * adjusted to the current system default time zone.
+ *
+ * @param self an OffsetTime
+ * @return a java.util.Date
+ * @since 2.5.0
+ */
+ public static Date toDate(final OffsetTime self) {
+ return toCalendar(self).getTime();
+ }
+
+ /**
+ * Returns a generally equivalent instance of {@link java.util.Calendar}.
+ * The date value of the returned calendar is now, the time value is truncated to milliseconds,
+ * and the time zone is based on the offset of this time.
+ *
+ * @param self an OffsetTime
+ * @return a java.util.Calendar
+ * @since 2.5.0
+ */
+ public static Calendar toCalendar(final OffsetTime self) {
+ TimeZone timeZone = toTimeZone(self.getOffset());
+ Calendar cal = Calendar.getInstance(timeZone);
+ cal.set(Calendar.HOUR_OF_DAY, self.getHour());
+ cal.set(Calendar.MINUTE, self.getMinute());
+ cal.set(Calendar.SECOND, self.getSecond());
+ cal.set(Calendar.MILLISECOND, millisFromNanos(self.getNano()));
+ return cal;
+ }
+
+ /* ******** java.time.Period extension methods ******** */
+
+ /**
+ * Returns a {@link java.time.Period} that is {@code days} days longer than this period.
+ * No normalization is performed.
+ *
+ * @param self a Period
+ * @param days the number of days to increase this Period by
+ * @return a Period
+ * @since 2.5.0
+ */
+ public static Period plus(final Period self, long days) {
+ return self.plusDays(days);
+ }
+
+ /**
+ * Returns a {@link java.time.Period} that is {@code days} days shorter than this period.
+ * No normalization is performed.
+ *
+ * @param self a Period
+ * @param days the number of days to decrease this Period by
+ * @return a Period
+ * @since 2.5.0
+ */
+ public static Period minus(final Period self, long days) {
+ return self.minusDays(days);
+ }
+
+ /**
+ * Returns a {@link java.time.Period} that is one day longer than this period.
+ * No normalization is performed.
+ *
+ * @param self a Period
+ * @return a Period one day longer in length
+ * @since 2.5.0
+ */
+ public static Period next(final Period self) {
+ return plus(self, 1);
+ }
+
+ /**
+ * Returns a {@link java.time.Period} that is one day shorter than this period.
+ * No normalization is performed.
+ *
+ * @param self a Period
+ * @return a Period one day shorter in length
+ * @since 2.5.0
+ */
+ public static Period previous(final Period self) {
+ return minus(self, 1);
+ }
+
+ /**
+ * Supports the unary minus operator; equivalent to calling the {@link java.time.Period#negated()} method.
+ *
+ * @param self a Period
+ * @return a negated Period
+ * @since 2.5.0
+ */
+ public static Period negative(final Period self) {
+ return self.negated();
+ }
+
+ /**
+ * Supports the unary plus operator; returns a {@link java.time.Period} with all unit values positive.
+ * For example, a period of "2 years, -3 months, and -4 days" would result in a period of
+ * "2 years, 3 months, and 4 days." No normalization is performed.
+ *
+ * @param self a Period
+ * @return a positive Period
+ * @since 2.5.0
+ */
+ public static Period positive(final Period self) {
+ return !self.isNegative() ? self : self.withDays(Math.abs(self.getDays()))
+ .withMonths(Math.abs(self.getMonths()))
+ .withYears(Math.abs(self.getYears()));
+ }
+
+ /**
+ * Supports the multiply operator; equivalent to calling the {@link java.time.Period#multipliedBy(int)} method.
+ *
+ * @param self a Period
+ * @param scalar a scalar to multiply each unit by
+ * @return a Period
+ * @since 2.5.0
+ */
+ public static Period multiply(final Period self, int scalar) {
+ return self.multipliedBy(scalar);
+ }
+
+ /**
+ * Returns true if this period is positive, excluding zero.
+ *
+ * @param self a ChronoPeriod
+ * @return true if positive
+ * @since 2.5.0
+ */
+ public static boolean isPositive(final ChronoPeriod self) {
+ return !self.isZero() && !self.isNegative();
+ }
+
+ /**
+ * Returns true if this period is zero or positive.
+ *
+ * @param self a ChronoPeriod
+ * @return true if nonnegative
+ * @since 2.5.0
+ */
+ public static boolean isNonnegative(final ChronoPeriod self) {
+ return self.isZero() || !self.isNegative();
+ }
+
+ /**
+ * Returns true if this period is zero or negative.
+ *
+ * @param self a ChronoPeriod
+ * @return true if nonpositive
+ * @since 2.5.0
+ */
+ public static boolean isNonpositive(final ChronoPeriod self) {
+ return self.isZero() || self.isNegative();
+ }
+
+ /* ******** java.time.Year extension methods ******** */
+
+ /**
+ * Returns a {@link java.time.Year} that is {@code years} years after this year.
+ *
+ * @param self a Year
+ * @param years the number of years to add
+ * @return a Year
+ * @since 2.5.0
+ */
+ public static Year plus(final Year self, long years) {
+ return self.plusYears(years);
+ }
+
+ /**
+ * Returns a {@link java.time.Year} that is {@code years} years before this year.
+ *
+ * @param self a Year
+ * @param years the number of years to subtract
+ * @return a Year
+ * @since 2.5.0
+ */
+ public static Year minus(final Year self, long years) {
+ return self.minusYears(years);
+ }
+
+ /**
+ * Returns a {@link java.time.Year} after this year.
+ *
+ * @param self a Year
+ * @return the next Year
+ * @since 2.5.0
+ */
+ public static Year next(final Year self) {
+ return plus(self, 1);
+ }
+
+ /**
+ * Returns a {@link java.time.Year} before this year.
+ *
+ * @param self a Year
+ * @return the previous Year
+ * @since 2.5.0
+ */
+ public static Year previous(final Year self) {
+ return minus(self, 1);
+ }
+
+ /**
+ * Returns a {@link java.time.Period} between the first day of this year (inclusive) and the first day of the
+ * provided {@link java.time.Year} (exclusive).
+ *
+ * @param self a Year
+ * @param year another Year
+ * @return a Period between the Years
+ * @since 2.5.0
+ */
+ public static Period rightShift(final Year self, Year year) {
+ return Period.between(self.atDay(1), year.atDay(1));
+ }
+
+ /**
+ * Returns a {@link java.time.YearMonth} of this year and the provided {@link java.time.Month}.
+ *
+ * @param self a Year
+ * @param month a Month
+ * @return a YearMonth
+ * @since 2.5.0
+ */
+ public static YearMonth leftShift(final Year self, Month month) {
+ return self.atMonth(month);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDate} of this year on the given {@link java.time.MonthDay}.
+ *
+ * @param self a Year
+ * @param monthDay a MonthDay
+ * @return a LocalDate
+ * @since 2.5.0
+ */
+ public static LocalDate leftShift(final Year self, MonthDay monthDay) {
+ return self.atMonthDay(monthDay);
+ }
+
+ /**
+ * Equivalent to calling the {@link java.time.Year#get(java.time.temporal.TemporalField)} method with a
+ * {@link java.time.temporal.ChronoField#ERA} argument.
+ * <p>
+ * Returns the era of the year, which is currently either 0 (BC) or 1 (AD).
+ *
+ * @param self a Year
+ * @return an int representing the era
+ * @since 2.5.0
+ */
+ public static int getEra(final Year self) {
+ return self.get(ChronoField.ERA);
+ }
+
+ /**
+ * Equivalent to calling the {@link java.time.Year#get(java.time.temporal.TemporalField)} method with a
+ * {@link java.time.temporal.ChronoField#YEAR_OF_ERA} argument.
+ * <p>
+ * Since Year=0 represents 1 BC, the yearOfEra value of Year=0 is 1, Year=-1 is 2, and so on.
+ *
+ * @param self a Year
+ * @return the year value of the era
+ * @since 2.5.0
+ */
+ public static int getYearOfEra(final Year self) {
+ return self.get(ChronoField.YEAR_OF_ERA);
+ }
+
+ /* ******** java.time.YearMonth extension methods ******** */
+
+ /**
+ * Returns a {@link java.time.YearMonth} that is {@code months} months after this year/month.
+ *
+ * @param self a YearMonth
+ * @param months the number of months to add
+ * @return a Year
+ * @since 2.5.0
+ */
+ public static YearMonth plus(final YearMonth self, long months) {
+ return self.plusMonths(months);
+ }
+
+ /**
+ * Returns a {@link java.time.YearMonth} that is {@code months} months before this year/month.
+ *
+ * @param self a YearMonth
+ * @param months the number of months to subtract
+ * @return a Year
+ * @since 2.5.0
+ */
+ public static YearMonth minus(final YearMonth self, long months) {
+ return self.minusMonths(months);
+ }
+
+ /**
+ * Returns a {@link java.time.YearMonth} that is the month after this year/month.
+ *
+ * @param self a YearMonth
+ * @return the next YearMonth
+ * @since 2.5.0
+ */
+ public static YearMonth next(final YearMonth self) {
+ return plus(self, 1);
+ }
+
+ /**
+ * Returns a {@link java.time.YearMonth} that is the month before this year/month.
+ *
+ * @param self a YearMonth
+ * @return the previous YearMonth
+ * @since 2.5.0
+ */
+ public static YearMonth previous(final YearMonth self) {
+ return minus(self, 1);
+ }
+
+ /**
+ * Returns a {@link java.time.LocalDate} of this year/month and the given day of the month.
+ *
+ * @param self a YearMonth
+ * @param dayOfMonth a day of the month
+ * @return a LocalDate
+ * @since 2.5.0
+ */
+ public static LocalDate leftShift(final YearMonth self, int dayOfMonth) {
+ return self.atDay(dayOfMonth);
+ }
+
+ /**
+ * Returns a {@link java.time.Period} of time between the first day of this year/month (inclusive) and the
+ * given {@link java.time.YearMonth} (exclusive).
+ *
+ * @param self a YearMonth
+ * @param other another YearMonth
+ * @return a Period
+ * @since 2.5.0
+ */
+ public static Period rightShift(YearMonth self, YearMonth other) {
+ return Period.between(self.atDay(1), other.atDay(1));
+ }
+
+ /* ******** java.time.ZonedDateTime extension methods ******** */
+
+ /**
+ * Formats this date/time with the provided {@link java.time.format.DateTimeFormatter} pattern.
+ *
+ * @param self a ZonedDateTime
+ * @param pattern the formatting pattern
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String format(final ZonedDateTime self, String pattern) {
+ return self.format(DateTimeFormatter.ofPattern(pattern));
+ }
+
+ /**
+ * Formats this date/time in the provided, localized {@link java.time.format.FormatStyle}.
+ *
+ * @param self a ZonedDateTime
+ * @param dateTimeStyle the FormatStyle
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String format(final ZonedDateTime self, FormatStyle dateTimeStyle) {
+ return self.format(DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle));
+ }
+
+ /**
+ * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE_TIME} formatter
+ * and appends the zone's short name, e.g. {@code 2018-03-10T14:34:55.144EST}.
+ *
+ * @param self a ZonedDateTime
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String getDateTimeString(final ZonedDateTime self) {
+ return self.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + self.format(ZONE_SHORT_FORMATTER);
+ }
+
+ /**
+ * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE} formatter
+ * and appends the zone's short name, e.g. {@code 2018-03-10EST}.
+ *
+ * @param self a ZonedDateTime
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String getDateString(final ZonedDateTime self) {
+ return self.format(DateTimeFormatter.ISO_LOCAL_DATE) + self.format(ZONE_SHORT_FORMATTER);
+ }
+
+ /**
+ * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_TIME} formatter
+ * and appends the zone's short name, e.g. {@code 14:34:55.144EST}.
+ *
+ * @param self a ZonedDateTime
+ * @return a formatted String
+ * @see java.time.format.DateTimeFormatter
+ * @since 2.5.0
+ */
+ public static String getTimeString(final ZonedDateTime self) {
+ return self.format(DateTimeFormatter.ISO_LOCAL_TIME) + self.format(ZONE_SHORT_FORMATTER);
+ }
+
+ /**
+ * Returns an {@link java.time.ZonedDateTime} with the time portion cleared.
+ *
+ * @param self a ZonedDateTime
+ * @return a ZonedDateTime
+ * @since 2.5.0
+ */
+ public static ZonedDateTime clearTime(final ZonedDateTime self) {
+ return self.truncatedTo(DAYS);
+ }
+
+ /**
+ * Returns a {@link java.time.ZonedDateTime} that is {@code seconds} seconds after this date/time.
+ *
+ * @param self an ZonedDateTime
+ * @param seconds the number of seconds to add
+ * @return a ZonedDateTime
+ * @since 2.5.0
+ */
+ public static ZonedDateTime plus(final ZonedDateTime self, long seconds) {
+ return self.plusSeconds(seconds);
+ }
+
+ /**
+ * Returns a {@link java.time.ZonedDateTime} that is {@code seconds} seconds before this date/time.
+ *
+ * @param self a ZonedDateTime
+ * @param seconds the number of seconds to subtract
+ * @return a ZonedDateTime
+ * @since 2.5.0
+ */
+ public static ZonedDateTime minus(final ZonedDateTime self, long seconds) {
+ return self.minusSeconds(seconds);
+ }
+
+ /**
+ * Returns a {@link java.time.ZonedDateTime} that is one second after this date/time.
+ *
+ * @param self a ZonedDateTime
+ * @return a ZonedDateTime
+ * @since 2.5.0
+ */
+ public static ZonedDateTime next(final ZonedDateTime self) {
+ return plus(self, 1);
+ }
+
+ /**
+ * Returns a {@link java.time.ZonedDateTime} that is one second before this date/time.
+ *
+ * @param self a ZonedDateTime
+ * @return a ZonedDateTime
+ * @since 2.5.0
+ */
+ public static ZonedDateTime previous(final ZonedDateTime self) {
+ return minus(self, 1);
+ }
+
+ /**
+ * Returns a generally equivalent instance of {@link java.util.Date}.
+ * The time value of the returned date is truncated to milliseconds and will be
+ * adjusted to the current system default time zone.
+ *
+ * @param self a ZonedDateTime
+ * @return a java.util.Date
+ * @since 2.5.0
+ */
+ public static Date toDate(final ZonedDateTime self) {
+ return toCalendar(self).getTime();
+ }
+
+ /**
+ * Returns a generally equivalent instance of {@link java.util.Calendar}.
+ * The time value of the returned calendar is truncated to milliseconds and the time zone
+ * is determined by the zone of this date/time.
+ *
+ * @param self an ZonedDateTime
+ * @return a java.util.Calendar
+ * @since 2.5.0
+ */
+ public static Calendar toCalendar(final ZonedDateTime self) {
+ Calendar cal = Calendar.getInstance(toTimeZone(self.getZone()));
+ cal.set(Calendar.DATE, self.getDayOfMonth());
+ cal.set(Calendar.MONTH, self.getMonthValue() - 1);
+ cal.set(Calendar.YEAR, self.getYear());
+ cal.set(Calendar.HOUR_OF_DAY, self.getHour());
+ cal.set(Calendar.MINUTE, self.getMinute());
+ cal.set(Calendar.SECOND, self.getSecond());
+ cal.set(Calendar.MILLISECOND, millisFromNanos(self.getNano()));
+ return cal;
+ }
+
+ /* ******** java.time.ZoneId extension methods ******** */
+
+ /**
+ * Returns a {@link java.util.TimeZone} equivalent to this zone.
+ *
+ * @param self a ZoneId
+ * @return a TimeZone
+ * @since 2.5.0
+ */
+ public static TimeZone toTimeZone(final ZoneId self) {
+ return TimeZone.getTimeZone(self);
+ }
+
+ /**
+ * Returns the name of this zone formatted according to the {@link java.time.format.TextStyle#FULL} text style.
+ *
+ * @param self a ZoneId
+ * @return the full display name of the ZoneId
+ * @since 2.5.0
+ */
+ public static String getFullName(final ZoneId self) {
+ return getFullName(self, Locale.getDefault());
+ }
+
+ /**
+ * Returns the name of this zone formatted according to the {@link java.time.format.TextStyle#FULL} text style
+ * for the provided {@link java.util.Locale}.
+ *
+ * @param self a ZoneId
+ * @param locale a Locale
+ * @return the full display name of the ZoneId
+ * @since 2.5.0
+ */
+ public static String getFullName(final ZoneId self, Locale locale) {
+ return self.getDisplayName(TextStyle.FULL, locale);
+ }
+
+ /**
+ * Returns the name of this zone formatted according to the {@link java.time.format.TextStyle#SHORT} text style.
+ *
+ * @param self a ZoneId
+ * @return the short display name of the ZoneId
+ * @since 2.5.0
+ */
+ public static String getShortName(final ZoneId self) {
+ return getShortName(self, Locale.getDefault());
+ }
+
+ /**
+ * Returns the name of this zone formatted according to the {@link java.time.format.TextStyle#SHORT} text style
+ * for the provided {@link java.util.Locale}.
+ *
+ * @param self a ZoneId
+ * @param locale a Locale
+ * @return the short display name of the ZoneId
+ * @since 2.5.0
+ */
+ public static String getShortName(final ZoneId self, Locale locale) {
+ return self.getDisplayName(TextStyle.SHORT, locale);
+ }
+
+ /**
+ * Returns a {@link java.time.ZoneOffset} for this zone as of now.
+ *
+ * @param self a ZoneId
+ * @return a ZoneOffset
+ * @since 2.5.0
+ */
+ public static ZoneOffset getOffset(final ZoneId self) {
+ return getOffset(self, Instant.now());
+ }
+
+ /**
+ * Returns a {@link java.time.ZoneOffset} for this zone as of the provided {@link java.time.Instant}.
+ *
+ * @param self a ZoneId
+ * @param instant an Instant
+ * @return a ZoneOffset
+ * @since 2.5.0
+ */
+ public static ZoneOffset getOffset(final ZoneId self, Instant instant) {
+ return self.getRules().getOffset(instant);
+ }
+
+ /**
+ * Returns a {@link java.time.ZonedDateTime} of this zone and the given {@link java.time.LocalDateTime}.
+ *
+ * @param self a ZoneId
+ * @return a ZonedDateTime
+ * @since 2.5.0
+ */
+ public static ZonedDateTime leftShift(final ZoneId self, LocalDateTime dateTime) {
+ return ZonedDateTime.of(dateTime, self);
+ }
+
+ /* ******** java.time.ZoneOffset extension methods ******** */
+
+ /**
+ * Returns a generally equivalent {@link java.util.TimeZone}. The offset will be truncated to minutes.
+ *
+ * @param self a ZoneOffset
+ * @return a TimeZone
+ * @since 2.5.0
+ */
+ public static TimeZone toTimeZone(final ZoneOffset self) {
+ if (ZoneOffset.UTC.equals(self)) {
+ return TimeZone.getTimeZone("GMT");
+ } else if (getSeconds(self) == 0) {
+ return TimeZone.getTimeZone("GMT" + self.getId());
+ } else {
+ // TimeZone is only hours and minutes--no seconds
+ ZoneOffset noSeconds = ZoneOffset.ofHoursMinutes(getHours(self), getMinutes(self));
+ return TimeZone.getTimeZone("GMT" + noSeconds.getId());
+ }
+ }
+
+ /**
+ * Returns the value of the provided field for the ZoneOffset as if the ZoneOffset's
+ * hours/minutes/seconds were reckoned as a LocalTime.
+ */
+ private static int offsetFieldValue(ZoneOffset offset, TemporalField field) {
+ int offsetSeconds = offset.getTotalSeconds();
+ int value = LocalTime.ofSecondOfDay(Math.abs(offsetSeconds)).get(field);
+ return offsetSeconds < 0 ? value * -1 : value;
+ }
+
+ /**
+ * Returns the hours component of this offset. If the offset's total seconds are negative, a negative
+ * value will be returned.
+ *
+ * @param self a ZoneOffset
+ * @return the hours component value
+ * @since 2.5.0
+ */
+ public static int getHours(final ZoneOffset self) {
+ return offsetFieldValue(self, ChronoField.HOUR_OF_DAY);
+ }
+
+ /**
+ * Returns the minutes component of this offset. If the offset's total seconds are negative, a negative
+ * value will be returned.
+ *
+ * @param self a ZoneOffset
+ * @return the minutes component value
+ * @since 2.5.0
+ */
+ public static int getMinutes(final ZoneOffset self) {
+ return offsetFieldValue(self, ChronoField.MINUTE_OF_HOUR);
+ }
+
+ /**
+ * Returns the seconds component of this offset. This is not the same as the total seconds. For example:
+ * <pre>
+ * def offset = ZoneOffset.ofHoursMinutesSeconds(0, 1, 1)
+ * assert offset.seconds == 1
+ * assert offset.totalSeconds == 61
+ * </pre>
+ * <p>
+ * If the offset's total seconds are negative, a negative value will be returned.
+ *
+ * @param self a ZoneOffset
+ * @return the seconds component value
+ * @since 2.5.0
+ */
+ public static int getSeconds(final ZoneOffset self) {
+ return offsetFieldValue(self, ChronoField.SECOND_OF_MINUTE);
+ }
+
+ /**
+ * Supports the getAt operator; equivalent to calling the
+ * {@link java.time.ZoneOffset#getLong(java.time.temporal.TemporalField)} method.
+ *
+ * @param self a ZoneOffset
+ * @param field a TemporalField
+ * @return the ZoneOffset's field value
+ * @since 2.5.0
+ */
+ public static long getAt(final ZoneOffset self, TemporalField field) {
+ return self.getLong(field);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetDateTime} of this offset and the provided {@link java.time.LocalDateTime}.
+ *
+ * @param self a ZoneOffset
+ * @param dateTime a LocalDateTime
+ * @return an OffsetDateTime
+ * @since 2.5.0
+ */
+ public static OffsetDateTime leftShift(final ZoneOffset self, LocalDateTime dateTime) {
+ return OffsetDateTime.of(dateTime, self);
+ }
+
+ /**
+ * Returns an {@link java.time.OffsetDateTime} of this offset and the provided {@link java.time.LocalTime}.
+ *
+ * @param self a ZoneOffset
+ * @param time a LocalTime
+ * @return an OffsetTime
+ * @since 2.5.0
+ */
+ public static OffsetTime leftShift(final ZoneOffset self, LocalTime time) {
+ return OffsetTime.of(time, self);
+ }
+
+ /* ******** java.time.DayOfWeek extension methods ******** */
+
+ /**
+ * Returns the {@link java.time.DayOfWeek} that is {@code days} many days after this day of the week.
+ *
+ * @param self a DayOfWeek
+ * @param days the number of days to move forward
+ * @return the DayOfWeek
+ * @since 2.5.0
+ */
+ public static DayOfWeek plus(final DayOfWeek self, int days) {
+ int daysPerWeek = DayOfWeek.values().length;
+ int val = ((self.getValue() + days - 1) % daysPerWeek) + 1;
+ return DayOfWeek.of(val > 0 ? val : daysPerWeek + val);
+ }
+
+ /**
+ * Returns the {@link java.time.DayOfWeek} that is {@code days} many days before this day of the week.
+ *
+ * @param self a DayOfWeek
+ * @param days the number of days to move back
+ * @return the DayOfWeek
+ * @since 2.5.0
+ */
+ public static DayOfWeek minus(final DayOfWeek self, int days) {
+ return plus(self, days * -1);
+ }
+
+ /**
+ * Returns {@code true} if this day of the week is a weekend day (Saturday or Sunday).
+ *
+ * @param self a DayOfWeek
+ * @return true if this DayOfWeek is Saturday or Sunday
+ * @since 2.5.0
+ */
+ public static boolean isWeekend(final DayOfWeek self) {
+ return self == DayOfWeek.SATURDAY || self == DayOfWeek.SUNDAY;
+ }
+
+ /**
+ * Returns {@code true} if the DayOfWeek is a weekday.
+ *
+ * @return true if this DayOfWeek is Monday through Friday
+ * @since 2.5.0
+ */
+ public static boolean isWeekday(final DayOfWeek self) {
+ return !isWeekend(self);
+ }
+
+ /* ******** java.time.Month extension methods ******** */
+
+ /**
+ * Returns the {@link java.time.Month} that is {@code months} months after this month.
+ *
+ * @param self a Month
+ * @param months the number of months move forward
+ * @return the Month
+ * @since 2.5.0
+ */
+ public static Month plus(final Month self, int months) {
+ int monthsPerYear = Month.values().length;
+ int val = ((self.getValue() + months - 1) % monthsPerYear) + 1;
+ return Month.of(val > 0 ? val : monthsPerYear + val);
+ }
+
+ /**
+ * Returns the {@link java.time.Month} that is {@code months} months before this month.
+ *
+ * @param self a Month
+ * @param months the number of months to move back
+ * @return the Month
+ * @since 2.5.0
+ */
+ public static Month minus(final Month self, int months) {
+ return plus(self, months * -1);
+ }
+
+ /**
+ * Creates a {@link java.time.MonthDay} at the provided day of the month.
+ *
+ * @param self a Month
+ * @param dayOfMonth a day of the month
+ * @return a MonthDay
+ * @since 2.5.0
+ */
+ public static MonthDay leftShift(final Month self, int dayOfMonth) {
+ return MonthDay.of(self, dayOfMonth);
+ }
+
+ /**
+ * Creates a {@link java.time.YearMonth} at the provided {@link java.time.Year}.
+ *
+ * @param self a Month
+ * @param year a Year
+ * @return a YearMonth
+ * @since 2.5.0
+ */
+ public static YearMonth leftShift(final Month self, Year year) {
+ return YearMonth.of(year.getValue(), self);
+ }
+
+ /**
+ * Returns the Time Zone offset of the Calendar as a {@link java.time.ZoneOffset}.
+ *
+ * @param self a Calendar
+ * @return a ZoneOffset
+ * @since 2.5.0
+ */
+ public static ZoneOffset getZoneOffset(final Calendar self) {
+ int offsetMillis = self.get(Calendar.ZONE_OFFSET) + self.get(Calendar.DST_OFFSET);
+ return ZoneOffset.ofTotalSeconds(offsetMillis / 1000);
+ }
+
+ /* duplicated with DateUtilExtensions.toCalendar() but we don't want modulkes to depend on one another */
+ private static Calendar toCalendar(Date self) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(self);
+ return cal;
+ }
+
+ /**
+ * Returns the Time Zone offset of the Date as a {@link java.time.ZoneOffset},
+ * which will typically be system's default offset.
+ *
+ * @param self a Date
+ * @return a ZoneOffset
+ * @since 2.5.0
+ */
+ public static ZoneOffset getZoneOffset(final Date self) {
+ return getZoneOffset(toCalendar(self));
+ }
+
+ /**
+ * Returns the Time Zone of the Calendar as a java.time.ZoneId.
+ *
+ * @param self a Calendar
+ * @return a ZoneId
+ * @since 2.5.0
+ */
+ public static ZoneId getZoneId(final Calendar self) {
+ return self.getTimeZone().toZoneId();
+ }
+
+ /**
+ * Returns the Time Zone of the Date as a {@link java.time.ZoneId}. This will
+ * typically be the system's default ZoneId.
+ *
+ * @param self a Date
+ * @return a ZoneId
+ * @since 2.5.0
+ */
+ public static ZoneId getZoneId(final Date self) {
+ return getZoneId(toCalendar(self));
+ }
+
+ /**
+ * Converts the Calendar to a corresponding {@link java.time.Year}. If the Calendar has a different
+ * time zone than the system default, the Year will be adjusted into the default time zone.
+ *
+ * @param self a Calendar
+ * @return a Year
+ * @since 2.5.0
+ */
+ public static Year toYear(final Calendar self) {
+ return Year.of(self.get(Calendar.YEAR));
+ }
+
+ /**
+ * Converts the Date to a corresponding {@link java.time.Year}.
+ *
+ * @param self a Date
+ * @return a Year
+ * @since 2.5.0
+ */
+ public static Year toYear(final Date self) {
+ return toYear(toCalendar(self));
+ }
+
+ /**
+ * Converts the Calendar to a corresponding {@link java.time.Month}. If the Calendar has a different
+ * time zone than the system default, the Month will be adjusted into the default time zone.
+ *
+ * @param self a Calendar
+ * @return a Month
+ * @since 2.5.0
+ */
+ public static Month toMonth(final Calendar self) {
+ return Month.of(self.get(Calendar.MONTH) + 1);
+ }
+
+ /**
+ * Converts the Date to a corresponding {@link java.time.Month}.
+ *
+ * @param self a Date
+ * @return a Month
+ * @since 2.5.0
+ */
+ public static Month toMonth(final Date self) {
+ return toMonth(toCalendar(self));
+ }
+
+ /**
+ * Converts the Calendar to a corresponding {@link java.time.MonthDay}. If the Calendar has a different
+ * time zone than the system default, the MonthDay will be adjusted into the default time zone.
+ *
+ * @param self a Calendar
+ * @return a MonthDay
+ * @since 2.5.0
+ */
+ public static MonthDay toMonthDay(final Calendar self) {
+ return MonthDay.of(toMonth(self), self.get(Calendar.DAY_OF_MONTH));
+ }
+
+ /**
+ * Converts the Date to a corresponding {@link java.time.MonthDay}.
+ *
+ * @param self a Date
+ * @return a MonthDay
+ * @since 2.5.0
+ */
+ public static MonthDay toMonthDay(final Date self) {
+ return toMonthDay(toCalendar(self));
+ }
+
+ /**
+ * Converts the Calendar to a corresponding {@link java.time.YearMonth}. If the Calendar has a different
+ * time zone than the system default, the YearMonth will be adjusted into the default time zone.
+ *
+ * @param self a Calendar
+ * @return a YearMonth
+ * @since 2.5.0
+ */
+ public static YearMonth toYearMonth(final Calendar self) {
+ return toYear(self).atMonth(toMonth(self));
+ }
+
+ /**
+ * Converts the Date to a corresponding {@link java.time.YearMonth}.
+ *
+ * @param self a Date
+ * @return a YearMonth
+ * @since 2.5.0
+ */
+ public static YearMonth toYearMonth(final Date self) {
+ return toYearMonth(toCalendar(self));
+ }
+
+ /**
+ * Converts the Calendar to a corresponding {@link java.time.DayOfWeek}. If the Calendar has a different
+ * time zone than the system default, the DayOfWeek will be adjusted into the default time zone.
+ *
+ * @param self a Calendar
+ * @return a DayOfWeek
+ * @since 2.5.0
+ */
+ public static DayOfWeek toDayOfWeek(final Calendar self) {
+ return DayOfWeek.of(self.get(Calendar.DAY_OF_WEEK)).minus(1);
+ }
+
+ /**
+ * Converts the Date to a corresponding {@link java.time.DayOfWeek}.
+ *
+ * @param self a Date
+ * @return a DayOfWeek
+ * @since 2.5.0
+ */
+ public static DayOfWeek toDayOfWeek(final Date self) {
+ return toDayOfWeek(toCalendar(self));
+ }
+
+ /**
+ * Converts the Calendar to a corresponding {@link java.time.LocalDate}. If the Calendar has a different
+ * time zone than the system default, the LocalDate will be adjusted into the default time zone.
+ *
+ * @param self a Calendar
+ * @return a LocalDate
+ * @since 2.5.0
+ */
+ static LocalDate toLocalDate(final Calendar self) {
+ return LocalDate.of(self.get(Calendar.YEAR), toMonth(self), self.get(Calendar.DAY_OF_MONTH));
+ }
+
+ /**
+ * Converts the Date to a corresponding {@link java.time.LocalDate}.
+ *
+ * @param self a Date
+ * @return a LocalDate
+ * @since 2.5.0
+ */
+ public static LocalDate toLocalDate(final Date self) {
+ return toLocalDate(toCalendar(self));
+ }
+
+ /**
+ * Converts the Calendar to a corresponding {@link java.time.LocalTime}. If the Calendar has a different
+ * time zone than the system default, the LocalTime will be adjusted into the default time zone.
+ *
+ * @param self a Calendar
+ * @return a LocalTime
+ * @since 2.5.0
+ */
+ public static LocalTime toLocalTime(final Calendar self) {
+ int hour = self.get(Calendar.HOUR_OF_DAY);
+ int minute = self.get(Calendar.MINUTE);
+ int second = self.get(Calendar.SECOND);
+ int ns = self.get(Calendar.MILLISECOND) * 1_000_000;
+ return LocalTime.of(hour, minute, second, ns);
+ }
+
+ /**
+ * Converts the Date to a corresponding {@link java.time.LocalTime}.
+ *
+ * @param self a Date
+ * @return a LocalTime
+ * @since 2.5.0
+ */
+ public static LocalTime toLocalTime(final Date self) {
+ return toLocalTime(toCalendar(self));
+ }
+
+ /**
+ * Converts the Calendar to a corresponding {@link java.time.LocalDateTime}. If the Calendar has a different
+ * time zone than the system default, the LocalDateTime will be adjusted into the default time zone.
+ *
+ * @param self a Calendar
+ * @return a LocalDateTime
+ * @since 2.5.0
+ */
+ public static LocalDateTime toLocalDateTime(final Calendar self) {
+ return LocalDateTime.of(toLocalDate(self), toLocalTime(self));
+ }
+
+ /**
+ * Converts the Date to a corresponding {@link java.time.LocalDateTime}.
+ *
+ * @param self a Date
+ * @return a LocalDateTime
+ * @since 2.5.0
+ */
+ public static LocalDateTime toLocalDateTime(final Date self) {
+ return toLocalDateTime(toCalendar(self));
+ }
+
+ /**
+ * <p>Converts the Calendar to a corresponding {@link java.time.ZonedDateTime}.</p><p>Note that
+ * {@link java.util.GregorianCalendar} has a {@link java.util.GregorianCalendar#toZonedDateTime} method,
+ * which is commonly the specific type of Calendar in use.</p>
+ *
+ * @param self a Calendar
+ * @return a ZonedDateTime
+ * @since 2.5.0
+ */
+ public static ZonedDateTime toZonedDateTime(final Calendar self) {
+ if (self instanceof GregorianCalendar) { // would this branch ever be true?
+ return ((GregorianCalendar) self).toZonedDateTime();
+ } else {
+ return ZonedDateTime.of(toLocalDateTime(self), getZoneId(self));
+ }
+ }
+
+ /**
+ * Converts the Date to a corresponding {@link java.time.ZonedDateTime}.
+ *
+ * @param self a Date
+ * @return a ZonedDateTime
+ * @since 2.5.0
+ */
+ public static ZonedDateTime toZonedDateTime(final Date self) {
+ return toZonedDateTime(toCalendar(self));
+ }
+
+ /**
+ * Converts the Calendar to a corresponding {@link java.time.OffsetDateTime}.
+ *
+ * @param self a Calendar
+ * @return an OffsetDateTime
+ * @since 2.5.0
+ */
+ public static OffsetDateTime toOffsetDateTime(final Calendar self) {
+ return OffsetDateTime.of(toLocalDateTime(self), getZoneOffset(self));
+ }
+
+ /**
+ * Converts the Date to a corresponding {@link java.time.OffsetDateTime}.
+ *
+ * @param self a Date
+ * @return an OffsetDateTime
+ * @since 2.5.0
+ */
+ public static OffsetDateTime toOffsetDateTime(final Date self) {
+ return toOffsetDateTime(toCalendar(self));
+ }
+
+ /**
+ * Converts the Calendar to a corresponding {@link java.time.OffsetTime}.
+ *
+ * @param self a Calendar
+ * @return an OffsetTime
+ * @since 2.5.0
+ */
+ public static OffsetTime toOffsetTime(final Calendar self) {
+ return OffsetTime.of(toLocalTime(self), getZoneOffset(self));
+ }
+
+ /**
+ * Converts the Date to a corresponding {@link java.time.OffsetTime}.
+ *
+ * @param self a Date
+ * @return an OffsetTime
+ * @since 2.5.0
+ */
+ public static OffsetTime toOffsetTime(final Date self) {
+ return toOffsetTime(toCalendar(self));
+ }
+
+ /**
+ * Convenience method for converting a Calendar to a corresponding {@link java.time.Instant}.
+ *
+ * @param self a Calendar
+ * @return an Instant
+ * @since 2.5.0
+ */
+ public static Instant toInstant(final Calendar self) {
+ return self.getTime().toInstant();
+ }
+
+ /**
+ * Converts the TimeZone to a corresponding {@link java.time.ZoneOffset}. The offset is determined
+ * using the current date/time.
+ *
+ * @param self a TimeZone
+ * @return a ZoneOffset
+ * @since 2.5.0
+ */
+ public static ZoneOffset toZoneOffset(final TimeZone self) {
+ return toZoneOffset(self, Instant.now());
+ }
+
+ /**
+ * Converts this TimeZone to a corresponding {@link java.time.ZoneOffset}. The offset is determined
+ * using the date/time of specified Instant.
+ *
+ * @param self a TimeZone
+ * @return a ZoneOffset
+ * @since 2.5.0
+ */
+ public static ZoneOffset toZoneOffset(final TimeZone self, Instant instant) {
+ return self.toZoneId().getRules().getOffset(instant);
+ }
+}
[7/7] groovy git commit: optimize imports
Posted by pa...@apache.org.
optimize imports
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/b3c6f0eb
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/b3c6f0eb
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/b3c6f0eb
Branch: refs/heads/master
Commit: b3c6f0ebd7911ab02222010b05920e9e38bda388
Parents: 6d32a16
Author: paulk <pa...@asert.com.au>
Authored: Thu Mar 22 02:48:30 2018 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Thu Mar 22 02:48:30 2018 +1000
----------------------------------------------------------------------
.../groovy/runtime/DefaultGroovyStaticMethods.java | 14 --------------
1 file changed, 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/b3c6f0eb/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
index ed2d2a2..04421af 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
@@ -26,20 +26,6 @@ import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.Month;
-import java.time.MonthDay;
-import java.time.OffsetDateTime;
-import java.time.OffsetTime;
-import java.time.Period;
-import java.time.Year;
-import java.time.YearMonth;
-import java.time.ZoneId;
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
import java.util.ResourceBundle;
[5/7] groovy git commit: move datetime extensions to their own module
Posted by pa...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/src/main/java/org/codehaus/groovy/runtime/DateTimeGroovyMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DateTimeGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DateTimeGroovyMethods.java
deleted file mode 100644
index 93cecf5..0000000
--- a/src/main/java/org/codehaus/groovy/runtime/DateTimeGroovyMethods.java
+++ /dev/null
@@ -1,2030 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.codehaus.groovy.runtime;
-
-import groovy.lang.Closure;
-import groovy.lang.GroovyRuntimeException;
-
-import java.time.*;
-import java.time.chrono.ChronoLocalDate;
-import java.time.chrono.ChronoPeriod;
-import java.time.format.DateTimeFormatter;
-import java.time.format.FormatStyle;
-import java.time.format.TextStyle;
-import java.time.temporal.*;
-import java.util.*;
-
-import static java.time.temporal.ChronoUnit.DAYS;
-import static java.time.temporal.ChronoUnit.MONTHS;
-import static java.time.temporal.ChronoUnit.YEARS;
-
-/**
- * This class defines new Groovy methods which appear on normal JDK
- * Date/Time API (java.time) classes inside the Groovy environment.
- */
-public class DateTimeGroovyMethods {
-
- // Static methods only
- private DateTimeGroovyMethods() {
- }
-
- private static final DateTimeFormatter ZONE_SHORT_FORMATTER = DateTimeFormatter.ofPattern("z");
-
- /**
- * For any Temporal subtype that does not use {@link java.time.temporal.ChronoUnit#SECONDS} as the unit for
- * the upto/downto methods, should have an entry.
- */
- private static Map<Class<? extends Temporal>, TemporalUnit> DEFAULT_UNITS = new HashMap<>();
- static {
- DEFAULT_UNITS.put(ChronoLocalDate.class, DAYS);
- DEFAULT_UNITS.put(YearMonth.class, MONTHS);
- DEFAULT_UNITS.put(Year.class, YEARS);
- }
-
- /**
- * A number of extension methods permit a long or int to be provided as a parameter. This method determines
- * what the unit should be for this number.
- */
- private static TemporalUnit defaultUnitFor(Temporal temporal) {
- return DEFAULT_UNITS.entrySet()
- .stream()
- .filter(e -> e.getKey().isAssignableFrom(temporal.getClass()))
- .findFirst()
- .map(Map.Entry::getValue)
- .orElse(ChronoUnit.SECONDS);
- }
-
- /**
- * Truncates a nanosecond value to milliseconds. No rounding.
- */
- private static int millisFromNanos(int nanos) {
- return nanos / 1_000_000;
- }
-
- /* ******** java.time.temporal.Temporal extension methods ******** */
-
- /**
- * Iterates from this to the {@code to} {@link java.time.temporal.Temporal}, inclusive, incrementing by one
- * unit each iteration, calling the closure once per iteration. The closure may accept a single
- * {@link java.time.temporal.Temporal} argument.
- * <p>
- * The particular unit incremented by depends on the specific sub-type of {@link java.time.temporal.Temporal}.
- * Most sub-types use a unit of {@link java.time.temporal.ChronoUnit#SECONDS} except for
- * <ul>
- * <li>{@link java.time.chrono.ChronoLocalDate} and its sub-types use {@link java.time.temporal.ChronoUnit#DAYS}.
- * <li>{@link java.time.YearMonth} uses {@link java.time.temporal.ChronoUnit#MONTHS}.
- * <li>{@link java.time.Year} uses {@link java.time.temporal.ChronoUnit#YEARS}.
- * </ul>
- *
- * @param from the starting Temporal
- * @param to the ending Temporal
- * @param closure the zero or one-argument closure to call
- * @throws GroovyRuntimeException if this value is later than {@code to}
- * @throws GroovyRuntimeException if {@code to} is a different type than this
- * @since 3.0
- */
- public static void upto(Temporal from, Temporal to, Closure closure) {
- upto(from, to, defaultUnitFor(from), closure);
- }
-
- /**
- * Iterates from this to the {@code to} {@link java.time.temporal.Temporal}, inclusive, incrementing by one
- * {@code unit} each iteration, calling the closure once per iteration. The closure may accept a single
- * {@link java.time.temporal.Temporal} argument.
- *
- * If the unit is too large to iterate to the second Temporal exactly, such as iterating from two LocalDateTimes
- * that are seconds apart using {@java.time.temporal.ChronoUnit#DAYS} as the unit, the iteration will cease
- * as soon as the current value of the iteration is later than the second Temporal argument. The closure will
- * not be called with any value later than the {@code to} value.
- *
- * @param from the starting Temporal
- * @param to the ending Temporal
- * @param unit the TemporalUnit to increment by
- * @param closure the zero or one-argument closure to call
- * @throws GroovyRuntimeException if this value is later than {@code to}
- * @throws GroovyRuntimeException if {@code to} is a different type than this
- * @since 3.0
- */
- public static void upto(Temporal from, Temporal to, TemporalUnit unit, Closure closure) {
- if (isUptoEligible(from, to)) {
- for (Temporal i = from; isUptoEligible(i, to); i = i.plus(1, unit)) {
- closure.call(i);
- }
- } else {
- throw new GroovyRuntimeException("The argument (" + to +
- ") to upto() cannot be earlier than the value (" + from + ") it's called on.");
- }
- }
-
- /**
- * Returns true if the {@code from} can be iterated up to {@code to}.
- */
- private static boolean isUptoEligible(Temporal from, Temporal to) {
- TemporalAmount amount = rightShift(from, to);
- if (amount instanceof Period) {
- return isNonnegative((Period) amount);
- } else if (amount instanceof Duration) {
- return isNonnegative((Duration) amount);
- } else {
- throw new GroovyRuntimeException("Temporal implementations of "
- + from.getClass().getCanonicalName() + " are not supported by upto().");
- }
- }
-
- /**
- * Iterates from this to the {@code to} {@link java.time.temporal.Temporal}, inclusive, decrementing by one
- * unit each iteration, calling the closure once per iteration. The closure may accept a single
- * {@link java.time.temporal.Temporal} argument.
- * <p>
- * The particular unit decremented by depends on the specific sub-type of {@link java.time.temporal.Temporal}.
- * Most sub-types use a unit of {@link java.time.temporal.ChronoUnit#SECONDS} except for
- * <ul>
- * <li>{@link java.time.chrono.ChronoLocalDate} and its sub-types use {@link java.time.temporal.ChronoUnit#DAYS}.
- * <li>{@link java.time.YearMonth} uses {@link java.time.temporal.ChronoUnit#MONTHS}.
- * <li>{@link java.time.Year} uses {@link java.time.temporal.ChronoUnit#YEARS}.
- * </ul>
- *
- * @param from the starting Temporal
- * @param to the ending Temporal
- * @param closure the zero or one-argument closure to call
- * @throws GroovyRuntimeException if this value is earlier than {@code to}
- * @throws GroovyRuntimeException if {@code to} is a different type than this
- * @since 3.0
- */
- public static void downto(Temporal from, Temporal to, Closure closure) {
- downto(from, to, defaultUnitFor(from), closure);
- }
-
- /**
- * Iterates from this to the {@code to} {@link java.time.temporal.Temporal}, inclusive, decrementing by one
- * {@code unit} each iteration, calling the closure once per iteration. The closure may accept a single
- * {@link java.time.temporal.Temporal} argument.
- *
- * If the unit is too large to iterate to the second Temporal exactly, such as iterating from two LocalDateTimes
- * that are seconds apart using {@java.time.temporal.ChronoUnit#DAYS} as the unit, the iteration will cease
- * as soon as the current value of the iteration is earlier than the second Temporal argument. The closure will
- * not be called with any value earlier than the {@code to} value.
- *
- * @param from the starting Temporal
- * @param to the ending Temporal
- * @param unit the TemporalUnit to increment by
- * @param closure the zero or one-argument closure to call
- * @throws GroovyRuntimeException if this value is earlier than {@code to}
- * @throws GroovyRuntimeException if {@code to} is a different type than this
- * @since 3.0
- */
- public static void downto(Temporal from, Temporal to, TemporalUnit unit, Closure closure) {
- if (isDowntoEligible(from, to)) {
- for (Temporal i = from; isDowntoEligible(i, to); i = i.minus(1, unit)) {
- closure.call(i);
- }
- } else {
- throw new GroovyRuntimeException("The argument (" + to +
- ") to downto() cannot be later than the value (" + from + ") it's called on.");
- }
- }
-
- /**
- * Returns true if the {@code from} can be iterated down to {@code to}.
- */
- private static boolean isDowntoEligible(Temporal from, Temporal to) {
- TemporalAmount amount = rightShift(from, to);
- if (amount instanceof Period) {
- return isNonpositive((Period) amount);
- } else if (amount instanceof Duration) {
- return isNonpositive((Duration) amount);
- } else {
- throw new GroovyRuntimeException("Temporal implementations of "
- + from.getClass().getCanonicalName() + " are not supported by downto().");
- }
- }
-
- /**
- * Returns a {@link java.time.Duration} or {@link java.time.Period} between this (inclusive) and the {@code other}
- * {@link java.time.temporal.Temporal} (exclusive).
- * <p>
- * A Period will be returned for types {@link java.time.Year}, {@link java.time.YearMonth}, and
- * {@link java.time.chrono.ChronoLocalDate}; otherwise, a Duration will be returned.
- * <p>
- * Note: if the Temporal is a ChronoLocalDate but not a {@link java.time.LocalDate}, a general
- * {@link java.time.chrono.ChronoPeriod} will be returned as per the return type of the method
- * {@link java.time.chrono.ChronoLocalDate#until(ChronoLocalDate)} .
- *
- * @param self a Temporal
- * @param other another Temporal of the same type
- * @return an TemporalAmount between the two Temporals
- * @since 3.0
- */
- public static TemporalAmount rightShift(final Temporal self, Temporal other) {
- if (!self.getClass().equals(other.getClass())) {
- throw new GroovyRuntimeException("Temporal arguments must be of the same type.");
- }
- switch ((ChronoUnit) defaultUnitFor(self)) {
- case YEARS:
- return DefaultGroovyStaticMethods.between(null, (Year) self, (Year) other);
- case MONTHS:
- return DefaultGroovyStaticMethods.between(null, (YearMonth) self, (YearMonth) other);
- case DAYS:
- return ChronoPeriod.between((ChronoLocalDate) self, (ChronoLocalDate) other);
- default:
- return Duration.between(self, other);
- }
- }
-
- /* ******** java.time.temporal.TemporalAccessor extension methods ******** */
-
- /**
- * Supports the getAt operator; equivalent to calling the
- * {@link java.time.temporal.TemporalAccessor#getLong(java.time.temporal.TemporalField)} method.
- *
- * @param self a TemporalAccessor
- * @param field a non-null TemporalField
- * @return the value for the field
- * @throws DateTimeException if a value for the field cannot be obtained
- * @throws UnsupportedTemporalTypeException if the field is not supported
- * @throws ArithmeticException if numeric overflow occurs
- * @since 3.0
- */
- public static long getAt(final TemporalAccessor self, TemporalField field) {
- return self.getLong(field);
- }
-
- /* ******** java.time.temporal.TemporalAmount extension methods ******** */
-
- /**
- * Supports the getAt operator; equivalent to calling the
- * {@link java.time.temporal.TemporalAmount#get(TemporalUnit)} method.
- *
- * @param self a TemporalAmount
- * @param unit a non-null TemporalUnit
- * @return the value for the field
- * @throws DateTimeException if a value for the field cannot be obtained
- * @throws UnsupportedTemporalTypeException if the field is not supported
- * @throws ArithmeticException if numeric overflow occurs
- * @since 3.0
- */
- public static long getAt(final TemporalAmount self, TemporalUnit unit) {
- return self.get(unit);
- }
-
- /* ******** java.time.Duration extension methods ******** */
-
- /**
- * Returns a {@link java.time.Duration} that is {@code seconds} seconds longer than this duration.
- *
- * @param self a Duration
- * @param seconds the number of seconds to add
- * @return a Duration
- * @since 3.0
- */
- public static Duration plus(final Duration self, long seconds) {
- return self.plusSeconds(seconds);
- }
-
- /**
- * Returns a {@link java.time.Duration} that is {@code seconds} seconds shorter that this duration.
- *
- * @param self a Duration
- * @param seconds the number of seconds to subtract
- * @return a Duration
- * @since 3.0
- */
- public static Duration minus(final Duration self, long seconds) {
- return self.minusSeconds(seconds);
- }
-
- /**
- * Returns a {@link java.time.Duration} that is one second longer than this duration.
- *
- * @param self a Duration
- * @return a Duration
- * @since 3.0
- */
- public static Duration next(final Duration self) {
- return self.plusSeconds(1);
- }
-
- /**
- * Returns a {@link java.time.Duration} that is one second shorter than this duration.
- *
- * @param self a Duration
- * @return a Duration
- * @since 3.0
- */
- public static Duration previous(final Duration self) {
- return self.minusSeconds(1);
- }
-
- /**
- * Supports the unary minus operator; equivalent to calling the {@link Duration#negated()} method.
- *
- * @param self a Duration
- * @return a Duration
- * @since 3.0
- */
- public static Duration negative(final Duration self) {
- return self.negated();
- }
-
- /**
- * Supports the unary plus operator; equivalent to calling the {@link Duration#abs()} method.
- *
- * @param self a Duration
- * @return a Duration
- * @since 3.0
- */
- public static Duration positive(final Duration self) {
- return self.abs();
- }
-
- /**
- * Supports the multiplication operator; equivalent to calling the {@link Duration#multipliedBy(long)} method.
- *
- * @param self a Duration
- * @param scalar the value to multiply by
- * @return a Duration
- * @since 3.0
- */
- public static Duration multiply(final Duration self, long scalar) {
- return self.multipliedBy(scalar);
- }
-
- /**
- * Supports the division operator; equivalent to calling the {@link Duration#dividedBy(long)} method.
- *
- * @param self a Duration
- * @param scalar the value to divide by
- * @return a Duration
- * @since 3.0
- */
- public static Duration div(final Duration self, long scalar) {
- return self.dividedBy(scalar);
- }
-
- /**
- * Returns true if this duration is positive, excluding zero.
- *
- * @param self a Duration
- * @return true if positive
- * @since 3.0
- */
- public static boolean isPositive(final Duration self) {
- return !self.isZero() && !self.isNegative();
- }
-
- /**
- * Returns true if this duration is zero or positive.
- *
- * @param self a Duration
- * @return true if nonnegative
- * @since 3.0
- */
- public static boolean isNonnegative(final Duration self) {
- return self.isZero() || !self.isNegative();
- }
-
- /**
- * Returns true if this duration is zero or negative.
- *
- * @param self a Duration
- * @return true if nonpositive
- * @since 3.0
- */
- public static boolean isNonpositive(final Duration self) {
- return self.isZero() || self.isNegative();
- }
-
- /* ******** java.time.Instant extension methods ******** */
-
- /**
- * Returns an {@link java.time.Instant} that is {@code seconds} seconds after this instant.
- *
- * @param self an Instant
- * @param seconds the number of seconds to add
- * @return an Instant
- * @since 3.0
- */
- public static Instant plus(final Instant self, long seconds) {
- return self.plusSeconds(seconds);
- }
-
- /**
- * Returns an {@link java.time.Instant} that is {@code seconds} seconds before this instant.
- *
- * @param self an Instant
- * @param seconds the number of seconds to subtract
- * @return an Instant
- * @since 3.0
- */
- public static Instant minus(final Instant self, long seconds) {
- return self.minusSeconds(seconds);
- }
-
- /**
- * Returns an {@link java.time.Instant} that is one second after this instant.
- *
- * @param self an Instant
- * @return an Instant one second ahead
- * @since 3.0
- */
- public static Instant next(final Instant self) {
- return plus(self, 1);
- }
-
- /**
- * Returns an {@link java.time.Instant} that one second before this instant.
- *
- * @param self an Instant
- * @return an Instant one second behind
- * @since 3.0
- */
- public static Instant previous(final Instant self) {
- return minus(self, 1);
- }
-
- /**
- * Returns a generally equivalent {@link java.util.Date} according the number of milliseconds since the epoch,
- * adjusted into the system default time zone.
- *
- * @param self an Instant
- * @return a Date
- * @since 3.0
- */
- public static Date toDate(final Instant self) {
- return new Date(self.toEpochMilli());
- }
-
- /**
- * Returns a generally equivalent {@link java.util.Calendar} in the GMT time zone, truncated to milliseconds.
- *
- * @param self an Instant
- * @return a Calendar
- * @since 3.0
- */
- public static Calendar toCalendar(final Instant self) {
- Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
- cal.setTime(toDate(self));
- return cal;
- }
-
- /* ******** java.time.LocalDate extension methods ******** */
-
- /**
- * Formats this date with the provided {@link java.time.format.DateTimeFormatter} pattern.
- *
- * @param self a LocalDate
- * @param pattern the formatting pattern
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String format(final LocalDate self, String pattern) {
- return self.format(DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Formats this date in the provided, localized {@link java.time.format.FormatStyle}.
- *
- * @param self a LocalDate
- * @param dateStyle the FormatStyle
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String format(final LocalDate self, FormatStyle dateStyle) {
- return self.format(DateTimeFormatter.ofLocalizedDate(dateStyle));
- }
-
- /**
- * Formats this date with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE} formatter.
- *
- * @param self a LocalDate
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String getDateString(final LocalDate self) {
- return self.format(DateTimeFormatter.ISO_LOCAL_DATE);
- }
-
- /**
- * Returns a {@link java.time.LocalDate} that is {@code days} days after this date.
- *
- * @param self a LocalDate
- * @param days the number of days to add
- * @return a LocalDate
- * @since 3.0
- */
- public static LocalDate plus(final LocalDate self, long days) {
- return self.plusDays(days);
- }
-
- /**
- * Returns a {@link java.time.LocalDate} that is {@code days} days before this date.
- *
- * @param self a LocalDate
- * @param days the number of days to subtract
- * @return a LocalDate
- * @since 3.0
- */
- public static LocalDate minus(final LocalDate self, long days) {
- return self.minusDays(days);
- }
-
- /**
- * Returns a {@link java.time.LocalDate} one day after this date.
- *
- * @param self a LocalDate
- * @return the next day
- * @since 3.0
- */
- public static LocalDate next(final LocalDate self) {
- return plus(self, 1);
- }
-
- /**
- * Returns a {@link java.time.LocalDate} one day before this date.
- *
- * @param self a LocalDate
- * @return the previous day
- * @since 3.0
- */
- public static LocalDate previous(final LocalDate self) {
- return minus(self, 1);
- }
-
- /**
- * Returns a {@link java.time.Period} equivalent to the time between this date (inclusive)
- * and the provided {@link java.time.LocalDate} (exclusive).
- *
- * @param self a LocalDate
- * @param other another LocalDate
- * @return a Period representing the time between the two LocalDates
- * @since 3.0
- */
- public static Period rightShift(final LocalDate self, LocalDate other) {
- return Period.between(self, other);
- }
-
- /**
- * Returns a {@link java.time.LocalDateTime} from this date and the provided {@link java.time.LocalTime}.
- *
- * @param self a LocalDate
- * @param time a LocalTime
- * @return a LocalDateTime
- * @since 3.0
- */
- public static LocalDateTime leftShift(final LocalDate self, LocalTime time) {
- return LocalDateTime.of(self, time);
- }
-
- /**
- * Returns a {@link java.time.OffsetDateTime} from this date and the provided {@link java.time.OffsetTime}.
- *
- * @param self a LocalDate
- * @param time an OffsetTime
- * @return an OffsetDateTime
- * @since 3.0
- */
- public static OffsetDateTime leftShift(final LocalDate self, OffsetTime time) {
- return time.atDate(self);
- }
-
- /**
- * Returns an equivalent instance of {@link java.util.Date}.
- * The time portion of the returned date is cleared.
- *
- * @param self a LocalDate
- * @return a java.util.Date
- * @since 3.0
- */
- public static Date toDate(final LocalDate self) {
- return toCalendar(self).getTime();
- }
-
- /**
- * Returns an equivalent instance of {@link java.util.Calendar}.
- * The time portion of the returned calendar is cleared and the time zone is the current system default.
- *
- * @param self a LocalDate
- * @return a java.util.Calendar
- * @since 3.0
- */
- public static Calendar toCalendar(final LocalDate self) {
- Calendar cal = Calendar.getInstance();
- cal.set(Calendar.DATE, self.getDayOfMonth());
- cal.set(Calendar.MONTH, self.getMonthValue() - 1);
- cal.set(Calendar.YEAR, self.getYear());
- return DateGroovyMethods.clearTime(cal);
- }
-
- /* ******** java.time.LocalDateTime extension methods ******** */
-
- /**
- * Formats this date/time with the provided {@link java.time.format.DateTimeFormatter} pattern.
- *
- * @param self a LocalDateTime
- * @param pattern the formatting pattern
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String format(final LocalDateTime self, String pattern) {
- return self.format(DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Formats this date/time in the provided, localized {@link java.time.format.FormatStyle}.
- *
- * @param self a LocalDateTime
- * @param dateTimeStyle the FormatStyle
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String format(final LocalDateTime self, FormatStyle dateTimeStyle) {
- return self.format(DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle));
- }
-
- /**
- * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE_TIME} formatter.
- *
- * @param self a LocalDateTime
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String getDateTimeString(final LocalDateTime self) {
- return self.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
- }
-
- /**
- * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE} formatter.
- *
- * @param self a LocalDateTime
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String getDateString(final LocalDateTime self) {
- return self.format(DateTimeFormatter.ISO_LOCAL_DATE);
- }
-
- /**
- * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_TIME} formatter.
- *
- * @param self a LocalDateTime
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String getTimeString(final LocalDateTime self) {
- return self.format(DateTimeFormatter.ISO_LOCAL_TIME);
- }
-
- /**
- * Returns a {@link java.time.LocalDateTime} with the time portion cleared.
- *
- * @param self a LocalDateTime
- * @return a LocalDateTime
- * @since 3.0
- */
- public static LocalDateTime clearTime(final LocalDateTime self) {
- return self.truncatedTo(DAYS);
- }
-
- /**
- * Returns a {@link java.time.LocalDateTime} that is {@code seconds} seconds after this date/time.
- *
- * @param self a LocalDateTime
- * @param seconds the number of seconds to add
- * @return a LocalDateTime
- * @since 3.0
- */
- public static LocalDateTime plus(final LocalDateTime self, long seconds) {
- return self.plusSeconds(seconds);
- }
-
- /**
- * Returns a {@link java.time.LocalDateTime} that is {@code seconds} seconds before this date/time.
- *
- * @param self a LocalDateTime
- * @param seconds the number of seconds to subtract
- * @return a LocalDateTime
- * @since 3.0
- */
- public static LocalDateTime minus(final LocalDateTime self, long seconds) {
- return self.minusSeconds(seconds);
- }
-
- /**
- * Returns a {@link java.time.LocalDateTime} that is one second after this date/time.
- *
- * @param self a LocalDateTime
- * @return a LocalDateTime
- * @since 3.0
- */
- public static LocalDateTime next(final LocalDateTime self) {
- return plus(self, 1);
- }
-
- /**
- * Returns a {@link java.time.LocalDateTime} that is one second before this date/time.
- *
- * @param self a LocalDateTime
- * @return a LocalDateTime
- * @since 3.0
- */
- public static LocalDateTime previous(final LocalDateTime self) {
- return minus(self, 1);
- }
-
- /**
- * Returns an {@link java.time.OffsetDateTime} of this date/time and the provided {@link java.time.ZoneOffset}.
- *
- * @param self a LocalDateTime
- * @param offset a ZoneOffset
- * @return an OffsetDateTime
- * @since 3.0
- */
- public static OffsetDateTime leftShift(final LocalDateTime self, ZoneOffset offset) {
- return OffsetDateTime.of(self, offset);
- }
-
- /**
- * Returns a {@link java.time.OffsetDateTime} of this date/time and the provided {@link java.time.ZoneId}.
- *
- * @param self a LocalDateTime
- * @param zone a ZoneId
- * @return a ZonedDateTime
- * @since 3.0
- */
- public static ZonedDateTime leftShift(final LocalDateTime self, ZoneId zone) {
- return ZonedDateTime.of(self, zone);
- }
-
- /**
- * Returns a generally equivalent instance of {@link java.util.Date}.
- * The time value of the returned date is truncated to milliseconds.
- *
- * @param self a LocalDateTime
- * @return a java.util.Date
- * @since 3.0
- */
- public static Date toDate(final LocalDateTime self) {
- return toCalendar(self).getTime();
- }
-
- /**
- * Returns a generally equivalent instance of {@link java.util.Calendar}.
- * The time value of the returned calendar is truncated to milliseconds and the
- * time zone is the current system default.
- *
- * @param self a LocalDateTime
- * @return a java.util.Calendar
- * @since 3.0
- */
- public static Calendar toCalendar(final LocalDateTime self) {
- Calendar cal = Calendar.getInstance();
- cal.set(Calendar.DATE, self.getDayOfMonth());
- cal.set(Calendar.MONTH, self.getMonthValue() - 1);
- cal.set(Calendar.YEAR, self.getYear());
- cal.set(Calendar.HOUR_OF_DAY, self.getHour());
- cal.set(Calendar.MINUTE, self.getMinute());
- cal.set(Calendar.SECOND, self.getSecond());
- cal.set(Calendar.MILLISECOND, millisFromNanos(self.getNano()));
- return cal;
- }
-
- /* ******** java.time.LocalTime extension methods ******** */
-
- /**
- * Formats this time with the provided {@link java.time.format.DateTimeFormatter} pattern.
- *
- * @param self a LocalDateTime
- * @param pattern the formatting pattern
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String format(final LocalTime self, String pattern) {
- return self.format(DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Formats this time in the provided, localized {@link java.time.format.FormatStyle}.
- *
- * @param self a LocalTime
- * @param timeStyle the FormatStyle
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String format(final LocalTime self, FormatStyle timeStyle) {
- return self.format(DateTimeFormatter.ofLocalizedTime(timeStyle));
- }
-
- /**
- * Formats this time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_TIME} formatter.
- *
- * @param self a LocalTime
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String getTimeString(final LocalTime self) {
- return self.format(DateTimeFormatter.ISO_LOCAL_TIME);
- }
-
- /**
- * Returns a {@link java.time.LocalTime} that is {@code seconds} seconds after this time.
- *
- * @param self a LocalTime
- * @param seconds the number of seconds to add
- * @return a LocalTime
- * @since 3.0
- */
- public static LocalTime plus(final LocalTime self, long seconds) {
- return self.plusSeconds(seconds);
- }
-
- /**
- * Returns a {@link java.time.LocalTime} that is {@code seconds} seconds before this time.
- *
- * @param self a LocalTime
- * @param seconds the number of seconds to subtract
- * @return a LocalTime
- * @since 3.0
- */
- public static LocalTime minus(final LocalTime self, long seconds) {
- return self.minusSeconds(seconds);
- }
-
- /**
- * Returns a {@link java.time.LocalTime} that is one second after this time.
- *
- * @param self a LocalTime
- * @return a LocalTime
- * @since 3.0
- */
- public static LocalTime next(final LocalTime self) {
- return plus(self, 1);
- }
-
- /**
- * Returns a {@link java.time.LocalTime} that is one second before this time.
- *
- * @param self a LocalTime
- * @return a LocalTime
- * @since 3.0
- */
- public static LocalTime previous(final LocalTime self) {
- return minus(self, 1);
- }
-
- /**
- * Returns a {@link java.time.LocalDateTime} of this time and the provided {@link java.time.LocalDate}.
- *
- * @param self a LocalTime
- * @param date a LocalDate
- * @return a LocalDateTime
- * @since 3.0
- */
- public static LocalDateTime leftShift(final LocalTime self, LocalDate date) {
- return LocalDateTime.of(date, self);
- }
-
- /**
- * Returns an {@link java.time.OffsetTime} of this time and the provided {@link java.time.ZoneOffset}.
- *
- * @param self a LocalTime
- * @param offset a ZoneOffset
- * @return an OffsetTime
- * @since 3.0
- */
- public static OffsetTime leftShift(final LocalTime self, ZoneOffset offset) {
- return OffsetTime.of(self, offset);
- }
-
- /**
- * Returns a generally equivalent instance of {@link java.util.Date}. The day-month-year value of the
- * returned date is today and the time is truncated to milliseconds.
- *
- * @param self a LocalTime
- * @return a java.util.Date
- * @since 3.0
- */
- public static Date toDate(final LocalTime self) {
- return toCalendar(self).getTime();
- }
-
- /**
- * Returns a generally equivalent instance of {@link java.util.Calendar}. The day-month-year value of the
- * returned calendar is today, the time is truncated to milliseconds, and the time zone is the current
- * system default.
- *
- * @param self a LocalTime
- * @return a java.util.Calendar
- * @since 3.0
- */
- public static Calendar toCalendar(final LocalTime self) {
- Calendar cal = Calendar.getInstance();
- cal.set(Calendar.HOUR_OF_DAY, self.getHour());
- cal.set(Calendar.MINUTE, self.getMinute());
- cal.set(Calendar.SECOND, self.getSecond());
- cal.set(Calendar.MILLISECOND, millisFromNanos(self.getNano()));
- return cal;
- }
-
- /* ******** java.time.MonthDay extension methods ******** */
-
- /**
- * Returns a {@link java.time.LocalDate} of this month/day and the provided year.
- *
- * @param self a MonthDay
- * @param year a year
- * @return a LocalDate
- * @since 3.0
- */
- public static LocalDate leftShift(final MonthDay self, int year) {
- return self.atYear(year);
- }
-
- /**
- * Returns a {@link java.time.LocalDate} of this month/day and the provided {@link java.time.Year}.
- *
- * @param self a MonthDay
- * @param year a Year
- * @return a LocalDate
- * @since 3.0
- */
- public static LocalDate leftShift(final MonthDay self, Year year) {
- return year.atMonthDay(self);
- }
-
- /* ******** java.time.OffsetDateTime extension methods ******** */
-
- /**
- * Formats this date/time with the provided {@link java.time.format.DateTimeFormatter} pattern.
- *
- * @param self an OffsetDateTime
- * @param pattern the formatting pattern
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String format(final OffsetDateTime self, String pattern) {
- return self.format(DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Formats this date/time in the provided, localized {@link java.time.format.FormatStyle}.
- *
- * @param self an OffsetDateTime
- * @param dateTimeStyle the FormatStyle
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String format(final OffsetDateTime self, FormatStyle dateTimeStyle) {
- return self.format(DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle));
- }
-
- /**
- * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_OFFSET_DATE_TIME} formatter.
- *
- * @param self an OffsetDateTime
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String getDateTimeString(final OffsetDateTime self) {
- return self.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
- }
-
- /**
- * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_OFFSET_DATE} formatter.
- *
- * @param self an OffsetDateTime
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String getDateString(final OffsetDateTime self) {
- return self.format(DateTimeFormatter.ISO_OFFSET_DATE);
- }
-
- /**
- * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_OFFSET_TIME} formatter.
- *
- * @param self an OffsetDateTime
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String getTimeString(final OffsetDateTime self) {
- return self.format(DateTimeFormatter.ISO_OFFSET_TIME);
- }
-
- /**
- * Returns an {@link java.time.OffsetDateTime} with the time portion cleared.
- *
- * @param self an OffsetDateTime
- * @return an OffsetDateTime
- * @since 3.0
- */
- public static OffsetDateTime clearTime(final OffsetDateTime self) {
- return self.truncatedTo(DAYS);
- }
-
- /**
- * Returns an {@link java.time.OffsetDateTime} that is {@code seconds} seconds after this date/time.
- *
- * @param self an OffsetDateTime
- * @param seconds the number of seconds to add
- * @return an OffsetDateTime
- * @since 3.0
- */
- public static OffsetDateTime plus(final OffsetDateTime self, long seconds) {
- return self.plusSeconds(seconds);
- }
-
- /**
- * Returns an {@link java.time.OffsetDateTime} that is {@code seconds} seconds before this date/time.
- *
- * @param self an OffsetDateTime
- * @param seconds the number of seconds to subtract
- * @return an OffsetDateTime
- * @since 3.0
- */
- public static OffsetDateTime minus(final OffsetDateTime self, long seconds) {
- return self.minusSeconds(seconds);
- }
-
- /**
- * Returns an {@link java.time.OffsetDateTime} one second after this date/time.
- *
- * @param self an OffsetDateTime
- * @return an OffsetDateTime
- * @since 3.0
- */
- public static OffsetDateTime next(final OffsetDateTime self) {
- return plus(self, 1);
- }
-
- /**
- * Returns an {@link java.time.OffsetDateTime} one second before this date/time.
- *
- * @param self an OffsetDateTime
- * @return an OffsetDateTime
- * @since 3.0
- */
- public static OffsetDateTime previous(final OffsetDateTime self) {
- return minus(self, 1);
- }
-
- /**
- * Returns a generally equivalent instance of {@link java.util.Date}.
- * The time value of the returned date is truncated to milliseconds and will be
- * adjusted to the current system default time zone.
- *
- * @param self an OffsetDateTime
- * @return a java.util.Date
- * @since 3.0
- */
- public static Date toDate(final OffsetDateTime self) {
- return toCalendar(self).getTime();
- }
-
- /**
- * Returns a generally equivalent instance of {@link java.util.Calendar}.
- * The time value of the returned calendar is truncated to milliseconds and the time zone
- * is based on the offset of this date/time.
- *
- * @param self an OffsetDateTime
- * @return a java.util.Calendar
- * @since 3.0
- */
- public static Calendar toCalendar(final OffsetDateTime self) {
- return toCalendar(self.toZonedDateTime());
- }
-
- /* ******** java.time.OffsetTime extension methods ******** */
-
- /**
- * Formats this time with the provided {@link java.time.format.DateTimeFormatter} pattern.
- *
- * @param self an OffsetTime
- * @param pattern the formatting pattern
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String format(final OffsetTime self, String pattern) {
- return self.format(DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Formats this time in the provided, localized {@link java.time.format.FormatStyle}.
- *
- * @param self an OffsetTime
- * @param timeStyle the FormatStyle
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String format(final OffsetTime self, FormatStyle timeStyle) {
- return self.format(DateTimeFormatter.ofLocalizedTime(timeStyle));
- }
-
- /**
- * Formats this time with the {@link java.time.format.DateTimeFormatter#ISO_OFFSET_TIME} formatter.
- *
- * @param self an OffsetTime
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String getTimeString(final OffsetTime self) {
- return self.format(DateTimeFormatter.ISO_OFFSET_TIME);
- }
-
- /**
- * Returns an {@link java.time.OffsetTime} that is {@code seconds} seconds after this time.
- *
- * @param self an OffsetTime
- * @param seconds the number of seconds to add
- * @return an OffsetTime
- * @since 3.0
- */
- public static OffsetTime plus(final OffsetTime self, long seconds) {
- return self.plusSeconds(seconds);
- }
-
- /**
- * Returns an {@link java.time.OffsetTime} that is {@code seconds} seconds before this time.
- *
- * @param self an OffsetTime
- * @param seconds the number of seconds to subtract
- * @return an OffsetTime
- * @since 3.0
- */
- public static OffsetTime minus(final OffsetTime self, long seconds) {
- return self.minusSeconds(seconds);
- }
-
- /**
- * Returns an {@link java.time.OffsetTime} that is one second after this time.
- *
- * @param self an OffsetTime
- * @return an OffsetTime
- * @since 3.0
- */
- public static OffsetTime next(final OffsetTime self) {
- return plus(self, 1);
- }
-
- /**
- * Returns an {@link java.time.OffsetTime} that is one second before this time.
- *
- * @param self an OffsetTime
- * @return an OffsetTime
- * @since 3.0
- */
- public static OffsetTime previous(final OffsetTime self) {
- return minus(self, 1);
- }
-
- /**
- * Returns an {@link java.time.OffsetDateTime} of this time and the provided {@link java.time.LocalDate}.
- *
- * @param self an OffsetTime
- * @param date a LocalDate
- * @return an OffsetDateTime
- * @since 3.0
- */
- public static OffsetDateTime leftShift(final OffsetTime self, LocalDate date) {
- return OffsetDateTime.of(date, self.toLocalTime(), self.getOffset());
- }
-
- /**
- * Returns a generally equivalent instance of {@link java.util.Date}.
- * The time value of the returned date is truncated to milliseconds and will be
- * adjusted to the current system default time zone.
- *
- * @param self an OffsetTime
- * @return a java.util.Date
- * @since 3.0
- */
- public static Date toDate(final OffsetTime self) {
- return toCalendar(self).getTime();
- }
-
- /**
- * Returns a generally equivalent instance of {@link java.util.Calendar}.
- * The date value of the returned calendar is now, the time value is truncated to milliseconds,
- * and the time zone is based on the offset of this time.
- *
- * @param self an OffsetTime
- * @return a java.util.Calendar
- * @since 3.0
- */
- public static Calendar toCalendar(final OffsetTime self) {
- TimeZone timeZone = toTimeZone(self.getOffset());
- Calendar cal = Calendar.getInstance(timeZone);
- cal.set(Calendar.HOUR_OF_DAY, self.getHour());
- cal.set(Calendar.MINUTE, self.getMinute());
- cal.set(Calendar.SECOND, self.getSecond());
- cal.set(Calendar.MILLISECOND, millisFromNanos(self.getNano()));
- return cal;
- }
-
- /* ******** java.time.Period extension methods ******** */
-
- /**
- * Returns a {@link java.time.Period} that is {@code days} days longer than this period.
- * No normalization is performed.
- *
- * @param self a Period
- * @param days the number of days to increase this Period by
- * @return a Period
- * @since 3.0
- */
- public static Period plus(final Period self, long days) {
- return self.plusDays(days);
- }
-
- /**
- * Returns a {@link java.time.Period} that is {@code days} days shorter than this period.
- * No normalization is performed.
- *
- * @param self a Period
- * @param days the number of days to decrease this Period by
- * @return a Period
- * @since 3.0
- */
- public static Period minus(final Period self, long days) {
- return self.minusDays(days);
- }
-
- /**
- * Returns a {@link java.time.Period} that is one day longer than this period.
- * No normalization is performed.
- *
- * @param self a Period
- * @return a Period one day longer in length
- * @since 3.0
- */
- public static Period next(final Period self) {
- return plus(self, 1);
- }
-
- /**
- * Returns a {@link java.time.Period} that is one day shorter than this period.
- * No normalization is performed.
- *
- * @param self a Period
- * @return a Period one day shorter in length
- * @since 3.0
- */
- public static Period previous(final Period self) {
- return minus(self, 1);
- }
-
- /**
- * Supports the unary minus operator; equivalent to calling the {@link java.time.Period#negated()} method.
- *
- * @param self a Period
- * @return a negated Period
- * @since 3.0
- */
- public static Period negative(final Period self) {
- return self.negated();
- }
-
- /**
- * Supports the unary plus operator; returns a {@link java.time.Period} with all unit values positive.
- * For example, a period of "2 years, -3 months, and -4 days" would result in a period of
- * "2 years, 3 months, and 4 days." No normalization is performed.
- *
- * @param self a Period
- * @return a positive Period
- * @since 3.0
- */
- public static Period positive(final Period self) {
- return !self.isNegative() ? self : self.withDays(Math.abs(self.getDays()))
- .withMonths(Math.abs(self.getMonths()))
- .withYears(Math.abs(self.getYears()));
- }
-
- /**
- * Supports the multiply operator; equivalent to calling the {@link java.time.Period#multipliedBy(int)} method.
- *
- * @param self a Period
- * @param scalar a scalar to multiply each unit by
- * @return a Period
- * @since 3.0
- */
- public static Period multiply(final Period self, int scalar) {
- return self.multipliedBy(scalar);
- }
-
- /**
- * Returns true if this period is positive, excluding zero.
- *
- * @param self a ChronoPeriod
- * @return true if positive
- * @since 3.0
- */
- public static boolean isPositive(final ChronoPeriod self) {
- return !self.isZero() && !self.isNegative();
- }
-
- /**
- * Returns true if this period is zero or positive.
- *
- * @param self a ChronoPeriod
- * @return true if nonnegative
- * @since 3.0
- */
- public static boolean isNonnegative(final ChronoPeriod self) {
- return self.isZero() || !self.isNegative();
- }
-
- /**
- * Returns true if this period is zero or negative.
- *
- * @param self a ChronoPeriod
- * @return true if nonpositive
- * @since 3.0
- */
- public static boolean isNonpositive(final ChronoPeriod self) {
- return self.isZero() || self.isNegative();
- }
-
- /* ******** java.time.Year extension methods ******** */
-
- /**
- * Returns a {@link java.time.Year} that is {@code years} years after this year.
- *
- * @param self a Year
- * @param years the number of years to add
- * @return a Year
- * @since 3.0
- */
- public static Year plus(final Year self, long years) {
- return self.plusYears(years);
- }
-
- /**
- * Returns a {@link java.time.Year} that is {@code years} years before this year.
- *
- * @param self a Year
- * @param years the number of years to subtract
- * @return a Year
- * @since 3.0
- */
- public static Year minus(final Year self, long years) {
- return self.minusYears(years);
- }
-
- /**
- * Returns a {@link java.time.Year} after this year.
- *
- * @param self a Year
- * @return the next Year
- * @since 3.0
- */
- public static Year next(final Year self) {
- return plus(self, 1);
- }
-
- /**
- * Returns a {@link java.time.Year} before this year.
- *
- * @param self a Year
- * @return the previous Year
- * @since 3.0
- */
- public static Year previous(final Year self) {
- return minus(self, 1);
- }
-
- /**
- * Returns a {@link java.time.Period} between the first day of this year (inclusive) and the first day of the
- * provided {@link java.time.Year} (exclusive).
- *
- * @param self a Year
- * @param year another Year
- * @return a Period between the Years
- * @since 3.0
- */
- public static Period rightShift(final Year self, Year year) {
- return Period.between(self.atDay(1), year.atDay(1));
- }
-
- /**
- * Returns a {@link java.time.YearMonth} of this year and the provided {@link java.time.Month}.
- *
- * @param self a Year
- * @param month a Month
- * @return a YearMonth
- * @since 3.0
- */
- public static YearMonth leftShift(final Year self, Month month) {
- return self.atMonth(month);
- }
-
- /**
- * Returns a {@link java.time.LocalDate} of this year on the given {@link java.time.MonthDay}.
- *
- * @param self a Year
- * @param monthDay a MonthDay
- * @return a LocalDate
- * @since 3.0
- */
- public static LocalDate leftShift(final Year self, MonthDay monthDay) {
- return self.atMonthDay(monthDay);
- }
-
- /**
- * Equivalent to calling the {@link java.time.Year#get(java.time.temporal.TemporalField)} method with a
- * {@link java.time.temporal.ChronoField#ERA} argument.
- *
- * Returns the era of the year, which is currently either 0 (BC) or 1 (AD).
- *
- * @param self a Year
- * @return an int representing the era
- * @since 3.0
- */
- public static int getEra(final Year self) {
- return self.get(ChronoField.ERA);
- }
-
- /**
- * Equivalent to calling the {@link java.time.Year#get(java.time.temporal.TemporalField)} method with a
- * {@link java.time.temporal.ChronoField#YEAR_OF_ERA} argument.
- *
- * Since Year=0 represents 1 BC, the yearOfEra value of Year=0 is 1, Year=-1 is 2, and so on.
- *
- * @param self a Year
- * @return the year value of the era
- * @since 3.0
- */
- public static int getYearOfEra(final Year self) {
- return self.get(ChronoField.YEAR_OF_ERA);
- }
-
- /* ******** java.time.YearMonth extension methods ******** */
-
- /**
- * Returns a {@link java.time.YearMonth} that is {@code months} months after this year/month.
- *
- * @param self a YearMonth
- * @param months the number of months to add
- * @return a Year
- * @since 3.0
- */
- public static YearMonth plus(final YearMonth self, long months) {
- return self.plusMonths(months);
- }
-
- /**
- * Returns a {@link java.time.YearMonth} that is {@code months} months before this year/month.
- *
- * @param self a YearMonth
- * @param months the number of months to subtract
- * @return a Year
- * @since 3.0
- */
- public static YearMonth minus(final YearMonth self, long months) {
- return self.minusMonths(months);
- }
-
- /**
- * Returns a {@link java.time.YearMonth} that is the month after this year/month.
- *
- * @param self a YearMonth
- * @return the next YearMonth
- * @since 3.0
- */
- public static YearMonth next(final YearMonth self) {
- return plus(self, 1);
- }
-
- /**
- * Returns a {@link java.time.YearMonth} that is the month before this year/month.
- *
- * @param self a YearMonth
- * @return the previous YearMonth
- * @since 3.0
- */
- public static YearMonth previous(final YearMonth self) {
- return minus(self, 1);
- }
-
- /**
- * Returns a {@link java.time.LocalDate} of this year/month and the given day of the month.
- *
- * @param self a YearMonth
- * @param dayOfMonth a day of the month
- * @return a LocalDate
- * @since 3.0
- */
- public static LocalDate leftShift(final YearMonth self, int dayOfMonth) {
- return self.atDay(dayOfMonth);
- }
-
- /**
- * Returns a {@link java.time.Period} of time between the first day of this year/month (inclusive) and the
- * given {@link java.time.YearMonth} (exclusive).
- *
- * @param self a YearMonth
- * @param other another YearMonth
- * @return a Period
- * @since 3.0
- */
- public static Period rightShift(YearMonth self, YearMonth other) {
- return Period.between(self.atDay(1), other.atDay(1));
- }
-
- /* ******** java.time.ZonedDateTime extension methods ******** */
-
- /**
- * Formats this date/time with the provided {@link java.time.format.DateTimeFormatter} pattern.
- *
- * @param self a ZonedDateTime
- * @param pattern the formatting pattern
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String format(final ZonedDateTime self, String pattern) {
- return self.format(DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Formats this date/time in the provided, localized {@link java.time.format.FormatStyle}.
- *
- * @param self a ZonedDateTime
- * @param dateTimeStyle the FormatStyle
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String format(final ZonedDateTime self, FormatStyle dateTimeStyle) {
- return self.format(DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle));
- }
-
- /**
- * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE_TIME} formatter
- * and appends the zone's short name, e.g. {@code 2018-03-10T14:34:55.144EST}.
- *
- * @param self a ZonedDateTime
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String getDateTimeString(final ZonedDateTime self) {
- return self.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + self.format(ZONE_SHORT_FORMATTER);
- }
-
- /**
- * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE} formatter
- * and appends the zone's short name, e.g. {@code 2018-03-10EST}.
- *
- * @param self a ZonedDateTime
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String getDateString(final ZonedDateTime self) {
- return self.format(DateTimeFormatter.ISO_LOCAL_DATE) + self.format(ZONE_SHORT_FORMATTER);
- }
-
- /**
- * Formats this date/time with the {@link java.time.format.DateTimeFormatter#ISO_LOCAL_TIME} formatter
- * and appends the zone's short name, e.g. {@code 14:34:55.144EST}.
- *
- * @param self a ZonedDateTime
- * @return a formatted String
- * @see java.time.format.DateTimeFormatter
- * @since 3.0
- */
- public static String getTimeString(final ZonedDateTime self) {
- return self.format(DateTimeFormatter.ISO_LOCAL_TIME) + self.format(ZONE_SHORT_FORMATTER);
- }
-
- /**
- * Returns an {@link java.time.ZonedDateTime} with the time portion cleared.
- *
- * @param self a ZonedDateTime
- * @return a ZonedDateTime
- * @since 3.0
- */
- public static ZonedDateTime clearTime(final ZonedDateTime self) {
- return self.truncatedTo(DAYS);
- }
-
- /**
- * Returns a {@link java.time.ZonedDateTime} that is {@code seconds} seconds after this date/time.
- *
- * @param self an ZonedDateTime
- * @param seconds the number of seconds to add
- * @return a ZonedDateTime
- * @since 3.0
- */
- public static ZonedDateTime plus(final ZonedDateTime self, long seconds) {
- return self.plusSeconds(seconds);
- }
-
- /**
- * Returns a {@link java.time.ZonedDateTime} that is {@code seconds} seconds before this date/time.
- *
- * @param self a ZonedDateTime
- * @param seconds the number of seconds to subtract
- * @return a ZonedDateTime
- * @since 3.0
- */
- public static ZonedDateTime minus(final ZonedDateTime self, long seconds) {
- return self.minusSeconds(seconds);
- }
-
- /**
- * Returns a {@link java.time.ZonedDateTime} that is one second after this date/time.
- *
- * @param self a ZonedDateTime
- * @return a ZonedDateTime
- * @since 3.0
- */
- public static ZonedDateTime next(final ZonedDateTime self) {
- return plus(self, 1);
- }
-
- /**
- * Returns a {@link java.time.ZonedDateTime} that is one second before this date/time.
- *
- * @param self a ZonedDateTime
- * @return a ZonedDateTime
- * @since 3.0
- */
- public static ZonedDateTime previous(final ZonedDateTime self) {
- return minus(self, 1);
- }
-
- /**
- * Returns a generally equivalent instance of {@link java.util.Date}.
- * The time value of the returned date is truncated to milliseconds and will be
- * adjusted to the current system default time zone.
- *
- * @param self a ZonedDateTime
- * @return a java.util.Date
- * @since 3.0
- */
- public static Date toDate(final ZonedDateTime self) {
- return toCalendar(self).getTime();
- }
-
- /**
- * Returns a generally equivalent instance of {@link java.util.Calendar}.
- * The time value of the returned calendar is truncated to milliseconds and the time zone
- * is determined by the zone of this date/time.
- *
- * @param self an ZonedDateTime
- * @return a java.util.Calendar
- * @since 3.0
- */
- public static Calendar toCalendar(final ZonedDateTime self) {
- Calendar cal = Calendar.getInstance(toTimeZone(self.getZone()));
- cal.set(Calendar.DATE, self.getDayOfMonth());
- cal.set(Calendar.MONTH, self.getMonthValue() - 1);
- cal.set(Calendar.YEAR, self.getYear());
- cal.set(Calendar.HOUR_OF_DAY, self.getHour());
- cal.set(Calendar.MINUTE, self.getMinute());
- cal.set(Calendar.SECOND, self.getSecond());
- cal.set(Calendar.MILLISECOND, millisFromNanos(self.getNano()));
- return cal;
- }
-
- /* ******** java.time.ZoneId extension methods ******** */
-
- /**
- * Returns a {@link java.util.TimeZone} equivalent to this zone.
- *
- * @param self a ZoneId
- * @return a TimeZone
- * @since 3.0
- */
- public static TimeZone toTimeZone(final ZoneId self) {
- return TimeZone.getTimeZone(self);
- }
-
- /**
- * Returns the name of this zone formatted according to the {@link java.time.format.TextStyle#FULL} text style.
- *
- * @param self a ZoneId
- * @return the full display name of the ZoneId
- * @since 3.0
- */
- public static String getFullName(final ZoneId self) {
- return getFullName(self, Locale.getDefault());
- }
-
- /**
- * Returns the name of this zone formatted according to the {@link java.time.format.TextStyle#FULL} text style
- * for the provided {@link java.util.Locale}.
- *
- * @param self a ZoneId
- * @param locale a Locale
- * @return the full display name of the ZoneId
- * @since 3.0
- */
- public static String getFullName(final ZoneId self, Locale locale) {
- return self.getDisplayName(TextStyle.FULL, locale);
- }
-
- /**
- * Returns the name of this zone formatted according to the {@link java.time.format.TextStyle#SHORT} text style.
- *
- * @param self a ZoneId
- * @return the short display name of the ZoneId
- * @since 3.0
- */
- public static String getShortName(final ZoneId self) {
- return getShortName(self, Locale.getDefault());
- }
-
- /**
- * Returns the name of this zone formatted according to the {@link java.time.format.TextStyle#SHORT} text style
- * for the provided {@link java.util.Locale}.
- *
- * @param self a ZoneId
- * @param locale a Locale
- * @return the short display name of the ZoneId
- * @since 3.0
- */
- public static String getShortName(final ZoneId self, Locale locale) {
- return self.getDisplayName(TextStyle.SHORT, locale);
- }
-
- /**
- * Returns a {@link java.time.ZoneOffset} for this zone as of now.
- *
- * @param self a ZoneId
- * @return a ZoneOffset
- * @since 3.0
- */
- public static ZoneOffset getOffset(final ZoneId self) {
- return getOffset(self, Instant.now());
- }
-
- /**
- * Returns a {@link java.time.ZoneOffset} for this zone as of the provided {@link java.time.Instant}.
- *
- * @param self a ZoneId
- * @param instant an Instant
- * @return a ZoneOffset
- * @since 3.0
- */
- public static ZoneOffset getOffset(final ZoneId self, Instant instant) {
- return self.getRules().getOffset(instant);
- }
-
- /**
- * Returns a {@link java.time.ZonedDateTime} of this zone and the given {@link java.time.LocalDateTime}.
- *
- * @param self a ZoneId
- * @return a ZonedDateTime
- * @since 3.0
- */
- public static ZonedDateTime leftShift(final ZoneId self, LocalDateTime dateTime) {
- return ZonedDateTime.of(dateTime, self);
- }
-
- /* ******** java.time.ZoneOffset extension methods ******** */
-
- /**
- * Returns a generally equivalent {@link java.util.TimeZone}. The offset will be truncated to minutes.
- *
- * @param self a ZoneOffset
- * @return a TimeZone
- * @since 3.0
- */
- public static TimeZone toTimeZone(final ZoneOffset self) {
- if (ZoneOffset.UTC.equals(self)) {
- return TimeZone.getTimeZone("GMT");
- } else if (getSeconds(self) == 0) {
- return TimeZone.getTimeZone("GMT" + self.getId());
- } else {
- // TimeZone is only hours and minutes--no seconds
- ZoneOffset noSeconds = ZoneOffset.ofHoursMinutes(getHours(self), getMinutes(self));
- return TimeZone.getTimeZone("GMT" + noSeconds.getId());
- }
- }
-
- /**
- * Returns the value of the provided field for the ZoneOffset as if the ZoneOffset's
- * hours/minutes/seconds were reckoned as a LocalTime.
- */
- private static int offsetFieldValue(ZoneOffset offset, TemporalField field) {
- int offsetSeconds = offset.getTotalSeconds();
- int value = LocalTime.ofSecondOfDay(Math.abs(offsetSeconds)).get(field);
- return offsetSeconds < 0 ? value * -1 : value;
- }
-
- /**
- * Returns the hours component of this offset. If the offset's total seconds are negative, a negative
- * value will be returned.
- *
- * @param self a ZoneOffset
- * @return the hours component value
- * @since 3.0
- */
- public static int getHours(final ZoneOffset self) {
- return offsetFieldValue(self, ChronoField.HOUR_OF_DAY);
- }
-
- /**
- * Returns the minutes component of this offset. If the offset's total seconds are negative, a negative
- * value will be returned.
- *
- * @param self a ZoneOffset
- * @return the minutes component value
- * @since 3.0
- */
- public static int getMinutes(final ZoneOffset self) {
- return offsetFieldValue(self, ChronoField.MINUTE_OF_HOUR);
- }
-
- /**
- * Returns the seconds component of this offset. This is not the same as the total seconds. For example:
- * <pre>
- * def offset = ZoneOffset.ofHoursMinutesSeconds(0, 1, 1)
- * assert offset.seconds == 1
- * assert offset.totalSeconds == 61
- * </pre>
- * <p>
- * If the offset's total seconds are negative, a negative value will be returned.
- *
- * @param self a ZoneOffset
- * @return the seconds component value
- * @since 3.0
- */
- public static int getSeconds(final ZoneOffset self) {
- return offsetFieldValue(self, ChronoField.SECOND_OF_MINUTE);
- }
-
- /**
- * Supports the getAt operator; equivalent to calling the
- * {@link java.time.ZoneOffset#getLong(java.time.temporal.TemporalField)} method.
- *
- * @param self a ZoneOffset
- * @param field a TemporalField
- * @return the ZoneOffset's field value
- * @since 3.0
- */
- public static long getAt(final ZoneOffset self, TemporalField field) {
- return self.getLong(field);
- }
-
- /**
- * Returns an {@link java.time.OffsetDateTime} of this offset and the provided {@link java.time.LocalDateTime}.
- *
- * @param self a ZoneOffset
- * @param dateTime a LocalDateTime
- * @return an OffsetDateTime
- * @since 3.0
- */
- public static OffsetDateTime leftShift(final ZoneOffset self, LocalDateTime dateTime) {
- return OffsetDateTime.of(dateTime, self);
- }
-
- /**
- * Returns an {@link java.time.OffsetDateTime} of this offset and the provided {@link java.time.LocalTime}.
- *
- * @param self a ZoneOffset
- * @param time a LocalTime
- * @return an OffsetTime
- * @since 3.0
- */
- public static OffsetTime leftShift(final ZoneOffset self, LocalTime time) {
- return OffsetTime.of(time, self);
- }
-
- /* ******** java.time.DayOfWeek extension methods ******** */
-
- /**
- * Returns the {@link java.time.DayOfWeek} that is {@code days} many days after this day of the week.
- *
- * @param self a DayOfWeek
- * @param days the number of days to move forward
- * @return the DayOfWeek
- * @since 3.0
- */
- public static DayOfWeek plus(final DayOfWeek self, int days) {
- int daysPerWeek = DayOfWeek.values().length;
- int val = ((self.getValue() + days - 1) % daysPerWeek) + 1;
- return DayOfWeek.of(val > 0 ? val : daysPerWeek + val);
- }
-
- /**
- * Returns the {@link java.time.DayOfWeek} that is {@code days} many days before this day of the week.
- *
- * @param self a DayOfWeek
- * @param days the number of days to move back
- * @return the DayOfWeek
- * @since 3.0
- */
- public static DayOfWeek minus(final DayOfWeek self, int days) {
- return plus(self, days * -1);
- }
-
- /**
- * Returns {@code true} if this day of the week is a weekend day (Saturday or Sunday).
- *
- * @param self a DayOfWeek
- * @return true if this DayOfWeek is Saturday or Sunday
- * @since 3.0
- */
- public static boolean isWeekend(final DayOfWeek self) {
- return self == DayOfWeek.SATURDAY || self == DayOfWeek.SUNDAY;
- }
-
- /**
- * Returns {@code true} if the DayOfWeek is a weekday.
- *
- * @return true if this DayOfWeek is Monday through Friday
- * @since 3.0
- */
- public static boolean isWeekday(final DayOfWeek self) {
- return !isWeekend(self);
- }
-
- /* ******** java.time.Month extension methods ******** */
-
- /**
- * Returns the {@link java.time.Month} that is {@code months} months after this month.
- *
- * @param self a Month
- * @param months the number of months move forward
- * @return the Month
- * @since 3.0
- */
- public static Month plus(final Month self, int months) {
- int monthsPerYear = Month.values().length;
- int val = ((self.getValue() + months - 1) % monthsPerYear) + 1;
- return Month.of(val > 0 ? val : monthsPerYear + val);
- }
-
- /**
- * Returns the {@link java.time.Month} that is {@code months} months before this month.
- *
- * @param self a Month
- * @param months the number of months to move back
- * @return the Month
- * @since 3.0
- */
- public static Month minus(final Month self, int months) {
- return plus(self, months * -1);
- }
-
- /**
- * Creates a {@link java.time.MonthDay} at the provided day of the month.
- *
- * @param self a Month
- * @param dayOfMonth a day of the month
- * @return a MonthDay
- * @since 3.0
- */
- public static MonthDay leftShift(final Month self, int dayOfMonth) {
- return MonthDay.of(self, dayOfMonth);
- }
-
- /**
- * Creates a {@link java.time.YearMonth} at the provided {@link java.time.Year}.
- *
- * @param self a Month
- * @param year a Year
- * @return a YearMonth
- * @since 3.0
- */
- public static YearMonth leftShift(final Month self, Year year) {
- return YearMonth.of(year.getValue(), self);
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index 1a356a5..fedaa29 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -220,15 +220,16 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
public static final Class[] DGM_LIKE_CLASSES = new Class[]{
DefaultGroovyMethods.class,
- DateGroovyMethods.class,
- DateTimeGroovyMethods.class,
EncodingGroovyMethods.class,
IOGroovyMethods.class,
ProcessGroovyMethods.class,
ResourceGroovyMethods.class,
SocketGroovyMethods.class,
StringGroovyMethods.class//,
- // TODO provide alternative way for these to be registered
+ // Below are registered as module extension classes
+// DateUtilExtensions.class,
+// DateTimeStaticExtensions.class,
+// DateTimeExtensions.class,
// SqlGroovyMethods.class,
// SwingGroovyMethods.class,
// XmlGroovyMethods.class,
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
index 5b88e78..ed2d2a2 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
@@ -318,208 +318,4 @@ public class DefaultGroovyStaticMethods {
return System.currentTimeMillis() / 1000;
}
- /**
- * Parse text into a {@link java.time.LocalDate} using the provided pattern.
- *
- * @param type placeholder variable used by Groovy categories; ignored for default static methods
- * @param text String to be parsed to create the date instance
- * @param pattern pattern used to parse the text
- * @return a LocalDate representing the parsed text
- * @throws java.lang.IllegalArgumentException if the pattern is invalid
- * @throws java.time.format.DateTimeParseException if the text cannot be parsed
- * @see java.time.format.DateTimeFormatter
- * @see java.time.LocalDate#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
- * @since 3.0
- */
- public static LocalDate parse(final LocalDate type, CharSequence text, String pattern) {
- return LocalDate.parse(text, DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Parse text into a {@link java.time.LocalDateTime} using the provided pattern.
- *
- * @param type placeholder variable used by Groovy categories; ignored for default static methods
- * @param text String to be parsed to create the date instance
- * @param pattern pattern used to parse the text
- * @return a LocalDateTime representing the parsed text
- * @throws java.lang.IllegalArgumentException if the pattern is invalid
- * @throws java.time.format.DateTimeParseException if the text cannot be parsed
- * @see java.time.format.DateTimeFormatter
- * @see java.time.LocalDateTime#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
- * @since 3.0
- */
- public static LocalDateTime parse(final LocalDateTime type, CharSequence text, String pattern) {
- return LocalDateTime.parse(text, DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Parse text into a {@link java.time.LocalTime} using the provided pattern.
- *
- * @param type placeholder variable used by Groovy categories; ignored for default static methods
- * @param text String to be parsed to create the date instance
- * @param pattern pattern used to parse the text
- * @return a LocalTime representing the parsed text
- * @throws java.lang.IllegalArgumentException if the pattern is invalid
- * @throws java.time.format.DateTimeParseException if the text cannot be parsed
- * @see java.time.format.DateTimeFormatter
- * @see java.time.LocalTime#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
- * @since 3.0
- */
- public static LocalTime parse(final LocalTime type, CharSequence text, String pattern) {
- return LocalTime.parse(text, DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Parse text into a {@link java.time.MonthDay} using the provided pattern.
- *
- * @param type placeholder variable used by Groovy categories; ignored for default static methods
- * @param text String to be parsed to create the date instance
- * @param pattern pattern used to parse the text
- * @return a MonthDay representing the parsed text
- * @throws java.lang.IllegalArgumentException if the pattern is invalid
- * @throws java.time.format.DateTimeParseException if the text cannot be parsed
- * @see java.time.format.DateTimeFormatter
- * @see java.time.MonthDay#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
- * @since 3.0
- */
- public static MonthDay parse(final MonthDay type, CharSequence text, String pattern) {
- return MonthDay.parse(text, DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Parse text into an {@link java.time.OffsetDateTime} using the provided pattern.
- *
- * @param type placeholder variable used by Groovy categories; ignored for default static methods
- * @param text String to be parsed to create the date instance
- * @param pattern pattern used to parse the text
- * @return an OffsetDateTime representing the parsed text
- * @throws java.lang.IllegalArgumentException if the pattern is invalid
- * @throws java.time.format.DateTimeParseException if the text cannot be parsed
- * @see java.time.format.DateTimeFormatter
- * @see java.time.OffsetDateTime#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
- * @since 3.0
- */
- public static OffsetDateTime parse(final OffsetDateTime type, CharSequence text, String pattern) {
- return OffsetDateTime.parse(text, DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Parse text into an {@link java.time.OffsetTime} using the provided pattern.
- *
- * @param type placeholder variable used by Groovy categories; ignored for default static methods
- * @param text String to be parsed to create the date instance
- * @param pattern pattern used to parse the text
- * @return an OffsetTime representing the parsed text
- * @throws java.lang.IllegalArgumentException if the pattern is invalid
- * @throws java.time.format.DateTimeParseException if the text cannot be parsed
- * @see java.time.format.DateTimeFormatter
- * @see java.time.OffsetTime#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
- * @since 3.0
- */
- public static OffsetTime parse(final OffsetTime type, CharSequence text, String pattern) {
- return OffsetTime.parse(text, DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Parse text into a {@link java.time.Year} using the provided pattern.
- *
- * @param type placeholder variable used by Groovy categories; ignored for default static methods
- * @param text String to be parsed to create the date instance
- * @param pattern pattern used to parse the text
- * @return a Year representing the parsed text
- * @throws java.lang.IllegalArgumentException if the pattern is invalid
- * @throws java.time.format.DateTimeParseException if the text cannot be parsed
- * @see java.time.format.DateTimeFormatter
- * @see java.time.Year#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
- * @since 3.0
- */
- public static Year parse(final Year type, CharSequence text, String pattern) {
- return Year.parse(text, DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Parse text into a {@link java.time.YearMonth} using the provided pattern.
- *
- * @param type placeholder variable used by Groovy categories; ignored for default static methods
- * @param text String to be parsed to create the date instance
- * @param pattern pattern used to parse the text
- * @return a YearMonth representing the parsed text
- * @throws java.lang.IllegalArgumentException if the pattern is invalid
- * @throws java.time.format.DateTimeParseException if the text cannot be parsed
- * @see java.time.format.DateTimeFormatter
- * @see java.time.YearMonth#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
- * @since 3.0
- */
- public static YearMonth parse(final YearMonth type, CharSequence text, String pattern) {
- return YearMonth.parse(text, DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Parse text into a {@link java.time.ZonedDateTime} using the provided pattern.
- *
- * @param type placeholder variable used by Groovy categories; ignored for default static methods
- * @param text String to be parsed to create the date instance
- * @param pattern pattern used to parse the text
- * @return a ZonedDateTime representing the parsed text
- * @throws java.lang.IllegalArgumentException if the pattern is invalid
- * @throws java.time.format.DateTimeParseException if the text cannot be parsed
- * @see java.time.format.DateTimeFormatter
- * @see java.time.ZonedDateTime#parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
- * @since 3.0
- */
- public static ZonedDateTime parse(final ZonedDateTime type, CharSequence text, String pattern) {
- return ZonedDateTime.parse(text, DateTimeFormatter.ofPattern(pattern));
- }
-
- /**
- * Returns the {@link java.time.ZoneOffset} currently associated with the system default {@link java.time.ZoneId}.
- *
- * @param type placeholder variable used by Groovy categories; ignored for default static methods
- * @return a ZoneOffset
- * @see java.time.ZoneId#systemDefault()
- * @since 3.0
- */
- public static ZoneOffset systemDefault(final ZoneOffset type) {
- return DateTimeGroovyMethods.getOffset(ZoneId.systemDefault());
- }
-
- /**
- * Obtains a Period consisting of the number of years between two {@link java.time.Year} instances.
- * The months and days of the Period will be zero.
- * The result of this method can be a negative period if the end is before the start.
- *
- * @param type placeholder variable used by Groovy categories; ignored for default static methods
- * @param startInclusive the start {@link java.time.Year}, inclusive, not null
- * @param endExclusive the end {@link java.time.Year}, exclusive, not null
- * @return a Period between the years
- * @see java.time.Period#between(LocalDate, LocalDate)
- */
- public static Period between(final Period type, Year startInclusive, Year endExclusive) {
- MonthDay now = MonthDay.of(Month.JANUARY, 1);
- return Period.between(
- DateTimeGroovyMethods.leftShift(startInclusive, now),
- DateTimeGroovyMethods.leftShift(endExclusive, now))
- .withDays(0)
- .withMonths(0);
- }
-
- /**
- * Obtains a Period consisting of the number of years and months between two {@link java.time.YearMonth} instances.
- * The days of the Period will be zero.
- * The result of this method can be a negative period if the end is before the start.
- *
- * @param type placeholder variable used by Groovy categories; ignored for default static methods
- * @param startInclusive the start {@link java.time.YearMonth}, inclusive, not null
- * @param endExclusive the end {@link java.time.YearMonth}, exclusive, not null
- * @return a Period between the year/months
- * @see java.time.Period#between(LocalDate, LocalDate)
- */
- public static Period between(final Period type, YearMonth startInclusive, YearMonth endExclusive) {
- int dayOfMonth = 1;
- return Period.between(
- DateTimeGroovyMethods.leftShift(startInclusive, dayOfMonth),
- DateTimeGroovyMethods.leftShift(endExclusive, dayOfMonth))
- .withDays(0);
- }
-
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/src/spec/doc/core-gdk.adoc
----------------------------------------------------------------------
diff --git a/src/spec/doc/core-gdk.adoc b/src/spec/doc/core-gdk.adoc
index 2d239fe..7a79e0b 100644
--- a/src/spec/doc/core-gdk.adoc
+++ b/src/spec/doc/core-gdk.adoc
@@ -25,7 +25,9 @@ include::{projectdir}/src/spec/doc/working-with-io.adoc[leveloffset=+1]
include::{projectdir}/src/spec/doc/working-with-collections.adoc[leveloffset=+1]
-include::{projectdir}/src/spec/doc/working-with-datetime-types.adoc[leveloffset=+1]
+include::{projectdir}/subprojects/groovy-dateutil/{specfolder}/working-with-dateutil-types.adoc[leveloffset=+1]
+
+include::{projectdir}/subprojects/groovy-datetime/{specfolder}/working-with-datetime-types.adoc[leveloffset=+1]
== Handy utilities
[6/7] groovy git commit: move datetime extensions to their own module
Posted by pa...@apache.org.
move datetime extensions to their own module
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/6d32a16c
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/6d32a16c
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/6d32a16c
Branch: refs/heads/master
Commit: 6d32a16c4c9412366d77f40b6eeb8b77bfccba6f
Parents: 4abc754
Author: paulk <pa...@asert.com.au>
Authored: Thu Mar 22 00:41:01 2018 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Thu Mar 22 00:41:01 2018 +1000
----------------------------------------------------------------------
build.gradle | 1 +
gradle/binarycompatibility.gradle | 2 +-
gradle/docs.gradle | 5 +-
gradle/pomconfigurer.gradle | 3 +
settings.gradle | 9 +-
.../groovy/runtime/DateGroovyMethods.java | 880 +------
.../groovy/runtime/DateTimeGroovyMethods.java | 2030 ---------------
.../groovy/runtime/DefaultGroovyMethods.java | 7 +-
.../runtime/DefaultGroovyStaticMethods.java | 204 --
src/spec/doc/core-gdk.adoc | 4 +-
src/spec/doc/working-with-datetime-types.adoc | 341 ---
.../gdk/WorkingWithDateTimeTypesTest.groovy | 222 --
src/test/groovy/DateTest.groovy | 79 -
src/test/groovy/DateTimeTest.groovy | 821 ------
.../groovy/runtime/DateGroovyMethodsTest.java | 116 -
.../codehaus/groovy/runtime/DateGDKTest.groovy | 275 --
subprojects/groovy-datetime/build.gradle | 29 +
.../datetime/extensions/DateTimeExtensions.java | 2419 ++++++++++++++++++
.../extensions/DateTimeStaticExtensions.java | 250 ++
.../spec/doc/working-with-datetime-types.adoc | 338 +++
.../gdk/WorkingWithDateTimeTypesTest.groovy | 253 ++
.../src/test/java/groovy/DateTimeTest.groovy | 851 ++++++
.../extensions/DateTimeExtensionsTest.java | 94 +
subprojects/groovy-dateutil/build.gradle | 28 +
.../dateutil/extensions/DateUtilExtensions.java | 778 ++++++
.../spec/doc/working-with-dateutil-types.adoc | 54 +
.../gdk/WorkingWithDateUtilTypesTest.groovy | 81 +
.../src/test/java/groovy/DateTest.groovy | 327 +++
.../extensions/DateUtilExtensionsTest.java | 64 +
subprojects/groovy-json/build.gradle | 1 +
30 files changed, 5628 insertions(+), 4938 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index 94405cf..e05d973 100644
--- a/build.gradle
+++ b/build.gradle
@@ -257,6 +257,7 @@ dependencies {
antlr2 "org.apache.ant:ant-antlr:$antVersion"
testCompile project(':groovy-ant')
+ testCompile project(':groovy-dateutil')
testCompile project(':groovy-test')
testCompile project(':groovy-macro')
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/gradle/binarycompatibility.gradle
----------------------------------------------------------------------
diff --git a/gradle/binarycompatibility.gradle b/gradle/binarycompatibility.gradle
index 3dfdbdd..0b6e04f 100644
--- a/gradle/binarycompatibility.gradle
+++ b/gradle/binarycompatibility.gradle
@@ -35,7 +35,7 @@ task checkBinaryCompatibility {
check.dependsOn(checkBinaryCompatibility)
// for comparing between versions with different modules, set excludeModules to differing modules, e.g.
-def excludeModules = ['performance', 'groovy-macro', 'tests-vm8', 'groovy-json-direct']
+def excludeModules = ['groovy-dateutil', 'groovy-datetime', 'performance', 'groovy-macro', 'tests-vm8', 'groovy-json-direct']
//def excludeModules = []
Set projectsToCheck = allprojects.findAll{ !(it.name in excludeModules) }
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/gradle/docs.gradle
----------------------------------------------------------------------
diff --git a/gradle/docs.gradle b/gradle/docs.gradle
index 9fb0ca7..ac4fc7d 100644
--- a/gradle/docs.gradle
+++ b/gradle/docs.gradle
@@ -141,8 +141,6 @@ task docGDK {
// either package name if in core or fully qualified path otherwise
arg(value: 'org.codehaus.groovy.runtime.DefaultGroovyMethods')
arg(value: 'org.codehaus.groovy.runtime.DefaultGroovyStaticMethods')
- arg(value: 'org.codehaus.groovy.runtime.DateGroovyMethods')
- arg(value: 'org.codehaus.groovy.runtime.DateTimeGroovyMethods')
arg(value: 'org.codehaus.groovy.runtime.EncodingGroovyMethods')
arg(value: 'org.codehaus.groovy.runtime.IOGroovyMethods')
arg(value: 'org.codehaus.groovy.runtime.ProcessGroovyMethods')
@@ -152,6 +150,9 @@ task docGDK {
arg(value: 'org.codehaus.groovy.vmplugin.v5.PluginDefaultGroovyMethods')
arg(value: 'org.codehaus.groovy.vmplugin.v8.PluginDefaultGroovyMethods')
// TODO don't hard-code these
+ arg(value: 'subprojects/groovy-dateutil/src/main/java/org/apache/groovy/dateutil/extensions/DateUtilExtensions.java')
+ arg(value: 'subprojects/groovy-datetime/src/main/java/org/apache/groovy/dateutil/extensions/DateTimeExtensions.java')
+ arg(value: 'subprojects/groovy-datetime/src/main/java/org/apache/groovy/dateutil/extensions/DateTimeStaticExtensions.java')
arg(value: 'subprojects/groovy-sql/src/main/java/org/codehaus/groovy/runtime/SqlGroovyMethods.java')
arg(value: 'subprojects/groovy-swing/src/main/java/org/codehaus/groovy/runtime/SwingGroovyMethods.java')
arg(value: 'subprojects/groovy-xml/src/main/java/org/codehaus/groovy/runtime/XmlGroovyMethods.java')
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/gradle/pomconfigurer.gradle
----------------------------------------------------------------------
diff --git a/gradle/pomconfigurer.gradle b/gradle/pomconfigurer.gradle
index 1bbfcc2..1ebe9ed 100644
--- a/gradle/pomconfigurer.gradle
+++ b/gradle/pomconfigurer.gradle
@@ -609,6 +609,9 @@ project.ext.pomConfigureClosureWithoutTweaks = {
contributor {
name 'Kent Inge Fagerland Simonsen'
}
+ contributor {
+ name 'Tom Nichols'
+ }
}
mailingLists {
mailingList {
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/settings.gradle
----------------------------------------------------------------------
diff --git a/settings.gradle b/settings.gradle
index fe0915d..271d33a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -19,6 +19,8 @@
def subprojects = ['groovy-ant',
'groovy-bsf',
'groovy-console',
+ 'groovy-datetime',
+ 'groovy-dateutil',
'groovy-docgenerator',
'groovy-groovydoc',
'groovy-groovysh',
@@ -34,13 +36,10 @@ def subprojects = ['groovy-ant',
'groovy-test',
'groovy-testng',
'groovy-xml',
- 'groovy-macro'
+ 'groovy-macro',
+ 'performance'
]
-if (JavaVersion.current().isJava8Compatible()) {
- subprojects << 'performance'
-}
-
if (hasProperty('stressTests')) {
subprojects << 'stress'
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/6d32a16c/src/main/java/org/codehaus/groovy/runtime/DateGroovyMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DateGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DateGroovyMethods.java
index c811fb8..f452d13 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DateGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DateGroovyMethods.java
@@ -24,105 +24,42 @@ import groovy.lang.GroovyRuntimeException;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
-import java.time.DayOfWeek;
-import java.time.Instant;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.Month;
-import java.time.MonthDay;
-import java.time.OffsetDateTime;
-import java.time.OffsetTime;
-import java.time.Year;
-import java.time.YearMonth;
-import java.time.ZoneId;
-import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
/**
- * This class defines new groovy methods which appear on normal JDK
- * Date and Calendar classes inside the Groovy environment.
+ * @deprecated use DateUtilExtensions instead
*/
+@Deprecated
public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
- /**
- * Support the subscript operator for a Date.
- *
- * @param self a Date
- * @param field a Calendar field, e.g. MONTH
- * @return the value for the given field, e.g. FEBRUARY
- * @see java.util.Calendar
- * @since 1.5.5
- */
+ @Deprecated
public static int getAt(Date self, int field) {
Calendar cal = Calendar.getInstance();
cal.setTime(self);
return cal.get(field);
}
- /**
- * Convert a Date to a Calendar.
- *
- * @param self a Date
- * @return a Calendar corresponding to the given Date
- * @since 1.7.6
- */
+ @Deprecated
public static Calendar toCalendar(Date self) {
Calendar cal = Calendar.getInstance();
cal.setTime(self);
return cal;
}
- /**
- * Support the subscript operator for a Calendar.
- *
- * @param self a Calendar
- * @param field a Calendar field, e.g. MONTH
- * @return the value for the given field, e.g. FEBRUARY
- * @see java.util.Calendar
- * @since 1.7.3
- */
+ @Deprecated
public static int getAt(Calendar self, int field) {
return self.get(field);
}
- /**
- * Support the subscript operator for mutating a Calendar.
- * Example usage:
- * <pre>
- * import static java.util.Calendar.*
- * def cal = Calendar.instance
- * cal[DAY_OF_WEEK] = MONDAY
- * cal[MONTH] = MARCH
- * println cal.time // A Monday in March
- * </pre>
- *
- * @param self A Calendar
- * @param field A Calendar field, e.g. MONTH
- * @param value The value for the given field, e.g. FEBRUARY
- * @see java.util.Calendar#set(int, int)
- * @since 1.7.3
- */
+ @Deprecated
public static void putAt(Calendar self, int field, int value) {
self.set(field, value);
}
- /**
- * Support the subscript operator for mutating a Date.
- *
- * @param self A Date
- * @param field A Calendar field, e.g. MONTH
- * @param value The value for the given field, e.g. FEBRUARY
- * @see #putAt(java.util.Calendar, int, int)
- * @see java.util.Calendar#set(int, int)
- * @since 1.7.3
- */
+ @Deprecated
public static void putAt(Date self, int field, int value) {
Calendar cal = Calendar.getInstance();
cal.setTime(self);
@@ -130,125 +67,30 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
self.setTime(cal.getTimeInMillis());
}
- /**
- * Support mutating a Calendar with a Map.
- * <p>
- * The map values are the normal values provided as the
- * second parameter to <code>java.util.Calendar#set(int, int)</code>.
- * The keys can either be the normal fields values provided as
- * the first parameter to that method or one of the following Strings:
- * <table border="1" cellpadding="4">
- * <caption>Calendar index values</caption>
- * <tr><td>year</td><td>Calendar.YEAR</td></tr>
- * <tr><td>month</td><td>Calendar.MONTH</td></tr>
- * <tr><td>date</td><td>Calendar.DATE</td></tr>
- * <tr><td>dayOfMonth</td><td>Calendar.DATE</td></tr>
- * <tr><td>hourOfDay</td><td>Calendar.HOUR_OF_DAY</td></tr>
- * <tr><td>minute</td><td>Calendar.MINUTE</td></tr>
- * <tr><td>second</td><td>Calendar.SECOND</td></tr>
- * </table>
- * Example usage:
- * <pre>
- * import static java.util.Calendar.*
- * def cal = Calendar.instance
- * def m = [:]
- * m[YEAR] = 2010
- * m[MONTH] = DECEMBER
- * m[DATE] = 25
- * cal.set(m)
- * println cal.time // Christmas 2010
- *
- * cal.set(year:2011, month:DECEMBER, date:25)
- * println cal.time // Christmas 2010
- * </pre>
- *
- * @param self A Calendar
- * @param updates A Map of Calendar keys and values
- * @see java.util.Calendar#set(int, int)
- * @see java.util.Calendar#set(int, int, int, int, int, int)
- * @since 1.7.3
- */
+ @Deprecated
public static void set(Calendar self, Map<Object, Integer> updates) {
for (Map.Entry<Object, Integer> entry : updates.entrySet()) {
Object key = entry.getKey();
- if (key instanceof String) key = CAL_MAP.get(key);
+// if (key instanceof String) key = CAL_MAP.get(key);
if (key instanceof Integer) self.set((Integer) key, entry.getValue());
}
}
- /**
- * Legacy alias for copyWith. Will be deprecated and removed in future versions of Groovy.
- *
- * @see #copyWith(java.util.Calendar, java.util.Map)
- * @since 1.7.3
- */
+ @Deprecated
public static Calendar updated(Calendar self, Map<Object, Integer> updates) {
Calendar result = (Calendar) self.clone();
set(result, updates);
return result;
}
- /**
- * Support creating a new Date having similar properties to
- * an existing Date (which remains unaltered) but with
- * some fields updated according to a Map of changes.
- * <p>
- * Example usage:
- * <pre>
- * import static java.util.Calendar.YEAR
- * def now = Calendar.instance
- * def nextYear = now[YEAR] + 1
- * def oneYearFromNow = now.copyWith(year: nextYear)
- * println now.time
- * println oneYearFromNow.time
- * </pre>
- *
- * @param self A Calendar
- * @param updates A Map of Calendar keys and values
- * @return The newly created Calendar
- * @see java.util.Calendar#set(int, int)
- * @see java.util.Calendar#set(int, int, int, int, int, int)
- * @see #set(java.util.Calendar, java.util.Map)
- * @since 2.2.0
- */
+ @Deprecated
public static Calendar copyWith(Calendar self, Map<Object, Integer> updates) {
Calendar result = (Calendar) self.clone();
set(result, updates);
return result;
}
- /**
- * Support mutating a Date with a Map.
- * <p>
- * The map values are the normal values provided as the
- * second parameter to <code>java.util.Calendar#set(int, int)</code>.
- * The keys can either be the normal fields values provided as
- * the first parameter to that method or one of the following Strings:
- * <table border="1" cellpadding="4">
- * <caption>Calendar index values</caption>
- * <tr><td>year</td><td>Calendar.YEAR</td></tr>
- * <tr><td>month</td><td>Calendar.MONTH</td></tr>
- * <tr><td>date</td><td>Calendar.DATE</td></tr>
- * <tr><td>dayOfMonth</td><td>Calendar.DATE</td></tr>
- * <tr><td>hourOfDay</td><td>Calendar.HOUR_OF_DAY</td></tr>
- * <tr><td>minute</td><td>Calendar.MINUTE</td></tr>
- * <tr><td>second</td><td>Calendar.SECOND</td></tr>
- * </table>
- * Example usage:
- * <pre>
- * import static java.util.Calendar.YEAR
- * def date = new Date()
- * def nextYear = date[YEAR] + 1
- * date.set(year: nextYear)
- * println date
- * </pre>
- *
- * @param self A Date
- * @param updates A Map of Calendar keys and values
- * @see java.util.Calendar#set(int, int)
- * @see #set(java.util.Calendar, java.util.Map)
- * @since 1.7.3
- */
+ @Deprecated
public static void set(Date self, Map<Object, Integer> updates) {
Calendar cal = Calendar.getInstance();
cal.setTime(self);
@@ -256,12 +98,7 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
self.setTime(cal.getTimeInMillis());
}
- /**
- * Legacy alias for copyWith. Will be deprecated and removed in future versions of Groovy.
- *
- * @see #copyWith(java.util.Date, java.util.Map)
- * @since 1.7.3
- */
+ @Deprecated
public static Date updated(Date self, Map<Object, Integer> updates) {
Calendar cal = Calendar.getInstance();
cal.setTime(self);
@@ -269,29 +106,7 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
return cal.getTime();
}
- /**
- * Support creating a new Date having similar properties to
- * an existing Date (which remains unaltered) but with
- * some fields updated according to a Map of changes.
- * <p>
- * Example usage:
- * <pre>
- * import static java.util.Calendar.YEAR
- * def today = new Date()
- * def nextYear = today[YEAR] + 1
- * def oneYearFromNow = today.copyWith(year: nextYear)
- * println today
- * println oneYearFromNow
- * </pre>
- *
- * @param self A Date
- * @param updates A Map of Calendar keys and values
- * @return The newly created Date
- * @see java.util.Calendar#set(int, int)
- * @see #set(java.util.Date, java.util.Map)
- * @see #copyWith(java.util.Calendar, java.util.Map)
- * @since 2.2.0
- */
+ @Deprecated
public static Date copyWith(Date self, Map<Object, Integer> updates) {
Calendar cal = Calendar.getInstance();
cal.setTime(self);
@@ -299,96 +114,41 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
return cal.getTime();
}
- private static final Map<String, Integer> CAL_MAP = new HashMap<String, Integer>();
-
- static {
- CAL_MAP.put("year", Calendar.YEAR);
- CAL_MAP.put("month", Calendar.MONTH);
- CAL_MAP.put("date", Calendar.DATE);
- CAL_MAP.put("dayOfMonth", Calendar.DATE);
- CAL_MAP.put("hourOfDay", Calendar.HOUR_OF_DAY);
- CAL_MAP.put("minute", Calendar.MINUTE);
- CAL_MAP.put("second", Calendar.SECOND);
- }
-
- /**
- * Increment a Date by one day.
- *
- * @param self a Date
- * @return the next days date
- * @since 1.0
- */
+ @Deprecated
public static Date next(Date self) {
return plus(self, 1);
}
- /**
- * Increment a Calendar by one day.
- *
- * @param self a Calendar
- * @return a new Calendar set to the next day
- * @since 1.8.7
- */
+ @Deprecated
public static Calendar next(Calendar self) {
Calendar result = (Calendar) self.clone();
result.add(Calendar.DATE, 1);
return result;
}
- /**
- * Decrement a Calendar by one day.
- *
- * @param self a Calendar
- * @return a new Calendar set to the previous day
- * @since 1.8.7
- */
+ @Deprecated
public static Calendar previous(Calendar self) {
Calendar result = (Calendar) self.clone();
result.add(Calendar.DATE, -1);
return result;
}
- /**
- * Increment a java.sql.Date by one day.
- *
- * @param self a java.sql.Date
- * @return the next days date
- * @since 1.0
- */
+ @Deprecated
public static java.sql.Date next(java.sql.Date self) {
return new java.sql.Date(next((Date) self).getTime());
}
- /**
- * Decrement a Date by one day.
- *
- * @param self a Date
- * @return the previous days date
- * @since 1.0
- */
+ @Deprecated
public static Date previous(Date self) {
return minus(self, 1);
}
- /**
- * Decrement a java.sql.Date by one day.
- *
- * @param self a java.sql.Date
- * @return the previous days date
- * @since 1.0
- */
+ @Deprecated
public static java.sql.Date previous(java.sql.Date self) {
return new java.sql.Date(previous((Date) self).getTime());
}
- /**
- * Add a number of days to this date and returns the new date.
- *
- * @param self a Date
- * @param days the number of days to increase
- * @return the new date
- * @since 1.0
- */
+ @Deprecated
public static Date plus(Date self, int days) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(self);
@@ -396,25 +156,12 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
return calendar.getTime();
}
- /**
- * Add a number of days to this date and returns the new date.
- *
- * @param self a java.sql.Date
- * @param days the number of days to increase
- * @return the new date
- * @since 1.0
- */
+ @Deprecated
public static java.sql.Date plus(java.sql.Date self, int days) {
return new java.sql.Date(plus((Date) self, days).getTime());
}
- /**
- * Add number of days to this Timestamp and returns the new Timestamp object.
- *
- * @param self a Timestamp
- * @param days the number of days to increase
- * @return the new Timestamp
- */
+ @Deprecated
public static Timestamp plus(Timestamp self, int days) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(self);
@@ -424,53 +171,22 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
return ts;
}
- /**
- * Subtract a number of days from this date and returns the new date.
- *
- * @param self a Date
- * @param days the number of days to subtract
- * @return the new date
- * @since 1.0
- */
+ @Deprecated
public static Date minus(Date self, int days) {
return plus(self, -days);
}
- /**
- * Subtract a number of days from this date and returns the new date.
- *
- * @param self a java.sql.Date
- * @param days the number of days to subtract
- * @return the new date
- * @since 1.0
- */
+ @Deprecated
public static java.sql.Date minus(java.sql.Date self, int days) {
return new java.sql.Date(minus((Date) self, days).getTime());
}
- /**
- * Subtract a number of days from this Timestamp and returns the new Timestamp object.
- *
- * @param self a Timestamp
- * @param days the number of days to subtract
- * @return the new Timestamp
- */
+ @Deprecated
public static Timestamp minus(Timestamp self, int days) {
return plus(self, -days);
}
- /**
- * Subtract another date from this one and return the number of days of the difference.
- * <p>
- * Date self = Date then + (Date self - Date then)
- * <p>
- * IOW, if self is before then the result is a negative value.
- *
- * @param self a Calendar
- * @param then another Calendar
- * @return number of days
- * @since 1.6.0
- */
+ @Deprecated
public static int minus(Calendar self, Calendar then) {
Calendar a = self;
Calendar b = then;
@@ -500,18 +216,7 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
return days;
}
- /**
- * Subtract another Date from this one and return the number of days of the difference.
- * <p>
- * Date self = Date then + (Date self - Date then)
- * <p>
- * IOW, if self is before then the result is a negative value.
- *
- * @param self a Date
- * @param then another Date
- * @return number of days
- * @since 1.6.0
- */
+ @Deprecated
public static int minus(Date self, Date then) {
Calendar a = (Calendar) Calendar.getInstance().clone();
a.setTime(self);
@@ -520,118 +225,34 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
return minus(a, b);
}
- /**
- * <p>Create a String representation of this date according to the given
- * format pattern.
- * <p>
- * <p>For example, if the system timezone is GMT,
- * <code>new Date(0).format('MM/dd/yy')</code> would return the string
- * <code>"01/01/70"</code>. See documentation for {@link java.text.SimpleDateFormat}
- * for format pattern use.
- * <p>
- * <p>Note that a new DateFormat instance is created for every
- * invocation of this method (for thread safety).
- *
- * @param self a Date
- * @param format the format pattern to use according to {@link java.text.SimpleDateFormat}
- * @return a string representation of this date.
- * @see java.text.SimpleDateFormat
- * @since 1.5.7
- */
+ @Deprecated
public static String format(Date self, String format) {
return new SimpleDateFormat(format).format(self);
}
- /**
- * <p>Create a String representation of this date according to the given
- * format pattern and timezone.
- * <p>
- * <p>For example:
- * <code>
- * def d = new Date(0)
- * def tz = TimeZone.getTimeZone('GMT')
- * println d.format('dd/MMM/yyyy', tz)
- * </code> would return the string
- * <code>"01/Jan/1970"</code>. See documentation for {@link java.text.SimpleDateFormat}
- * for format pattern use.
- * <p>
- * <p>Note that a new DateFormat instance is created for every
- * invocation of this method (for thread safety).
- *
- * @param self a Date
- * @param format the format pattern to use according to {@link java.text.SimpleDateFormat}
- * @param tz the TimeZone to use
- * @return a string representation of this date.
- * @see java.text.SimpleDateFormat
- * @since 1.8.3
- */
+ @Deprecated
public static String format(Date self, String format, TimeZone tz) {
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setTimeZone(tz);
return sdf.format(self);
}
- /**
- * <p>Return a string representation of the 'day' portion of this date
- * according to the locale-specific {@link java.text.DateFormat#SHORT} default format.
- * For an "en_UK" system locale, this would be <code>dd/MM/yy</code>.
- * <p>
- * <p>Note that a new DateFormat instance is created for every
- * invocation of this method (for thread safety).
- *
- * @param self a Date
- * @return a string representation of this date
- * @see java.text.DateFormat#getDateInstance(int)
- * @see java.text.DateFormat#SHORT
- * @since 1.5.7
- */
+ @Deprecated
public static String getDateString(Date self) {
return DateFormat.getDateInstance(DateFormat.SHORT).format(self);
}
- /**
- * <p>Return a string representation of the time portion of this date
- * according to the locale-specific {@link java.text.DateFormat#MEDIUM} default format.
- * For an "en_UK" system locale, this would be <code>HH:MM:ss</code>.
- * <p>
- * <p>Note that a new DateFormat instance is created for every
- * invocation of this method (for thread safety).
- *
- * @param self a Date
- * @return a string representing the time portion of this date
- * @see java.text.DateFormat#getTimeInstance(int)
- * @see java.text.DateFormat#MEDIUM
- * @since 1.5.7
- */
+ @Deprecated
public static String getTimeString(Date self) {
return DateFormat.getTimeInstance(DateFormat.MEDIUM).format(self);
}
- /**
- * <p>Return a string representation of the date and time time portion of
- * this Date instance, according to the locale-specific format used by
- * {@link java.text.DateFormat}. This method uses the {@link java.text.DateFormat#SHORT}
- * preset for the day portion and {@link java.text.DateFormat#MEDIUM} for the time
- * portion of the output string.
- * <p>
- * <p>Note that a new DateFormat instance is created for every
- * invocation of this method (for thread safety).
- *
- * @param self a Date
- * @return a string representation of this date and time
- * @see java.text.DateFormat#getDateTimeInstance(int, int)
- * @since 1.5.7
- */
+ @Deprecated
public static String getDateTimeString(Date self) {
return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM).format(self);
}
- /**
- * Common code for {@link #clearTime(java.util.Calendar)} and {@link #clearTime(java.util.Date)}
- * and {@link #clearTime(java.sql.Date)}
- *
- * @param self a Calendar to adjust
- */
+ @Deprecated
private static void clearTimeCommon(final Calendar self) {
self.set(Calendar.HOUR_OF_DAY, 0);
self.clear(Calendar.MINUTE);
@@ -639,14 +260,7 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
self.clear(Calendar.MILLISECOND);
}
- /**
- * Clears the time portion of this Date instance; useful utility where
- * it makes sense to compare month/day/year only portions of a Date.
- *
- * @param self a Date
- * @return the Date but with the time portion cleared
- * @since 1.6.7
- */
+ @Deprecated
public static Date clearTime(final Date self) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(self);
@@ -655,14 +269,7 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
return self;
}
- /**
- * Clears the time portion of this java.sql.Date instance; useful utility
- * where it makes sense to compare month/day/year only portions of a Date.
- *
- * @param self a java.sql.Date
- * @return the java.sql.Date but with the time portion cleared
- * @since 1.6.7
- */
+ @Deprecated
public static java.sql.Date clearTime(final java.sql.Date self) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(self);
@@ -671,56 +278,20 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
return self;
}
- /**
- * Clears the time portion of this Calendar instance; useful utility
- * where it makes sense to compare month/day/year only portions of a Calendar.
- *
- * @param self a Calendar
- * @return the Calendar but with the time portion cleared
- * @since 1.6.7
- */
+ @Deprecated
public static Calendar clearTime(final Calendar self) {
clearTimeCommon(self);
return self;
}
- /**
- * <p>Shortcut for {@link java.text.SimpleDateFormat} to output a String representation
- * of this calendar instance. This method respects the Calendar's assigned
- * {@link java.util.TimeZone}, whereas calling <code>cal.time.format('HH:mm:ss')</code>
- * would use the system timezone.
- * <p>Note that Calendar equivalents of <code>date.getDateString()</code>
- * and variants do not exist because those methods are Locale-dependent.
- * Although a Calendar may be assigned a {@link java.util.Locale}, that information is
- * lost and therefore cannot be used to control the default date/time formats
- * provided by these methods. Instead, the system Locale would always be
- * used. The alternative is to simply call
- * {@link java.text.DateFormat#getDateInstance(int, java.util.Locale)} and pass the same Locale
- * that was used for the Calendar.
- *
- * @param self this calendar
- * @param pattern format pattern
- * @return String representation of this calendar with the given format.
- * @see java.text.DateFormat#setTimeZone(java.util.TimeZone)
- * @see java.text.SimpleDateFormat#format(java.util.Date)
- * @see #format(java.util.Date, String)
- * @since 1.6.0
- */
+ @Deprecated
public static String format(Calendar self, String pattern) {
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
sdf.setTimeZone(self.getTimeZone());
return sdf.format(self.getTime());
}
- /**
- * Iterates from this date up to the given date, inclusive,
- * incrementing by one day each time.
- *
- * @param self a Date
- * @param to another Date to go up to
- * @param closure the closure to call
- * @since 2.2
- */
+ @Deprecated
public static void upto(Date self, Date to, Closure closure) {
if (self.compareTo(to) <= 0) {
for (Date i = (Date) self.clone(); i.compareTo(to) <= 0; i = next(i)) {
@@ -731,15 +302,7 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
") to upto() cannot be earlier than the value (" + self + ") it's called on.");
}
- /**
- * Iterates from the date represented by this calendar up to the date represented
- * by the given calendar, inclusive, incrementing by one day each time.
- *
- * @param self a Calendar
- * @param to another Calendar to go up to
- * @param closure the closure to call
- * @since 2.2
- */
+ @Deprecated
public static void upto(Calendar self, Calendar to, Closure closure) {
if (self.compareTo(to) <= 0) {
for (Calendar i = (Calendar) self.clone(); i.compareTo(to) <= 0; i = next(i)) {
@@ -750,15 +313,7 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
") to upto() cannot be earlier than the value (" + self + ") it's called on.");
}
- /**
- * Iterates from this date down to the given date, inclusive,
- * decrementing by one day each time.
- *
- * @param self a Date
- * @param to another Date to go down to
- * @param closure the closure to call
- * @since 2.2
- */
+ @Deprecated
public static void downto(Date self, Date to, Closure closure) {
if (self.compareTo(to) >= 0) {
for (Date i = (Date) self.clone(); i.compareTo(to) >= 0; i = previous(i)) {
@@ -769,15 +324,7 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
") to downto() cannot be later than the value (" + self + ") it's called on.");
}
- /**
- * Iterates from the date represented by this calendar up to the date represented
- * by the given calendar, inclusive, incrementing by one day each time.
- *
- * @param self a Calendar
- * @param to another Calendar to go down to
- * @param closure the closure to call
- * @since 2.2
- */
+ @Deprecated
public static void downto(Calendar self, Calendar to, Closure closure) {
if (self.compareTo(to) >= 0) {
for (Calendar i = (Calendar) self.clone(); i.compareTo(to) >= 0; i = previous(i)) {
@@ -787,347 +334,4 @@ public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
throw new GroovyRuntimeException("The argument (" + to +
") to downto() cannot be later than the value (" + self + ") it's called on.");
}
-
- /**
- * Returns the Time Zone offset of the Calendar as a {@link java.time.ZoneOffset}.
- *
- * @param self a Calendar
- * @return a ZoneOffset
- * @since 3.0
- */
- public static ZoneOffset getZoneOffset(final Calendar self) {
- int offsetMillis = self.get(Calendar.ZONE_OFFSET) + self.get(Calendar.DST_OFFSET);
- return ZoneOffset.ofTotalSeconds(offsetMillis / 1000);
- }
-
- /**
- * Returns the Time Zone offset of the Date as a {@link java.time.ZoneOffset},
- * which will typically be system's default offset.
- *
- * @param self a Date
- * @return a ZoneOffset
- * @since 3.0
- */
- public static ZoneOffset getZoneOffset(final Date self) {
- return getZoneOffset(toCalendar(self));
- }
-
- /**
- * Returns the Time Zone of the Calendar as a java.time.ZoneId.
- *
- * @param self a Calendar
- * @return a ZoneId
- * @since 3.0
- */
- public static ZoneId getZoneId(final Calendar self) {
- return self.getTimeZone().toZoneId();
- }
-
- /**
- * Returns the Time Zone of the Date as a {@link java.time.ZoneId}. This will
- * typically be the system's default ZoneId.
- *
- * @param self a Date
- * @return a ZoneId
- * @since 3.0
- */
- public static ZoneId getZoneId(final Date self) {
- return getZoneId(toCalendar(self));
- }
-
- /**
- * Converts the Calendar to a corresponding {@link java.time.Year}. If the Calendar has a different
- * time zone than the system default, the Year will be adjusted into the default time zone.
- *
- * @param self a Calendar
- * @return a Year
- * @since 3.0
- */
- public static Year toYear(final Calendar self) {
- return Year.of(self.get(Calendar.YEAR));
- }
-
- /**
- * Converts the Date to a corresponding {@link java.time.Year}.
- *
- * @param self a Date
- * @return a Year
- * @since 3.0
- */
- public static Year toYear(final Date self) {
- return toYear(toCalendar(self));
- }
-
- /**
- * Converts the Calendar to a corresponding {@link java.time.Month}. If the Calendar has a different
- * time zone than the system default, the Month will be adjusted into the default time zone.
- *
- * @param self a Calendar
- * @return a Month
- * @since 3.0
- */
- public static Month toMonth(final Calendar self) {
- return Month.of(self.get(Calendar.MONTH) + 1);
- }
-
- /**
- * Converts the Date to a corresponding {@link java.time.Month}.
- *
- * @param self a Date
- * @return a Month
- * @since 3.0
- */
- public static Month toMonth(final Date self) {
- return toMonth(toCalendar(self));
- }
-
- /**
- * Converts the Calendar to a corresponding {@link java.time.MonthDay}. If the Calendar has a different
- * time zone than the system default, the MonthDay will be adjusted into the default time zone.
- *
- * @param self a Calendar
- * @return a MonthDay
- * @since 3.0
- */
- public static MonthDay toMonthDay(final Calendar self) {
- return MonthDay.of(toMonth(self), self.get(Calendar.DAY_OF_MONTH));
- }
-
- /**
- * Converts the Date to a corresponding {@link java.time.MonthDay}.
- *
- * @param self a Date
- * @return a MonthDay
- * @since 3.0
- */
- public static MonthDay toMonthDay(final Date self) {
- return toMonthDay(toCalendar(self));
- }
-
- /**
- * Converts the Calendar to a corresponding {@link java.time.YearMonth}. If the Calendar has a different
- * time zone than the system default, the YearMonth will be adjusted into the default time zone.
- *
- * @param self a Calendar
- * @return a YearMonth
- * @since 3.0
- */
- public static YearMonth toYearMonth(final Calendar self) {
- return toYear(self).atMonth(toMonth(self));
- }
-
- /**
- * Converts the Date to a corresponding {@link java.time.YearMonth}.
- *
- * @param self a Date
- * @return a YearMonth
- * @since 3.0
- */
- public static YearMonth toYearMonth(final Date self) {
- return toYearMonth(toCalendar(self));
- }
-
- /**
- * Converts the Calendar to a corresponding {@link java.time.DayOfWeek}. If the Calendar has a different
- * time zone than the system default, the DayOfWeek will be adjusted into the default time zone.
- *
- *
- * @param self a Calendar
- * @return a DayOfWeek
- * @since 3.0
- */
- public static DayOfWeek toDayOfWeek(final Calendar self) {
- return DayOfWeek.of(self.get(Calendar.DAY_OF_WEEK)).minus(1);
- }
-
- /**
- * Converts the Date to a corresponding {@link java.time.DayOfWeek}.
- *
- * @param self a Date
- * @return a DayOfWeek
- * @since 3.0
- */
- public static DayOfWeek toDayOfWeek(final Date self) {
- return toDayOfWeek(toCalendar(self));
- }
-
- /**
- * Converts the Calendar to a corresponding {@link java.time.LocalDate}. If the Calendar has a different
- * time zone than the system default, the LocalDate will be adjusted into the default time zone.
- *
- * @param self a Calendar
- * @return a LocalDate
- * @since 3.0
- */
- static LocalDate toLocalDate(final Calendar self) {
- return LocalDate.of(self.get(Calendar.YEAR), toMonth(self), self.get(Calendar.DAY_OF_MONTH));
- }
-
- /**
- * Converts the Date to a corresponding {@link java.time.LocalDate}.
- *
- * @param self a Date
- * @return a LocalDate
- * @since 3.0
- */
- public static LocalDate toLocalDate(final Date self) {
- return toLocalDate(toCalendar(self));
- }
-
- /**
- * Converts the Calendar to a corresponding {@link java.time.LocalTime}. If the Calendar has a different
- * time zone than the system default, the LocalTime will be adjusted into the default time zone.
- *
- * @param self a Calendar
- * @return a LocalTime
- * @since 3.0
- */
- public static LocalTime toLocalTime(final Calendar self) {
- int hour = self.get(Calendar.HOUR_OF_DAY);
- int minute = self.get(Calendar.MINUTE);
- int second = self.get(Calendar.SECOND);
- int ns = self.get(Calendar.MILLISECOND) * 1_000_000;
- return LocalTime.of(hour, minute, second, ns);
- }
-
- /**
- * Converts the Date to a corresponding {@link java.time.LocalTime}.
- *
- * @param self a Date
- * @return a LocalTime
- * @since 3.0
- */
- public static LocalTime toLocalTime(final Date self) {
- return toLocalTime(toCalendar(self));
- }
-
- /**
- * Converts the Calendar to a corresponding {@link java.time.LocalDateTime}. If the Calendar has a different
- * time zone than the system default, the LocalDateTime will be adjusted into the default time zone.
- *
- * @param self a Calendar
- * @return a LocalDateTime
- * @since 3.0
- */
- public static LocalDateTime toLocalDateTime(final Calendar self) {
- return LocalDateTime.of(toLocalDate(self), toLocalTime(self));
- }
-
- /**
- * Converts the Date to a corresponding {@link java.time.LocalDateTime}.
- *
- * @param self a Date
- * @return a LocalDateTime
- * @since 3.0
- */
- public static LocalDateTime toLocalDateTime(final Date self) {
- return toLocalDateTime(toCalendar(self));
- }
-
- /**
- * <p>Converts the Calendar to a corresponding {@link java.time.ZonedDateTime}.</p><p>Note that
- * {@link java.util.GregorianCalendar} has a {@link java.util.GregorianCalendar#toZonedDateTime} method,
- * which is commonly the specific type of Calendar in use.</p>
- *
- * @param self a Calendar
- * @return a ZonedDateTime
- * @since 3.0
- */
- public static ZonedDateTime toZonedDateTime(final Calendar self) {
- if (self instanceof GregorianCalendar) { // would this branch ever be true?
- return ((GregorianCalendar) self).toZonedDateTime();
- } else {
- return ZonedDateTime.of(toLocalDateTime(self), getZoneId(self));
- }
- }
-
- /**
- * Converts the Date to a corresponding {@link java.time.ZonedDateTime}.
- *
- * @param self a Date
- * @return a ZonedDateTime
- * @since 3.0
- */
- public static ZonedDateTime toZonedDateTime(final Date self) {
- return toZonedDateTime(toCalendar(self));
- }
-
- /**
- * Converts the Calendar to a corresponding {@link java.time.OffsetDateTime}.
- *
- * @param self a Calendar
- * @return an OffsetDateTime
- * @since 3.0
- */
- public static OffsetDateTime toOffsetDateTime(final Calendar self) {
- return OffsetDateTime.of(toLocalDateTime(self), getZoneOffset(self));
- }
-
- /**
- * Converts the Date to a corresponding {@link java.time.OffsetDateTime}.
- *
- * @param self a Date
- * @return an OffsetDateTime
- * @since 3.0
- */
- public static OffsetDateTime toOffsetDateTime(final Date self) {
- return toOffsetDateTime(toCalendar(self));
- }
-
- /**
- * Converts the Calendar to a corresponding {@link java.time.OffsetTime}.
- *
- * @param self a Calendar
- * @return an OffsetTime
- * @since 3.0
- */
- public static OffsetTime toOffsetTime(final Calendar self) {
- return OffsetTime.of(toLocalTime(self), getZoneOffset(self));
- }
-
- /**
- * Converts the Date to a corresponding {@link java.time.OffsetTime}.
- *
- * @param self a Date
- * @return an OffsetTime
- * @since 3.0
- */
- public static OffsetTime toOffsetTime(final Date self) {
- return toOffsetTime(toCalendar(self));
- }
-
- /**
- * Convenience method for converting a Calendar to a corresponding {@link java.time.Instant}.
- *
- * @param self a Calendar
- * @return an Instant
- * @since 3.0
- */
- public static Instant toInstant(final Calendar self) {
- return self.getTime().toInstant();
- }
-
- /**
- * Converts the TimeZone to a corresponding {@link java.time.ZoneOffset}. The offset is determined
- * using the current date/time.
- *
- * @param self a TimeZone
- * @return a ZoneOffset
- * @since 3.0
- */
- public static ZoneOffset toZoneOffset(final TimeZone self) {
- return toZoneOffset(self, Instant.now());
- }
-
- /**
- * Converts this TimeZone to a corresponding {@link java.time.ZoneOffset}. The offset is determined
- * using the date/time of specified Instant.
- *
- * @param self a TimeZone
- * @return a ZoneOffset
- * @since 3.0
- */
- public static ZoneOffset toZoneOffset(final TimeZone self, Instant instant) {
- return self.toZoneId().getRules().getOffset(instant);
- }
}