All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.webtoolkit.jwt.WDate Maven / Gradle / Ivy

/*
 * Copyright (C) 2009 Emweb bvba, Leuven, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
package eu.webtoolkit.jwt;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * Class which holds a date on the gregorian calendar, specified as
 * day/month/year.
 * 
 * A valid date may be specified by year, month, and day of month (using the
 * {@link #WDate(int, int, int)} constructor, or the
 * {@link #setDate(int year, int month, int day)} method). When attempting to
 * specify an invalid date (with an impossible combination of year/month/date)
 * an {@link IllegalArgumentException} will be thrown.
 * 
 * The class provides a flexible way for converting between strings and dates.
 * Use toString() to convert to strings, and fromString() for parsing strings.
 * Both methods take a format string, and the same format syntax is supported by
 * both methods.
 * 
 * Simple operations are supported to compare dates, or to calculate with dates.
 */
public class WDate implements Comparable {
	static class RegExpInfo {
		public String regexp;
		public String yearGetJS;
		public String dayGetJS;
		public String monthGetJS;
	}

	enum Day {
		Sunday(Calendar.SUNDAY), Monday(Calendar.MONDAY), Tuesday(
				Calendar.TUESDAY), Wednesday(Calendar.WEDNESDAY), Thursday(
				Calendar.THURSDAY), Friday(Calendar.FRIDAY), Saturday(
				Calendar.SATURDAY);

		private int calendarCode;

		private Day(int calendarCode) {
			this.calendarCode = calendarCode;
		}
		
		// calendarCode: 0 (Sunday) to 6 (Saturday)
		static Day fromInt(int day) {
			return values()[day];
		}
	}

	private Date d;

	/**
	 * Set a date by year, month (1-12), day (1-31), hour (0-23), minute (0-59),
	 * second (0 - 59), millisecond (0 - 999)
	 * 
	 * When the date is invalid, an IllegalArgumentException is thrown.
	 * 
	 * @see #setDate(int year, int month, int day, int hour, int minute, int
	 *      second, int millisecond)
	 */
	public WDate(int year, int month, int day, int hour, int minute,
			int second, int millisecond) {
		d = new Date();
		setDate(year, month, day, hour, minute, second, millisecond);
	}

	/**
	 * Set a date by year, month (1-12), day (1-31), hour (0-23), minute (0-59),
	 * second (0 - 59)
	 * 
	 * When the date is invalid, an IllegalArgumentException is thrown.
	 * 
	 * @see #setDate(int year, int month, int day, int hour, int minute, int
	 *      second)
	 */
	public WDate(int year, int month, int day, int hour, int minute, int second) {
		this(year, month, day, hour, minute, second, 0);
	}

	/**
	 * Specify a date by year, month (1-12), and day (1-31)
	 * 
	 * When the date is invalid, an IllegalArgumentException is thrown.
	 * 
	 * @see #setDate(int year, int month, int day)
	 * @see #getYear()
	 * @see #getMonth()
	 * @see #getDay()
	 */
	public WDate(int year, int month, int day) {
		Calendar c = Calendar.getInstance();
		c.set(year, month - 1, day);

		if (c.get(Calendar.YEAR) != year || c.get(Calendar.MONTH) + 1 != month
				|| c.get(Calendar.DATE) != day) {
			throw new IllegalArgumentException("Illegal WDate");
		}

		d = c.getTime();
	}

	/**
	 * Specify a date by a Date object.
	 */
	public WDate(Date date) {
		d = date;
	}

	/**
	 * Set a date by year, month (1-12), day (1-31), hour (0-23), minute (0-59),
	 * second (0 - 59), millisecond (0 - 999)
	 * 
	 * When the new date is invalid, an IllegalArgumentException is thrown.
	 * 
	 * @see #WDate(int year, int month, int day, int hour, int minute, int
	 *      second, int millisecond)
	 * @see #getYear()
	 * @see #getMonth()
	 * @see #getDay()
	 * @see #getHour()
	 * @see #getMinute()
	 * @see #getSecond()
	 * @see #getMillisecond
	 */
	public void setDate(int year, int month, int day, int hour, int minute,
			int second, int millisecond) {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		c.set(year, month - 1, day, hour, minute, second);
		c.set(Calendar.MILLISECOND, millisecond);

		if (c.get(Calendar.YEAR) != year || c.get(Calendar.MONTH) + 1 != month
				|| c.get(Calendar.DATE) != day
				|| c.get(Calendar.HOUR_OF_DAY) != hour
				|| c.get(Calendar.MINUTE) != minute
				|| c.get(Calendar.SECOND) != second
				|| c.get(Calendar.MILLISECOND) != millisecond) {
			throw new IllegalArgumentException("Illegal WDate");
		}

		d = c.getTime();
	}

	/**
	 * Set a date by year, month (1-12), day (1-31)
	 * 
	 * When the new date is invalid, an IllegalArgumentException is thrown.
	 * 
	 * @see #setDate(int, int, int, int, int, int)
	 */
	public void setDate(int year, int month, int day) {
		this.setDate(year, month, day, 0, 0, 0);
	}

	/**
	 * Set a date by year, month (1-12), and day (1-31), hour (0-23), minute
	 * (0-59), second (0 - 59).
	 * 
	 * When the new date is invalid, an IllegalArgumentException is thrown.
	 * 
	 * @see #setDate(int, int, int, int, int, int, int)
	 */
	public void setDate(int year, int month, int day, int hour, int minute,
			int second) {
		this.setDate(year, month, day, hour, minute, second, 0);
	}

	/**
	 * Adds seconds.
	 * 
	 * Returns a time that is  nSeconds  seconds later than this time.
	 * Negative values for  nSeconds  will result in a time that is as
	 * many seconds earlier.
	 */
	public WDate addSeconds(int nSeconds) {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		c.add(Calendar.SECOND, nSeconds);
		return new WDate(c.getTime());
	}

	/**
	 * Adds milliseconds.
	 * 
	 * Returns a time that is  nMilliseconds  milliseconds later than
	 * this time. Negative values for  nMilliseconds  will result in a
	 * time that is as many seconds earlier.
	 */
	public WDate addMilliseconds(int nMilliseconds) {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		c.add(Calendar.MILLISECOND, nMilliseconds);
		return new WDate(c.getTime());
	}

	/**
	 * Add days to a date.
	 * 
	 * Returns a date that is ndays later than this date. Negative values
	 * for ndays will result in a date that is as many days earlier.
	 * 
	 * @see #addMonths(int)
	 * @see #addYears(int)
	 */
	public WDate addDays(int ndays) {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		c.add(Calendar.DATE, ndays);
		return new WDate(c.getTime());
	}

	/**
	 * Add months to a date.
	 * 
	 * Returns a date that is the same day of the month, but nmonths
	 * later than this date. Negative values for nmonths will result in a
	 * date that is as many months earlier.
	 * 
	 * @see #addDays(int)
	 * @see #addYears(int)
	 */
	public WDate addMonths(int nmonths) {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		c.add(Calendar.MONTH, nmonths);
		return new WDate(c.getTime());
	}

	/**
	 * Add years to a date.
	 * 
	 * Returns a date that is nyears later than this date. Negative
	 * values for nyears will result in a date that is as many years
	 * earlier.
	 * 
	 * @see #addDays(int)
	 * @see #addMonths(int)
	 */
	public WDate addYears(int nyears) {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		c.add(Calendar.YEAR, nyears);
		return new WDate(c.getTime());
	}

	/**
	 * Year
	 */
	public int getYear() {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		return c.get(Calendar.YEAR);
	}

	/**
	 * Month (1-12)
	 */
	public int getMonth() {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		return c.get(Calendar.MONTH) + 1;
	}

	/**
	 * Day of month (1-31)
	 */
	public int getDay() {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		return c.get(Calendar.DATE);
	}

	/**
	 * Hour (0-24)
	 */
	public int getHour() {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		return c.get(Calendar.HOUR_OF_DAY);
	}

	/**
	 * Minute (0-59)
	 */
	public int getMinute() {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		return c.get(Calendar.MINUTE);
	}

	/**
	 * Second (0-59)
	 */
	public int getSecond() {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		return c.get(Calendar.SECOND);
	}

	/**
	 * Millisecond (0-999)
	 */
	public int getMillisecond() {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		return c.get(Calendar.MILLISECOND);
	}

	/**
	 * Returns the difference between to time values (in seconds).
	 * 
	 * This returns a value between -86400 s and 86400 s.
	 */
	public int getSecondsTo(WDate d) {
		return (int) (getMillisecondsTo(d) / 1000);
	}

	/**
	 * Returns the difference between to time values (in milliseconds).
	 * 
	 * This returns a value between -86400000 ms and 86400000 ms.
	 */
	public int getMillisecondsTo(WDate d) {
		return (int) (d.d.getTime() - this.d.getTime());
	}

	/**
	 * Day of week (1-7)
	 */
	public int getDayOfWeek() {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		return c.get(Calendar.DAY_OF_WEEK);
	}

	/**
	 * Returns the number of days from this date to date.
	 */
	public int getDaysTo(WDate date) {
		return (int) ((date.d.getTime() - d.getTime()) / 1000 / 3600 / 24);
	}

	/**
	 * Returns the difference between two WDate values (as text).
	 * 
	 * This returns a textual representation of the approximate difference
	 * between this time and  other . The textual representation returns
	 * the difference as a number of seconds, minutes, hours, days, weeks,
	 * months, or years, using the coarsest unit that is more than \p minValue.
	 * 
	 * @see #getDaysTo(WDate)
	 * @see #getSecondsTo(WDate)
	 */
	public String getTimeTo(WDate other, int minValue) {
		int secs = getSecondsTo(other);

		if (Math.abs(secs) < 1)
			return "less than a second";
		else if (Math.abs(secs) < 60 * minValue)
			return String.valueOf(secs) + " second" + multiple(secs, "s");
		else {
			int minutes = secs / 60;
			if (Math.abs(minutes) < 60 * minValue)
				return String.valueOf(minutes) + " minute"
						+ multiple(minutes, "s");
			else {
				int hours = minutes / 60;
				if (Math.abs(hours) < 24 * minValue)
					return String.valueOf(hours) + " hour"
							+ multiple(hours, "s");
				else {
					int days = hours / 24;
					if (Math.abs(days) < 7 * minValue)
						return String.valueOf(days) + " day"
								+ multiple(days, "s");
					else {
						if (Math.abs(days) < 31 * minValue) {
							int weeks = days / 7;
							return String.valueOf(weeks) + " week"
									+ multiple(weeks, "s");
						} else {
							if (Math.abs(days) < 365 * minValue) {
								int months = days / 30;
								return String.valueOf(months) + " month"
										+ multiple(months, "s");
							} else {
								int years = days / 365;
								return String.valueOf(years) + " year"
										+ multiple(years, "s");
							}
						}
					}
				}
			}
		}
	}

	private String multiple(int secs, String s) {
		if (Math.abs(secs) == 1)
			return "";
		else
			return s;
	}

	/**
	 * Tests if this date is after the specified date.
	 * 
	 * @param when
	 *            - a date.
	 * @return true if and only if the instant represented by this Date object
	 *         is strictly earlier than the instant represented by when; false
	 *         otherwise.
	 */
	public boolean before(WDate when) {
		return d.before(when.d);
	}

	/**
	 * Tests if this date is after the specified date.
	 * 
	 * @param when
	 *            - a date.
	 * @return true if and only if the instant represented by this Date object
	 *         is strictly later than the instant represented by when; false
	 *         otherwise.
	 */
	public boolean after(WDate when) {
		return d.after(when.d);
	}

	/**
	 * Compares two dates for equality. The result is true if and only if the
	 * argument is not null and is a Date object that represents the same point
	 * in time, to the millisecond, as this object. Thus, two Date objects are
	 * equal if and only if the getTime method returns the same long value for
	 * both.
	 */
	public boolean equals(Object other) {
		if (other instanceof WDate) {
			WDate d2 = (WDate) other;
			return this.d.equals(d2.d);
		} else
			return false;
	}

	/**
	 * Returns the default date format.
	 */
	public static String getDefaultFormat() {
		return "ddd MMM d HH:mm:ss yyyy";
	}

	/**
	 * Construct a date for the current client date.
	 * 
	 * This method uses browser information to retrieve the date that is
	 * configured in the client.
	 */
	public static WDate getCurrentDate() {
		// TODO
		return new WDate(new Date());
	}

	/**
	 * Construct a date for the current server date.
	 * 
	 * This method returns the date as indicated by the system clock of the
	 * server.
	 */
	public static WDate getCurrentServerDate() {
		return getCurrentDate();
	}

	static boolean isLeapYear(int year) {
		GregorianCalendar c = new GregorianCalendar();
		return c.isLeapYear(year);
	}

	/**
	 * Returns the short day name.
	 * 
	 * Results (for given weekDay) are (default English):
* "Mon" (1),
* "Tue" (2),
* "Wed" (3),
* "Thu" (4),
* "Fri" (5),
* "Sat" (6),
* "Sun" (7). * * The result is affected by localization using the "Wt.WDate.Mon" to * "Wt.WDate.Sun" keys. * * @see #getLongDayName(int) */ public static String getShortDayName(int weekday) { final String[] shortDayNames = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; if (WApplication.getInstance() != null) return WString.tr("Wt.WDate.3." + shortDayNames[weekday - 1]).getValue(); else return shortDayNames[weekday - 1]; } /** * Returns the short month name. * * Results (for given month) are (default English):
* "Jan" (1),
* "Feb" (2),
* "Mar" (3),
* "Apr" (4),
* "May" (5),
* "Jun" (6),
* "Jul" (7),
* "Aug" (8),
* "Sep" (9),
* "Oct" (10),
* "Nov" (11),
* "Dec" (12). * * The result is affected by localization using the "Wt.WDate.Jan" to * "Wt.WDate.Dec" keys. * * @see #getLongMonthName(int) */ public static String getShortMonthName(int month) { final String[] shortMonthNames = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; if (WApplication.getInstance() != null) return WString.tr("Wt.WDate." + shortMonthNames[month - 1]).getValue(); else return shortMonthNames[month - 1]; } /** * Returns the long day name. * * Results (for given weekDay) are (default English):
* "Monday" (1),
* "Tuesday" (2),
* "Wednesday" (3),
* "Thursday" (4),
* "Friday" (5),
* "Saturday" (6),
* "Sunday" (7). * * The result is affected by localization using the "Wt.WDate.Monday" to * "Wt.WDate.Sunday" keys. * * @see #getShortDayName(int) */ public static String getLongDayName(int weekday) { final String[] longDayNames = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" }; if (WApplication.getInstance() != null) return WString.tr("Wt.WDate." + longDayNames[weekday - 1]).getValue(); else return longDayNames[weekday - 1]; } /** * Returns the long month name. * * Results (for given month) are (default English):
* "January" (1),
* "February" (2),
* "March" (3),
* "April" (4),
* "May" (5),
* "June" (6),
* "July" (7),
* "August" (8),
* "September" (9),
* "October" (10),
* "November" (11),
* "December" (12). * * The result is affected by localization using the "Wt.WDate.January" to * "Wt.WDate.December" keys. * * @see #getShortDayName(int) */ public static String getLongMonthName(int month) { final String[] longMonthNames = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; if (WApplication.getInstance() != null) return WString.tr("Wt.WDate." + longMonthNames[month - 1]).getValue(); else return longMonthNames[month - 1]; } /** * Parse a WString to a date using a default format. * * The default format is "ddd MMM d yyyy". For example, a date * specified as: * "Wed Aug 29 2007" * will be parsed as a date that equals a date * constructed as: * WDate d = new WDate(2007,8,29); * * * When the date could not be parsed or is not valid, null is returned. * * @see #fromString(String, String) */ public static WDate fromString(String text) { return fromString(text, getDefaultFormat()); } /** * Parse a String to a date using a specified format. * * The format follows the same syntax as used by * {@link #toString(String format)}. * * When the date could not be parsed or is not valid, null is returned. * * @see #toString(String format) */ public static WDate fromString(String text, String format) { SimpleDateFormat formatter = new SimpleDateFormat(format); try { formatter.setLenient(false); Date d = formatter.parse(text); if (d != null && formatter.format(d).equals(text)) return new WDate(d); } catch (ParseException e) { } return null; } /** * Converts the date to a Julian day. * * @see #fromJulianDay(int) */ public int toJulianDay() { int year = getYear(); int month = getMonth(); int day = getDay(); int y = year; if (year < 0) { y++; } int m = month; if (month > 2) { m++; } else { y--; m += 13; } int julian = (int) (java.lang.Math.floor(365.25 * y) + java.lang.Math.floor(30.6001 * m) + day + 1720995.0); int yearZero = 15 + 31 * (10 + 12 * 1582); if (day + 31 * (month + 12 * year) >= yearZero) { int jadj = (int) (0.01 * y); julian += 2 - jadj + (int) (0.25 * jadj); } return julian; } /** * Format this date to a String using a default format. * * The default format is "ddd MMM d yyyy". * * @see #toString(String format) * @see #fromString(String) */ @Override public String toString() { return toString(getDefaultFormat()); } /** * Format this date to a WString using a specified format. * * The format is a string interpreted by {@link SimpleDateFormat}. */ public String toString(String format) { SimpleDateFormat formatter = new SimpleDateFormat(format); return formatter.format(this.d); } static WDate getPreviousWeekday(WDate d, Day gw) { Calendar c = Calendar.getInstance(); c.setTime(d.d); // FIXME we shouldn't need a loop here! while (true) { c.add(Calendar.DATE, -1); if (c.get(Calendar.DAY_OF_WEEK) == gw.calendarCode) break; } return new WDate(c.getTime()); } static WDate.RegExpInfo formatToRegExp(String f) { WDate.RegExpInfo result = new WDate.RegExpInfo(); int currentGroup = 1; result.regexp = ""; result.dayGetJS = "1"; result.monthGetJS = "1"; result.yearGetJS = "2000"; boolean inQuote = false; boolean gotQuoteInQuote = false; int d = 0, M = 0, y = 0; for (int i = 0; i < f.length(); ++i) { if (inQuote) if (f.charAt(i) != '\'') if (gotQuoteInQuote) { gotQuoteInQuote = false; inQuote = false; } else result.regexp += f.charAt(i); else if (gotQuoteInQuote) { gotQuoteInQuote = false; result.regexp += f.charAt(i); } else gotQuoteInQuote = true; if (!inQuote) { switch (f.charAt(i)) { case 'd': if (d == 0) { currentGroup = writeRegExpLast(result, d, M, y, f, currentGroup); d = M = y = 0; } ++d; break; case 'M': if (M == 0) { currentGroup = writeRegExpLast(result, d, M, y, f, currentGroup); d = M = y = 0; } ++M; break; case 'y': if (y == 0) { currentGroup = writeRegExpLast(result, d, M, y, f, currentGroup); d = M = y = 0; } ++y; break; default: currentGroup = writeRegExpLast(result, d, M, y, f, currentGroup); d = M = y = 0; if (f.charAt(i) == '\'') { inQuote = true; gotQuoteInQuote = false; } else if ("/[\\^$.|?*+()".indexOf(f.charAt(i)) != -1) result.regexp += "\\" + f.charAt(i); else result.regexp += f.charAt(i); } } } currentGroup = writeRegExpLast(result, d, M, y, f, currentGroup); return result; } private static int writeRegExpLast(RegExpInfo result, int d, int M, int y, String format, int currentGroup) { if (d != 0) { switch (d) { case 1: case 2: if (d == 1) result.regexp += "(\\d{1,2})"; else result.regexp += "(\\d{2})"; result.dayGetJS = "return parseInt(results[" + String.valueOf(currentGroup++) + "], 10)"; break; default: fatalFormatRegExpError(format, d, "d's"); } } if (M != 0) { switch (M) { case 1: case 2: if (M == 1) result.regexp += "(\\d{1,2})"; else result.regexp += "(\\d{2})"; result.monthGetJS = "return parseInt(results[" + String.valueOf(currentGroup++) + "], 10)"; break; default: fatalFormatRegExpError(format, M, "M's"); } M = 0; } if (y != 0) { switch (y) { case 2: result.regexp += "(\\d{2})"; result.yearGetJS = "var y=parseInt(results[" + String.valueOf(currentGroup++) + "], 10);return y>38?1900+y:2000+y;"; break; case 4: result.regexp += "(\\d{4})"; result.yearGetJS = "return parseInt(results[" + String.valueOf(currentGroup++) + "], 10)"; break; default: fatalFormatRegExpError(format, y, "y's"); } } return currentGroup; } /** * Converts a Julian Day jd to a WDate. * * @see #toJulianDay() */ public static WDate fromJulianDay(int jd) { int julian = jd; int day, month, year; if (julian < 0) { julian = 0; } int a = julian; if (julian >= 2299161) { int jadj = (int) (((float) (julian - 1867216) - 0.25) / 36524.25); a += 1 + jadj - (int) (0.25 * jadj); } int b = a + 1524; int c = (int) (6680.0 + ((float) (b - 2439870) - 122.1) / 365.25); int d = (int) (365 * c + (0.25 * c)); int e = (int) ((b - d) / 30.6001); day = b - d - (int) (30.6001 * e); month = e - 1; if (month > 12) { month -= 12; } year = c - 4715; if (month > 2) { --year; } if (year <= 0) { --year; } return new WDate(year, month, day); } private static void fatalFormatRegExpError(String format, int c, String cs) { StringBuilder s = new StringBuilder(); s.append("WDate to regexp: (for \"").append(format).append( "\": cannot handle ").append(c).append(" consecutive ").append( cs); throw new RuntimeException(s.toString()); } /** * Returns the internal Date object. */ public Date getDate() { return d; } /** * Returns a hash code value for the object. */ public int hashCode() { return d.hashCode(); } /** * Compares this WDate object with the specified WDate object for order. */ public int compareTo(WDate o) { if (o == null) return 1; return d.compareTo(o.d); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy