Killing the lang sandbox component
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@263948 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/pending/CalendarUtils.java b/src/pending/CalendarUtils.java
new file mode 100644
index 0000000..180a4be
--- /dev/null
+++ b/src/pending/CalendarUtils.java
@@ -0,0 +1,467 @@
+// package org.apache.commons.lang;
+
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+
+import java.text.*;
+import java.util.*;
+
+/**
+ * A suite of utilities surrounding the use of the Calendar and Date object.
+ *
+ * @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
+ */
+public class CalendarUtils {
+
+ /**
+ * This is half a month, so this represents whether a date is in the top
+ * or bottom half of the month.
+ */
+ public final static int SEMI_MONTH = 1001;
+
+ private static final int[][] fields = {
+ {Calendar.MILLISECOND},
+ {Calendar.SECOND},
+ {Calendar.MINUTE},
+ {Calendar.HOUR_OF_DAY, Calendar.HOUR},
+ {Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM /* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */},
+ {Calendar.MONTH, CalendarUtils.SEMI_MONTH},
+ {Calendar.YEAR},
+ {Calendar.ERA}};
+
+ private static DateFormat[] dateFormats = {
+ //3/31/92 10:00:07 PST
+ new SimpleDateFormat("M/dd/yy h:mm:ss z"),
+ //January 23, 1987 10:05pm
+ new SimpleDateFormat("MMM d, yyyy h:mm a"),
+ //22:00 GMT
+ new SimpleDateFormat("h:mm z")};
+
+ /**
+ * A week range, starting on Sunday.
+ */
+ public final static int RANGE_WEEK_SUNDAY = 1;
+
+ /**
+ * A week range, starting on Monday.
+ */
+ public final static int RANGE_WEEK_MONDAY = 2;
+
+ /**
+ * A week range, starting on the day focused.
+ */
+ public final static int RANGE_WEEK_RELATIVE = 3;
+
+ /**
+ * A week range, centered around the day focused.
+ */
+ public final static int RANGE_WEEK_CENTER = 4;
+
+ /**
+ * A month range, the week starting on Sunday.
+ */
+ public final static int RANGE_MONTH_SUNDAY = 5;
+
+ /**
+ * A month range, the week starting on Monday.
+ */
+ public final static int RANGE_MONTH_MONDAY = 6;
+
+ /**
+ * See the other round method. Works with a Date object.
+ */
+ public static Date round(Date val, int field) {
+ GregorianCalendar gval = new GregorianCalendar();
+ gval.setTime(val);
+ modify(gval, field, true);
+ return gval.getTime();
+ }
+
+ /**
+ * Round this date, leaving the field specified as the most significant
+ * field. For example, if you had the datetime of 28 Mar 2002
+ * 13:45:01.231, if this was passed with HOUR, it would return 28 Mar
+ * 2002 14:00:00.000. If this was passed with MONTH, it would return
+ * 1 April 2002 0:00:00.000.
+ */
+ public static Calendar round(Calendar val, int field) {
+ Calendar rounded = (Calendar) val.clone();
+ modify(rounded, field, true);
+ return rounded;
+ }
+
+ /**
+ * See the other round method. Works with an Object, trying to
+ * use it as either a Date or Calendar.
+ */
+ public static Date round(Object val, int field) {
+ if (val instanceof Date) {
+ return round((Date) val, field);
+ } else if (val instanceof Calendar) {
+ return round((Calendar) val, field).getTime();
+ } else {
+ throw new ClassCastException("Could not round " + val);
+ }
+ }
+
+ /**
+ * See the other trunc method. Works with a Date.
+ */
+ public static Date trunc(Date val, int field) {
+ GregorianCalendar gval = new GregorianCalendar();
+ gval.setTime(val);
+ modify(gval, field, false);
+ return gval.getTime();
+ }
+
+ /**
+ * Truncate this date, leaving the field specified as the most significant
+ * field. For example, if you had the datetime of 28 Mar 2002
+ * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
+ * 2002 13:00:00.000. If this was passed with MONTH, it would return
+ * 1 Mar 2002 0:00:00.000.
+ */
+ public static Calendar trunc(Calendar val, int field) {
+ Calendar truncated = (Calendar) val.clone();
+ modify(truncated, field, false);
+ return truncated;
+ }
+
+ /**
+ * See the other trunc method. Works with an Object, trying to
+ * use it as either a Date or Calendar.
+ */
+ public static Date trunc(Object val, int field) {
+ if (val instanceof Date) {
+ return trunc((Date) val, field);
+ } else if (val instanceof Calendar) {
+ return trunc((Calendar) val, field).getTime();
+ } else {
+ throw new ClassCastException("Could not trunc " + val);
+ }
+ }
+
+ private static void modify(Calendar val, int field, boolean round) {
+ boolean roundUp = false;
+ for (int i = 0; i < fields.length; i++) {
+ for (int j = 0; j < fields[i].length; j++) {
+ if (fields[i][j] == field) {
+ //This is our field... we stop looping
+ if (round && roundUp) {
+ if (field == CalendarUtils.SEMI_MONTH) {
+ //This is a special case that's hard to generalize
+ //If the date is 1, we round up to 16, otherwise
+ // we subtract 15 days and add 1 month
+ if (val.get(Calendar.DATE) == 1) {
+ val.add(Calendar.DATE, 15);
+ } else {
+ val.add(Calendar.DATE, -15);
+ val.add(Calendar.MONTH, 1);
+ }
+ } else {
+ //We need at add one to this field since the
+ // last number causes us to round up
+ val.add(fields[i][0], 1);
+ }
+ }
+ return;
+ }
+ }
+ //We have various fields that are not easy roundings
+ int offset = 0;
+ boolean offsetSet = false;
+ //These are special types of fields that require different rounding rules
+ switch (field) {
+ case CalendarUtils.SEMI_MONTH:
+ if (fields[i][0] == Calendar.DATE) {
+ //If we're going to drop the DATE field's value,
+ // we want to do this our own way.
+ //We need to subtrace 1 since the date has a minimum of 1
+ offset = val.get(Calendar.DATE) - 1;
+ //If we're above 15 days adjustment, that means we're in the
+ // bottom half of the month and should stay accordingly.
+ if (offset >= 15) {
+ offset -= 15;
+ }
+ //Record whether we're in the top or bottom half of that range
+ roundUp = offset > 7;
+ offsetSet = true;
+ }
+ break;
+ case Calendar.AM_PM:
+ if (fields[i][0] == Calendar.HOUR) {
+ //If we're going to drop the HOUR field's value,
+ // we want to do this our own way.
+ offset = val.get(Calendar.HOUR);
+ if (offset >= 12) {
+ offset -= 12;
+ }
+ roundUp = offset > 6;
+ offsetSet = true;
+ }
+ break;
+ }
+ if (!offsetSet) {
+ int min = val.getActualMinimum(fields[i][0]);
+ int max = val.getActualMaximum(fields[i][0]);
+ //Calculate the offset from the minimum allowed value
+ offset = val.get(fields[i][0]) - min;
+ //Set roundUp if this is more than half way between the minimum and maximum
+ roundUp = offset > ((max - min) / 2);
+ }
+ //We need to remove this field
+ val.add(fields[i][0], -offset);
+ }
+ throw new RuntimeException("We do not support that field.");
+
+ }
+
+ /**
+ * Parses strings the way that CVS supports it... very human readable
+ */
+ public static Calendar parse(String original) {
+ return parse(original, Locale.getDefault());
+ }
+
+ /**
+ * Parses strings the way that CVS supports it... very human readable
+ */
+ public static Calendar parse(String original, Locale locale) {
+ //Get the symbol names
+ DateFormatSymbols symbols = new DateFormatSymbols(locale);
+
+ //Prep the string to parse
+ String value = original.toLowerCase().trim();
+
+ //Get the current date/time
+ Calendar now = Calendar.getInstance();
+ if (value.endsWith(" ago")) {
+ //If this was a date that was "ago" the current time...
+ //Strip out the ' ago' part
+ value = value.substring(0, value.length() - 4);
+
+ //Split the value and unit
+ int start = value.indexOf(" ");
+ if (start < 0) {
+ throw new RuntimeException("Could not find space in between value and unit");
+ }
+ String unit = value.substring(start + 1);
+ value = value.substring(0, start);
+ //We support "a week", so we need to parse the value as "a"
+ int val = 0;
+ if (value.equals("a") || value.equals("an")) {
+ val = 1;
+ } else {
+ val = Integer.parseInt(value);
+ }
+
+ //Determine the unit
+ if (unit.equals("milliseconds") || unit.equals("millisecond")) {
+ now.add(Calendar.MILLISECOND, -val);
+ } else if (unit.equals("seconds") || unit.equals("second")) {
+ now.add(Calendar.SECOND, -val);
+ } else if (unit.equals("minutes") || unit.equals("minute")) {
+ now.add(Calendar.MINUTE, -val);
+ } else if (unit.equals("hours") || unit.equals("hour")) {
+ now.add(Calendar.HOUR, -val);
+ } else if (unit.equals("days") || unit.equals("day")) {
+ now.add(Calendar.DATE, -val);
+ } else if (unit.equals("weeks") || unit.equals("week")) {
+ now.add(Calendar.DATE, -val * 7);
+ } else if (unit.equals("fortnights") || unit.equals("fortnight")) {
+ now.add(Calendar.DATE, -val * 14);
+ } else if (unit.equals("months") || unit.equals("month")) {
+ now.add(Calendar.MONTH, -val);
+ } else if (unit.equals("years") || unit.equals("year")) {
+ now.add(Calendar.YEAR, -val);
+ } else {
+ throw new RuntimeException("We do not understand that many units ago");
+ }
+ return now;
+ } else if (value.startsWith("last ")) {
+ //If this was the last time a certain field was met
+ //Strip out the 'last ' part
+ value = value.substring(5);
+ //Get the current date/time
+ String[] strings = symbols.getWeekdays();
+ for (int i = 0; i < strings.length; i++) {
+ if (value.equalsIgnoreCase(strings[i])) {
+ //How many days after Sunday
+ int daysAgo = now.get(Calendar.DAY_OF_WEEK) - i;
+ if (daysAgo <= 0) {
+ daysAgo += 7;
+ }
+ now.add(Calendar.DATE, -daysAgo);
+ return now;
+ }
+ }
+ strings = symbols.getMonths();
+ for (int i = 0; i < strings.length; i++) {
+ if (value.equalsIgnoreCase(strings[i])) {
+ //How many days after January
+ int monthsAgo = now.get(Calendar.MONTH) - i;
+ if (monthsAgo <= 0) {
+ monthsAgo += 12;
+ }
+ now.add(Calendar.MONTH, -monthsAgo);
+ return now;
+ }
+ }
+ if (value.equals("week")) {
+ now.add(Calendar.DATE, -7);
+ return now;
+ }
+ } else if (value.equals("yesterday")) {
+ now.add(Calendar.DATE, -1);
+ return now;
+ } else if (value.equals("tomorrow")) {
+ now.add(Calendar.DATE, 1);
+ return now;
+ }
+ //Try to parse the date a number of different ways
+ for (int i = 0; i < dateFormats.length; i++) {
+ try {
+ Date datetime = dateFormats[i].parse(original);
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(datetime);
+ return cal;
+ } catch (ParseException pe) {
+ //we ignore this and just keep trying
+ }
+ }
+
+ throw new RuntimeException("Unable to parse '" + original + "'.");
+ }
+
+ /**
+ * This constructs an Iterator that will start and stop over a date
+ * range based on the focused date and the range style. For instance,
+ * passing Thursday, July 4, 2002 and a RANGE_MONTH_SUNDAY will return
+ * an Iterator that starts with Sunday, June 30, 2002 and ends with
+ * Saturday, August 3, 2002.
+ */
+ public static Iterator getCalendarIterator(Calendar focus, int rangeStyle) {
+ Calendar start = null;
+ Calendar end = null;
+ int startCutoff = Calendar.SUNDAY;
+ int endCutoff = Calendar.SATURDAY;
+ switch (rangeStyle) {
+ case RANGE_MONTH_SUNDAY:
+ case RANGE_MONTH_MONDAY:
+ //Set start to the first of the month
+ start = trunc(focus, Calendar.MONTH);
+ //Set end to the last of the month
+ end = (Calendar) start.clone();
+ end.add(Calendar.MONTH, 1);
+ end.add(Calendar.DATE, -1);
+ //Loop start back to the previous sunday or monday
+ if (rangeStyle == RANGE_MONTH_MONDAY) {
+ startCutoff = Calendar.MONDAY;
+ endCutoff = Calendar.SUNDAY;
+ }
+ break;
+ case RANGE_WEEK_SUNDAY:
+ case RANGE_WEEK_MONDAY:
+ case RANGE_WEEK_RELATIVE:
+ case RANGE_WEEK_CENTER:
+ //Set start and end to the current date
+ start = trunc(focus, Calendar.DATE);
+ end = trunc(focus, Calendar.DATE);
+ switch (rangeStyle) {
+ case RANGE_WEEK_SUNDAY:
+ //already set by default
+ break;
+ case RANGE_WEEK_MONDAY:
+ startCutoff = Calendar.MONDAY;
+ endCutoff = Calendar.SUNDAY;
+ break;
+ case RANGE_WEEK_RELATIVE:
+ startCutoff = focus.get(Calendar.DAY_OF_WEEK);
+ endCutoff = startCutoff - 1;
+ break;
+ case RANGE_WEEK_CENTER:
+ startCutoff = focus.get(Calendar.DAY_OF_WEEK) - 3;
+ endCutoff = focus.get(Calendar.DAY_OF_WEEK) + 3;
+ break;
+ }
+ break;
+ default:
+ throw new RuntimeException("The range style " + rangeStyle + " is not valid.");
+ }
+ if (startCutoff < Calendar.SUNDAY) {
+ startCutoff += 7;
+ }
+ if (endCutoff > Calendar.SATURDAY) {
+ endCutoff -= 7;
+ }
+ while (start.get(Calendar.DAY_OF_WEEK) != startCutoff) {
+ start.add(Calendar.DATE, -1);
+ }
+ while (end.get(Calendar.DAY_OF_WEEK) != endCutoff) {
+ end.add(Calendar.DATE, 1);
+ }
+ final Calendar startFinal = start;
+ final Calendar endFinal = end;
+ Iterator it = new Iterator() {
+ Calendar spot = null;
+ {
+ spot = startFinal;
+ spot.add(Calendar.DATE, -1);
+ }
+
+ public boolean hasNext() {
+ return spot.before(endFinal);
+ }
+
+ public Object next() {
+ if (spot.equals(endFinal)) {
+ throw new NoSuchElementException();
+ }
+ spot.add(Calendar.DATE, 1);
+ return spot.clone();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ return it;
+ }
+
+ /**
+ * See the other getCalendarIterator. Works with a Date.
+ */
+ public static Iterator getCalendarIterator(Date focus, int rangeStyle) {
+ GregorianCalendar gval = new GregorianCalendar();
+ gval.setTime(focus);
+ return getCalendarIterator(gval, rangeStyle);
+ }
+
+ /**
+ * See the other getCalendarIterator. Works with an Object, trying
+ * to use it as a Date or Calendar.
+ */
+ public static Iterator getCalendarIterator(Object focus, int rangeStyle) {
+ if (focus instanceof Date) {
+ return getCalendarIterator((Date) focus, rangeStyle);
+ } else if (focus instanceof Calendar) {
+ return getCalendarIterator((Calendar) focus, rangeStyle);
+ } else {
+ throw new ClassCastException("Could not iterate based on " + focus);
+ }
+ }
+
+}