com.caucho.util.QDate Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of resin-kernel Show documentation
Show all versions of resin-kernel Show documentation
Kernel for Resin Java Application Server
The newest version!
/*
* Copyright (c) 1998-2012 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.util;
import com.caucho.vfs.WriteStream;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Resin Date object
*/
public class QDate {
private static final Logger log
= Logger.getLogger(QDate.class.getName());
static final public int YEAR = 0;
static final public int MONTH = YEAR + 1;
static final public int DAY_OF_MONTH = MONTH + 1;
static final public int DAY = DAY_OF_MONTH + 1;
static final public int DAY_OF_WEEK = DAY + 1;
static final public int HOUR = DAY_OF_WEEK + 1;
static final public int MINUTE = HOUR + 1;
static final public int SECOND = MINUTE + 1;
static final public int MILLISECOND = SECOND + 1;
static final public int TIME = MILLISECOND + 1;
static final public int TIME_ZONE = TIME + 1;
static final long MS_PER_DAY = 24 * 60 * 60 * 1000L;
static final long MS_PER_EON = MS_PER_DAY * (365 * 400 + 100 - 3);
static final int []DAYS_IN_MONTH = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
static final String []DAY_NAMES = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static final String []MONTH_NAMES = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
private static final String []SHORT_WEEKDAY = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
private static final String []LONG_WEEKDAY = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
};
private static final String []SHORT_MONTH = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
private static final String []LONG_MONTH = {
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December",
};
private static TimeZone _localTimeZone = TimeZone.getDefault();
private static TimeZone _gmtTimeZone = TimeZone.getTimeZone("GMT");
private static String _localDstName =
_localTimeZone.getDisplayName(true, TimeZone.SHORT);
private static String _localStdName =
_localTimeZone.getDisplayName(false, TimeZone.SHORT);
private static String _gmtDstName =
_gmtTimeZone.getDisplayName(true, TimeZone.SHORT);
private static String _gmtStdName =
_gmtTimeZone.getDisplayName(false, TimeZone.SHORT);
// static dates for the static formatting
private static QDate _gmtDate = new QDate(false);
private static QDate _localDate = new QDate(true);
private static final FreeList _freeLocalDate
= new FreeList(8);
private static final FreeList _freeGmtDate
= new FreeList(8);
private TimeZone _timeZone;
private Calendar _calendar;
private String _dstName;
private String _stdName;
private DateFormat _dateFormat;
private DateFormat _shortDateFormat;
private DateFormat _shortTimeFormat;
private Date _date = new Date();
// All times are local
private long _localTimeOfEpoch;
private long _dayOfEpoch;
private long _year;
private int _dayOfYear;
private long _month;
private long _dayOfMonth;
private long _hour;
private long _minute;
private long _second;
private long _ms;
private boolean _isLeapYear;
private long _timeOfDay;
private boolean _isDaylightTime;
private long _zoneOffset;
private String _zoneName;
private long _lastTime;
private String _lastDate;
/**
* Creates the date for GMT.
*/
public QDate()
{
this(_gmtTimeZone);
}
/**
* Creates the date for GMT.
*/
public QDate(long time)
{
this(_localTimeZone);
setGMTTime(time);
}
/**
* Creates the date form local or GMT.
*/
public QDate(boolean isLocal)
{
this(isLocal ? _localTimeZone : _gmtTimeZone);
}
/**
* Creates the date from local or GMT.
*/
public QDate(TimeZone zone)
{
_timeZone = zone;
if (zone == _gmtTimeZone) {
_stdName = _gmtStdName;
_dstName = _gmtDstName;
}
else if (zone == _localTimeZone) {
_stdName = _localStdName;
_dstName = _localDstName;
}
else {
_stdName = _timeZone.getDisplayName(false, TimeZone.SHORT);
_dstName = _timeZone.getDisplayName(true, TimeZone.SHORT);
}
_calendar = new GregorianCalendar(_timeZone);
setLocalTime(CurrentTime.getCurrentTime());
}
/**
* Creates the date from local or GMT.
*/
public QDate(TimeZone zone, long now)
{
_timeZone = zone;
if (zone == _gmtTimeZone) {
_stdName = _gmtStdName;
_dstName = _gmtDstName;
}
else if (zone == _localTimeZone) {
_stdName = _localStdName;
_dstName = _localDstName;
}
else {
_stdName = _timeZone.getDisplayName(false, TimeZone.SHORT);
_dstName = _timeZone.getDisplayName(true, TimeZone.SHORT);
}
_calendar = new GregorianCalendar(_timeZone);
if (zone == _gmtTimeZone)
setGMTTime(now);
else
setLocalTime(now);
}
/**
* Creates the date for the local time zone.
*
* @see #setDate(long, long, long)
*/
public QDate(long year, long month, long dayOfMonth)
{
this(_localTimeZone);
setDate(year, month, dayOfMonth);
}
/**
* Creates a local calendar.
*/
public static QDate createLocal()
{
return new QDate(true);
}
public static QDate allocateLocalDate()
{
QDate date = _freeLocalDate.allocate();
if (date == null)
date = new QDate(true);
return date;
}
public static void freeLocalDate(QDate date)
{
_freeLocalDate.free(date);
}
public static QDate allocateGmtDate()
{
QDate date = _freeGmtDate.allocate();
if (date == null)
date = new QDate(false);
return date;
}
public static void freeGmtDate(QDate date)
{
_freeGmtDate.free(date);
}
/**
* Sets the time in milliseconds since the epoch and calculate
* the internal variables.
*/
public void setLocalTime(long time)
{
// If this is a local time zone date, just set the time
if (_timeZone != _gmtTimeZone) {
calculateSplit(time);
}
// If this is a GMT date, convert from local to GMT
else {
calculateSplit(time - _localTimeZone.getRawOffset());
try {
long offset = _localTimeZone.getOffset(GregorianCalendar.AD,
(int) _year,
(int) _month,
(int) _dayOfMonth + 1,
getDayOfWeek(),
(int) _timeOfDay);
calculateSplit(time - offset);
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
}
}
}
/**
* Returns the time in milliseconds since the epoch.
*/
public long getLocalTime()
{
// If this is a local time zone date, just set the time
if (_timeZone != _gmtTimeZone) {
return _localTimeOfEpoch;
}
// If this is a GMT date, convert from local to GMT
else {
long offset = _localTimeZone.getOffset(GregorianCalendar.AD,
(int) _year,
(int) _month,
(int) _dayOfMonth + 1,
getDayOfWeek(),
(int) _timeOfDay);
return _localTimeOfEpoch + offset;
}
}
/**
* Return the current time as a java.util.Calendar.
**/
public Calendar getCalendar()
{
return _calendar;
}
/**
* Sets the time in milliseconds since the epoch and calculate
* the internal variables.
*/
public void setGMTTime(long time)
{
calculateSplit(time + _timeZone.getOffset(time));
}
/**
* Returns the time in milliseconds since the epoch.
*/
public long getGMTTime()
{
return _localTimeOfEpoch - _zoneOffset;
}
/**
* Returns the milliseconds since the beginning of the day.
*/
public long getTimeOfDay()
{
return _timeOfDay;
}
/**
* Returns the year.
*/
public int getYear()
{
return (int) _year;
}
/**
* Sets the year, recalculating the time since epoch.
*/
public void setYear(int year)
{
_year = year;
calculateJoin();
calculateSplit(_localTimeOfEpoch);
}
/**
* Returns the month in the year.
*/
public int getMonth()
{
return (int) _month;
}
/**
* Sets the month in the year.
*/
public void setMonth(int month)
{
if (month < 0 || DAYS_IN_MONTH.length <= month)
return;
_month = month;
if (DAYS_IN_MONTH[month] <= _dayOfMonth)
_dayOfMonth = DAYS_IN_MONTH[month] - 1;
calculateJoin();
calculateSplit(_localTimeOfEpoch);
}
/**
* Returns the day of the month, based on 1 for the first of the month.
*/
public int getDayOfMonth()
{
return (int) _dayOfMonth + 1;
}
/**
* sets the day of the month based on 1 for the first of the month.
*/
public void setDayOfMonth(int day)
{
_dayOfMonth = day - 1;
calculateJoin();
calculateSplit(_localTimeOfEpoch);
}
/**
* Returns the day of the month, based on 1 for the first of the month.
*/
public int getDaysInMonth()
{
if (_month == 1)
return _isLeapYear ? 29 : 28;
else
return DAYS_IN_MONTH[(int) _month];
}
/**
* Returns the day of the week.
*/
public int getDayOfWeek()
{
return (int) ((_dayOfEpoch % 7) + 11) % 7 + 1;
}
/**
* Returns the day of the year, based on 0 for January 1.
*/
public int getDayOfYear()
{
return (int) _dayOfYear;
}
/**
* Returns the hour.
*/
public int getHour()
{
return (int) _hour;
}
/**
* Sets the hour, recalculating the localTimeOfEpoch.
*/
public void setHour(int hour)
{
_hour = hour;
calculateJoin();
calculateSplit(_localTimeOfEpoch);
}
/**
* Returns the minute.
*/
public int getMinute()
{
return (int) _minute;
}
/**
* Sets the minute, recalculating the localTimeOfEpoch.
*/
public void setMinute(int minute)
{
_minute = minute;
calculateJoin();
calculateSplit(_localTimeOfEpoch);
}
/**
* Returns the second.
*/
public int getSecond()
{
return (int) _second;
}
/**
* Sets the second, recalculating the localTimeOfEpoch.
*/
public void setSecond(int second)
{
_second = second;
calculateJoin();
calculateSplit(_localTimeOfEpoch);
}
/**
* Returns the millisecond.
*/
public long getMillisecond()
{
return _ms;
}
/**
* Sets the millisecond, recalculating the localTimeOfEpoch.
*/
public void setMillisecond(long millisecond)
{
_ms = millisecond;
calculateJoin();
calculateSplit(_localTimeOfEpoch);
}
/**
* Returns the time zone offset for that particular day.
*/
public long getZoneOffset()
{
return _zoneOffset;
}
/**
* Returns the name of the timezone
*/
public String getZoneName()
{
return _zoneName;
}
/**
* Returns true for DST
*/
public boolean isDST()
{
return _isDaylightTime;
}
/**
* Returns the current time zone.
*/
public TimeZone getLocalTimeZone()
{
return _timeZone;
}
/**
* Returns the week in the year.
*/
public int getWeek()
{
int dow4th = (int) ((_dayOfEpoch - _dayOfYear + 3) % 7 + 10) % 7;
int ww1monday = 3 - dow4th;
if (_dayOfYear < ww1monday)
return 53;
int week = (_dayOfYear - ww1monday) / 7 + 1;
if (_dayOfYear >= 360) {
int days = 365 + (_isLeapYear ? 1 : 0);
long nextNewYear = (_dayOfEpoch - _dayOfYear + days);
int dowNext4th = (int) ((nextNewYear + 3) % 7 + 10) % 7;
int nextWw1Monday = 3 - dowNext4th;
if (days <= _dayOfYear - nextWw1Monday)
return 1;
}
return week;
}
/**
* Gets values based on a field.
*/
public long get(int field)
{
switch (field) {
case TIME:
return getLocalTime();
case YEAR:
return getYear();
case MONTH:
return getMonth();
case DAY_OF_MONTH:
return getDayOfMonth();
case DAY:
return getDayOfWeek();
case DAY_OF_WEEK:
return getDayOfWeek();
case HOUR:
return getHour();
case MINUTE:
return getMinute();
case SECOND:
return getSecond();
case MILLISECOND:
return getMillisecond();
case TIME_ZONE:
return getZoneOffset() / 1000;
default:
return Long.MAX_VALUE;
}
}
/**
* Sets values based on a field.
*/
public long set(int field, long value)
{
switch (field) {
case YEAR:
setYear((int) value);
break;
case MONTH:
setMonth((int) value);
break;
case DAY_OF_MONTH:
setDayOfMonth((int) value);
break;
case HOUR:
setHour((int) value);
break;
case MINUTE:
setMinute((int) value);
break;
case SECOND:
setSecond((int) value);
break;
case MILLISECOND:
setMillisecond(value);
break;
default:
throw new RuntimeException();
}
return _localTimeOfEpoch;
}
/*
* Mon, 17 Jan 1994 11:14:55 -0500 (EST)
*/
public String printDate()
{
if (_lastDate != null && _lastTime == _localTimeOfEpoch)
return _lastDate;
CharBuffer cb = new CharBuffer();
printDate(cb);
_lastDate = cb.toString();
_lastTime = _localTimeOfEpoch;
return _lastDate;
}
/*
* Mon, 17 Jan 1994 11:14:55 -0500 (EST)
*/
public void printDate(CharBuffer cb)
{
cb.append(DAY_NAMES[(int) (_dayOfEpoch % 7 + 11) % 7]);
cb.append(", ");
cb.append((_dayOfMonth + 1) / 10);
cb.append((_dayOfMonth + 1) % 10);
cb.append(" ");
cb.append(MONTH_NAMES[(int) _month]);
cb.append(" ");
cb.append(_year);
cb.append(" ");
cb.append((_timeOfDay / 36000000L) % 10);
cb.append((_timeOfDay / 3600000L) % 10);
cb.append(":");
cb.append((_timeOfDay / 600000L) % 6);
cb.append((_timeOfDay / 60000L) % 10);
cb.append(":");
cb.append((_timeOfDay / 10000L) % 6);
cb.append((_timeOfDay / 1000L) % 10);
if (_zoneName == null || _zoneName.equals("GMT")) {
cb.append(" GMT");
return;
}
long offset = _zoneOffset;
if (offset < 0) {
cb.append(" -");
offset = - offset;
} else
cb.append(" +");
cb.append((offset / 36000000) % 10);
cb.append((offset / 3600000) % 10);
cb.append((offset / 600000) % 6);
cb.append((offset / 60000) % 10);
cb.append(" (");
cb.append(_zoneName);
cb.append(")");
}
/**
* Prints the date to a stream.
*/
public void printDate(WriteStream os)
throws IOException
{
os.print(DAY_NAMES[(int) (_dayOfEpoch % 7 + 11) % 7]);
os.write(',');
os.write(' ');
os.print((_dayOfMonth + 1) / 10);
os.print((_dayOfMonth + 1) % 10);
os.write(' ');
os.print(MONTH_NAMES[(int) _month]);
os.write(' ');
os.print(_year);
os.write(' ');
os.print((_timeOfDay / 36000000) % 10);
os.print((_timeOfDay / 3600000) % 10);
os.write(':');
os.print((_timeOfDay / 600000) % 6);
os.print((_timeOfDay / 60000) % 10);
os.write(':');
os.print((_timeOfDay / 10000) % 6);
os.print((_timeOfDay / 1000) % 10);
if (_zoneName == null) {
os.print(" GMT");
return;
}
long offset = _zoneOffset;
if (offset < 0) {
os.write(' ');
os.write('-');
offset = - offset;
} else {
os.write(' ');
os.write('+');
}
os.print((offset / 36000000) % 10);
os.print((offset / 3600000) % 10);
os.print((offset / 600000) % 6);
os.print((offset / 60000) % 10);
os.write(' ');
os.write('(');
os.print(_zoneName);
os.write(')');
}
/*
* Mon, 17 Jan 1994 11:14:55 -0500
*/
public void printRFC2822(CharBuffer cb)
{
cb.append(DAY_NAMES[(int) (_dayOfEpoch % 7 + 11) % 7]);
cb.append(", ");
cb.append((_dayOfMonth + 1) / 10);
cb.append((_dayOfMonth + 1) % 10);
cb.append(" ");
cb.append(MONTH_NAMES[(int) _month]);
cb.append(" ");
cb.append(_year);
cb.append(" ");
cb.append((_timeOfDay / 36000000L) % 10);
cb.append((_timeOfDay / 3600000L) % 10);
cb.append(":");
cb.append((_timeOfDay / 600000L) % 6);
cb.append((_timeOfDay / 60000L) % 10);
cb.append(":");
cb.append((_timeOfDay / 10000L) % 6);
cb.append((_timeOfDay / 1000L) % 10);
long offset = _zoneOffset;
if (offset < 0) {
cb.append(" -");
offset = - offset;
} else
cb.append(" +");
cb.append((offset / 36000000) % 10);
cb.append((offset / 3600000) % 10);
cb.append((offset / 600000) % 6);
cb.append((offset / 60000) % 10);
}
/**
* Prints the time in ISO 8601
*/
public String printISO8601()
{
StringBuilder sb = new StringBuilder();
if (_year > 0) {
sb.append((_year / 1000) % 10);
sb.append((_year / 100) % 10);
sb.append((_year / 10) % 10);
sb.append(_year % 10);
sb.append('-');
sb.append(((_month + 1) / 10) % 10);
sb.append((_month + 1) % 10);
sb.append('-');
sb.append(((_dayOfMonth + 1) / 10) % 10);
sb.append((_dayOfMonth + 1) % 10);
}
long time = _timeOfDay / 1000;
long ms = _timeOfDay % 1000;
sb.append('T');
sb.append((time / 36000) % 10);
sb.append((time / 3600) % 10);
sb.append(':');
sb.append((time / 600) % 6);
sb.append((time / 60) % 10);
sb.append(':');
sb.append((time / 10) % 6);
sb.append((time / 1) % 10);
if (ms != 0) {
sb.append('.');
sb.append((ms / 100) % 10);
sb.append((ms / 10) % 10);
sb.append(ms % 10);
}
if (_zoneName == null) {
sb.append("Z");
return sb.toString();
}
// server/1471 - XXX: was commented out
long offset = _zoneOffset;
if (offset < 0) {
sb.append("-");
offset = - offset;
} else
sb.append("+");
sb.append((offset / 36000000) % 10);
sb.append((offset / 3600000) % 10);
sb.append(':');
sb.append((offset / 600000) % 6);
sb.append((offset / 60000) % 10);
return sb.toString();
}
/**
* Prints just the date component of ISO 8601
*/
public String printISO8601Date()
{
CharBuffer cb = new CharBuffer();
if (_year > 0) {
cb.append((_year / 1000) % 10);
cb.append((_year / 100) % 10);
cb.append((_year / 10) % 10);
cb.append(_year % 10);
cb.append('-');
cb.append(((_month + 1) / 10) % 10);
cb.append((_month + 1) % 10);
cb.append('-');
cb.append(((_dayOfMonth + 1) / 10) % 10);
cb.append((_dayOfMonth + 1) % 10);
}
return cb.toString();
}
/**
* Formats a date.
*
* @param time the time to format
* @param format the format string
*/
public synchronized static String formatGMT(long gmtTime, String format)
{
_gmtDate.setGMTTime(gmtTime);
return _gmtDate.format(new CharBuffer(), format).toString();
}
/**
* Formats a date, using the default time format.
*
* @param time the time to format
*/
public synchronized static String formatGMT(long gmtTime)
{
_gmtDate.setGMTTime(gmtTime);
return _gmtDate.printDate();
}
/**
* Formats a time in the local time zone.
*
* @param time in milliseconds, GMT, from the epoch.
* @param format formatting string.
*/
public synchronized static String formatLocal(long gmtTime, String format)
{
_localDate.setGMTTime(gmtTime);
return _localDate.format(new CharBuffer(), format).toString();
}
/**
* Formats a time in the local time zone, using the default format.
*
* @param time in milliseconds, GMT, from the epoch.
*/
public synchronized static String formatLocal(long gmtTime)
{
_localDate.setGMTTime(gmtTime);
return _localDate.printDate();
}
/**
* Formats a time in the local time zone.
*
* @param time in milliseconds, GMT, from the epoch.
* @param format formatting string.
*/
public synchronized static CharBuffer formatLocal(CharBuffer cb,
long gmtTime,
String format)
{
_localDate.setGMTTime(gmtTime);
return _localDate.format(cb, format);
}
public synchronized static String formatISO8601(long gmtTime)
{
if (_gmtDate == null)
_gmtDate = new QDate();
_gmtDate.setGMTTime(gmtTime);
return _gmtDate.printISO8601();
}
/**
* Global date must be synchronized before you can do anything on it.
*/
public static QDate getGlobalDate()
{
return _localDate;
}
/**
* Formats the current date.
*/
public String format(String format)
{
CharBuffer cb = new CharBuffer();
return format(cb, format).close();
}
/**
* Format the date using % escapes:
*
*
* %a day of week (short)
* %A day of week (verbose)
* %b month name (short)
* %B month name (verbose)
* %c Java locale date
* %d day of month (two-digit)
* %F %Y-%m-%d
* %H 24-hour (two-digit)
* %I 12-hour (two-digit)
* %j day of year (three-digit)
* %l 12-hour (one-digit prefixed by space)
* %m month (two-digit)
* %M minutes
* %p am/pm
* %P AM/PM
* %S seconds
* %s milliseconds
* %x Java locale short date
* %X Java locale short time
* %W week in year (three-digit)
* %w day of week (one-digit)
* %y year (two-digit)
* %Y year (four-digit)
* %Z time zone (name)
* %z time zone (+/-0800)
*
*/
public CharBuffer format(CharBuffer cb, String format)
{
int length = format.length();
for (int i = 0; i < length; i++) {
char ch = format.charAt(i);
if (ch != '%') {
cb.append(ch);
continue;
}
switch (format.charAt(++i)) {
case 'a':
cb.append(SHORT_WEEKDAY[getDayOfWeek() - 1]);
break;
case 'A':
cb.append(LONG_WEEKDAY[getDayOfWeek() - 1]);
break;
case 'h':
case 'b':
cb.append(SHORT_MONTH[(int) _month]);
break;
case 'B':
cb.append(LONG_MONTH[(int) _month]);
break;
case 'c':
cb.append(printLocaleDate());
break;
case 'd':
cb.append((_dayOfMonth + 1) / 10);
cb.append((_dayOfMonth + 1) % 10);
break;
case 'D':
cb.append((_month + 1) / 10);
cb.append((_month + 1) % 10);
cb.append('/');
cb.append((_dayOfMonth + 1) / 10);
cb.append((_dayOfMonth + 1) % 10);
cb.append('/');
cb.append(_year / 10 % 10);
cb.append(_year % 10);
break;
case 'e':
if ((_dayOfMonth + 1) / 10 == 0)
cb.append(' ');
else
cb.append((_dayOfMonth + 1) / 10);
cb.append((_dayOfMonth + 1) % 10);
break;
// ISO year
case 'F':
{
cb.append(_year / 1000 % 10);
cb.append(_year / 100 % 10);
cb.append(_year / 10 % 10);
cb.append(_year % 10);
cb.append('-');
cb.append((_month + 1) / 10);
cb.append((_month + 1) % 10);
cb.append('-');
cb.append((_dayOfMonth + 1) / 10);
cb.append((_dayOfMonth + 1) % 10);
break;
}
case 'H':
{
int hour = (int) (_timeOfDay / 3600000) % 24;
cb.append(hour / 10);
cb.append(hour % 10);
break;
}
case 'I':
{
int hour = (int) (_timeOfDay / 3600000) % 12;
if (hour == 0)
hour = 12;
cb.append(hour / 10);
cb.append(hour % 10);
break;
}
case 'j':
cb.append((_dayOfYear + 1) / 100);
cb.append((_dayOfYear + 1) / 10 % 10);
cb.append((_dayOfYear + 1) % 10);
break;
case 'l':
{
int hour = (int) (_timeOfDay / 3600000) % 12;
if (hour == 0)
hour = 12;
if (hour < 10) {
cb.append(' ');
}
cb.append(hour);
break;
}
case 'm':
cb.append((_month + 1) / 10);
cb.append((_month + 1) % 10);
break;
case 'M':
cb.append((_timeOfDay / 600000) % 6);
cb.append((_timeOfDay / 60000) % 10);
break;
case 'p':
{
int hour = (int) (_timeOfDay / 3600000) % 24;
if (hour < 12)
cb.append("am");
else
cb.append("pm");
break;
}
case 'P':
{
int hour = (int) (_timeOfDay / 3600000) % 24;
if (hour < 12)
cb.append("AM");
else
cb.append("PM");
break;
}
case 'S':
cb.append((_timeOfDay / 10000) % 6);
cb.append((_timeOfDay / 1000) % 10);
break;
case 's':
cb.append((_timeOfDay / 100) % 10);
cb.append((_timeOfDay / 10) % 10);
cb.append(_timeOfDay % 10);
break;
case 'T':
{
int hour = (int) (_timeOfDay / 3600000) % 24;
cb.append(hour / 10);
cb.append(hour % 10);
cb.append(':');
cb.append((_timeOfDay / 600000) % 6);
cb.append((_timeOfDay / 60000) % 10);
cb.append(':');
cb.append((_timeOfDay / 10000) % 6);
cb.append((_timeOfDay / 1000) % 10);
break;
}
case 'W':
int week = getWeek();
cb.append((week + 1) / 10);
cb.append((week + 1) % 10);
break;
case 'w':
cb.append(getDayOfWeek() - 1);
break;
case 'x':
cb.append(printShortLocaleDate());
break;
case 'X':
cb.append(printShortLocaleTime());
break;
case 'y':
cb.append(_year / 10 % 10);
cb.append(_year % 10);
break;
case 'Y':
cb.append(_year / 1000 % 10);
cb.append(_year / 100 % 10);
cb.append(_year / 10 % 10);
cb.append(_year % 10);
break;
case 'Z':
if (_zoneName == null)
cb.append("GMT");
else
cb.append(_zoneName);
break;
case 'z':
long offset = _zoneOffset;
if (offset < 0) {
cb.append("-");
offset = - offset;
}
else
cb.append("+");
cb.append((offset / 36000000) % 10);
cb.append((offset / 3600000) % 10);
cb.append((offset / 600000) % 6);
cb.append((offset / 60000) % 10);
break;
case '%':
cb.append('%');
break;
default:
cb.append(format.charAt(i));
}
}
return cb;
}
/*
* XXX: buggy (Because cal is buggy), may have to implement the sdf
*/
public String printLocaleDate()
{
_date.setTime(_localTimeOfEpoch);
// SimpleDateFormat sdf = new SimpleDateFormat();
// System.out.println("" + sdf.toPattern());
if (_dateFormat == null)
_dateFormat = DateFormat.getInstance();
return _dateFormat.format(_date);
}
/**
* Returns a date in M/dd/yy format (i.e. 11/30/69 in US locale).
*/
public String printShortLocaleDate()
{
_date.setTime(_localTimeOfEpoch);
if (_shortDateFormat == null)
_shortDateFormat = DateFormat.getDateInstance(DateFormat.SHORT);
return _shortDateFormat.format(_date);
}
/**
* Returns a date in H:mm:ss PM format.
*/
public String printShortLocaleTime()
{
_date.setTime(_localTimeOfEpoch);
if (_shortTimeFormat == null)
_shortTimeFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
return _shortTimeFormat.format(_date);
}
/*
* XXX: okay, this is vile.
* Mon, 17 Jan 1994 11:14:55 -0500 (EST)
*
* In local time
*/
public long parseLocalDate(String string) throws Exception
{
long time = parseDate(string);
synchronized (this) {
setLocalTime(time);
return getGMTTime();
}
}
/*
* XXX: okay, this is vile.
* Mon, 17 Jan 1994 11:14:55 -0500 (EST)
*
* In GMT time
*/
public long parseDate(String string) throws Exception
{
try {
int strlen = string.length();
if (strlen == 0)
return 0;
int i = skipWhitespace(string, strlen, 0);
int ch = string.charAt(i);
if (ch >= '0' && ch <= '9'
|| (ch == 'T' && i + 1 < strlen
&& string.charAt(i + 1) >= '0' && string.charAt(i + 1) <= '9'))
return parseISO8601Date(string, i);
CharBuffer cb = new CharBuffer();
i = scan(string, 0, cb, true);
if (cb.length() == 0 || ! Character.isDigit(cb.charAt(0)))
i = scan(string, i, cb, true);
int dayOfMonth = parseInt(cb);
i = scan(string, i, cb, true);
String smonth = cb.toString();
int month;
for (month = 0; month < 12; month++) {
if (MONTH_NAMES[(int) month].equalsIgnoreCase(smonth))
break;
}
if (month == 12)
throw new Exception("Unexpected month: " + month);
i = scan(string, i, cb, true);
int year = parseInt(cb);
if (cb.length() < 3 && year < 50)
year += 2000;
else if (cb.length() < 3 && year < 100)
year += 1900;
i = scan(string, i, cb, false);
long timeOfDay = parseInt(cb) * 3600000;
i = scan(string, i, cb, false);
timeOfDay += parseInt(cb) * 60000;
i = scan(string, i, cb, false);
timeOfDay += parseInt(cb) * 1000;
// XXX: gross hack
if (year <= 1600)
dayOfMonth--;
long time = (MS_PER_DAY * (yearToDayOfEpoch(year)
+ monthToDayOfYear(month, isLeapYear(year))
+ dayOfMonth - 1)
+ timeOfDay);
try {
i = scan(string, i, cb, false);
for (int j = 0; j < cb.length(); j++) {
if ((ch = cb.charAt(j)) == ';' || ch == ' ')
cb.setLength(j);
}
ch = cb.length() > 0 ? cb.charAt(0) : 0;
if (ch == '-' || ch == '+' || ch >= '0' && ch <= '9') {
long zoneOffset;
zoneOffset = parseInt(cb);
zoneOffset = 60000 * (60 * (zoneOffset / 100) + zoneOffset % 100);
time -= zoneOffset;
setGMTTime(time);
} else if (cb.equalsIgnoreCase("gmt") ||
cb.equalsIgnoreCase("utc")) {
setGMTTime(time);
} else {
setLocalTime(time);
}
} catch (Exception e) {
log.log(Level.FINER, e.toString(), e);
}
return _localTimeOfEpoch - _zoneOffset;
} catch (Exception e) {
log.log(Level.FINER, e.toString(), e);
return Long.MAX_VALUE;
}
}
private long parseISO8601Date(String string, int pos)
throws Exception
{
int strlen = string.length();
int year = 0;
char ch = string.charAt(pos);
if ('0' <= ch && ch <= '9') {
year = scanISOInt(string, pos, strlen, 4);
pos += 4;
}
if (pos < strlen && string.charAt(pos) == '-')
pos++;
int month = 0;
if (pos < strlen && '0' <= (ch = string.charAt(pos)) && ch <= '9') {
month = scanISOInt(string, pos, strlen, 2);
month--;
pos += 2;
} else if (ch == 'W')
return Long.MAX_VALUE;
if (pos < strlen && string.charAt(pos) == '-')
pos++;
int day = 0;
if (pos < strlen && '0' <= (ch = string.charAt(pos)) && ch <= '9') {
day = scanISOInt(string, pos, strlen, 2);
day--;
pos += 2;
}
int hour = 0;
int minute = 0;
int second = 0;
int millisecond = 0;
if (pos < strlen && string.charAt(pos) == 'T') {
pos++;
if (pos < strlen && '0' <= (ch = string.charAt(pos)) && ch <= '9') {
hour = scanISOInt(string, pos, strlen, 2);
pos += 2;
}
// XXX: fractions can technically be used anywhere by using a
// , or . instead of a :
// e.g. 14:30,5 == 14:30:30
if (pos < strlen && string.charAt(pos) == ':')
pos++;
if (pos < strlen && '0' <= (ch = string.charAt(pos)) && ch <= '9') {
minute = scanISOInt(string, pos, strlen, 2);
pos += 2;
}
if (pos < strlen && string.charAt(pos) == ':')
pos++;
if (pos < strlen && '0' <= (ch = string.charAt(pos)) && ch <= '9') {
second = scanISOInt(string, pos, strlen, 2);
pos += 2;
}
if (pos < strlen &&
(string.charAt(pos) == '.' || string.charAt(pos) == ',')) {
pos++;
// XXX: fractions can be any strlen, not just 3
millisecond = scanISOInt(string, pos, strlen, 3);
pos += 3;
}
}
long timeOfDay = millisecond + 1000 * (second + 60 * (minute + 60 * hour));
// XXX: gross hack
if (year <= 1600)
day--;
long time = (MS_PER_DAY * (yearToDayOfEpoch(year) +
monthToDayOfYear(month, isLeapYear(year)) +
day) +
timeOfDay);
if (strlen <= pos) {
setLocalTime(time);
return _localTimeOfEpoch;
}
if (string.charAt(pos) == 'Z') {
pos++;
}
else if (string.charAt(pos) == '-' || string.charAt(pos) == '+') {
int sign = -1;
if (string.charAt(pos) == '-')
sign = 1;
pos++;
int tzHour = scanISOInt(string, pos, strlen, 2);
pos += 2;
int tzMinute = 0;
if (pos < strlen && string.charAt(pos) == ':')
pos++;
if (pos < strlen && '0' <= (ch = string.charAt(pos)) && ch <= '9') {
tzMinute = scanISOInt(string, pos, strlen, 2);
pos += 2;
}
time += sign * 1000 * (60 * (tzMinute + 60 * tzHour));
}
else {
setLocalTime(time);
return _localTimeOfEpoch;
}
pos = skipWhitespace(string, strlen, pos);
if (pos < strlen)
throw new Exception("extra junk at end of ISO date");
setGMTTime(time);
return _localTimeOfEpoch;
}
/**
* Based on the year, return the number of days since the epoch.
*/
private long yearToDayOfEpoch(long year)
{
if (year > 0) {
year -= 1601;
return (365 * year + year / 4 - year / 100 + year / 400 -
((1970 - 1601) * 365 + (1970 - 1601) / 4 - 3));
} else {
year = 2000 - year;
return ((2000 - 1970) * 365 + (2000 - 1970) / 4 -
(365 * year + year / 4 - year / 100 + year / 400));
}
}
/**
* Calculates the day of the year for the beginning of the month.
*/
private long monthToDayOfYear(long month, boolean isLeapYear)
{
long day = 0;
for (int i = 0; i < month && i < 12; i++) {
day += DAYS_IN_MONTH[i];
if (i == 1 && isLeapYear)
day++;
}
return day;
}
/**
* Returns true if the given year is a leap year.
*/
private boolean isLeapYear(long year)
{
return ! ((year % 4) != 0 || (year % 100) == 0 && (year % 400) != 0);
}
private int scanISOInt(String string, int pos, int length, int digits)
throws Exception
{
int value = 0;
for (int i = 0; i < digits; i++) {
if (pos >= length)
throw new Exception("expected ISO8601 digit");
char ch = string.charAt(pos++);
if ('0' <= ch && ch <= '9')
value = 10 * value + ch - '0';
else
throw new Exception("expected ISO8601 digit");
}
return value;
}
private int skipWhitespace(String string, int strlen, int i)
{
char ch;
for (; i < strlen
&& ((ch = string.charAt(i)) == ' ' || ch == '\t'
|| ch == '\n' || ch == '\r');
i++) {
}
return i;
}
/*
* Scan to whitespace or ':'
*/
private int scan(String string, int i, CharBuffer cb, boolean dash)
throws Exception
{
char ch;
cb.setLength(0);
int strlen = string.length();
for (; i < strlen; i++) {
if (! Character.isWhitespace(ch = string.charAt(i)) &&
(ch != ':' && (! dash || ch != '-')))
break;
}
for (; i < strlen; i++) {
if (! Character.isWhitespace(ch = string.charAt(i)) &&
(ch != ':' && (! dash || ch != '-')))
cb.append((char) ch);
else
break;
}
if (cb.length() == 0)
throw new Exception();
return i;
}
private int parseInt(CharBuffer cb) throws Exception
{
int value = 0;
int sign = 1;
for (int i = 0; i < cb.length(); i++) {
int ch = cb.charAt(i);
if (i == 0 && ch == '-')
sign = -1;
else if (i == 0 && ch == '+') {
}
else if (ch >= '0' && ch <= '9')
value = 10 * value + ch - '0';
else
throw new Exception();
}
return sign * value;
}
/**
* Sets date in the local time.
*
* @param year
* @param month where January = 0
* @param day day of month where the 1st = 1
*/
public long setDate(long year, long month, long day)
{
year += (long) Math.floor(month / 12.0);
month -= (long) 12 * Math.floor(month / 12.0);
_year = year;
_month = month;
_dayOfMonth = day - 1;
calculateJoin();
calculateSplit(_localTimeOfEpoch);
return _localTimeOfEpoch;
}
public long setTime(long hour, long minute, long second, long ms)
{
_hour = hour;
_minute = minute;
_second = second;
_ms = ms;
calculateJoin();
calculateSplit(_localTimeOfEpoch);
return _localTimeOfEpoch;
}
/**
* Calculate and set the calendar components based on the given time.
*
* @param localTime local time in milliseconds since the epoch
*/
private void calculateSplit(long localTime)
{
_localTimeOfEpoch = localTime;
_dayOfEpoch = divFloor(_localTimeOfEpoch, MS_PER_DAY);
_timeOfDay = _localTimeOfEpoch - MS_PER_DAY * _dayOfEpoch;
calculateYear();
calculateMonth();
_hour = _timeOfDay / 3600000;
_minute = _timeOfDay / 60000 % 60;
_second = _timeOfDay / 1000 % 60;
_ms = _timeOfDay % 1000;
if (_timeZone == _gmtTimeZone) {
_isDaylightTime = false;
_zoneName = _stdName;
_zoneOffset = 0;
}
else {
// server/1470
long tempOffset = _timeZone.getOffset(_localTimeOfEpoch);
_zoneOffset = _timeZone.getOffset(_localTimeOfEpoch - tempOffset);
if (_zoneOffset == _timeZone.getRawOffset()) {
_isDaylightTime = false;
_zoneName = _stdName;
}
else {
_isDaylightTime = true;
_zoneName = _dstName;
}
}
_calendar.setTimeInMillis(_localTimeOfEpoch);
}
/**
* Calculates the year, the dayOfYear and whether this is a leap year
* from the current days since the epoch.
*/
private void calculateYear()
{
long days = _dayOfEpoch;
// shift to using 1601 as a base
days += (1970 - 1601) * 365 + (1970 - 1601) / 4 - 3;
long n400 = divFloor(days, 400 * 365 + 100 - 3);
days -= n400 * (400 * 365 + 100 - 3);
long n100 = divFloor(days, 100 * 365 + 25 - 1);
if (n100 == 4)
n100 = 3;
days -= n100 * (100 * 365 + 25 - 1);
long n4 = divFloor(days, 4 * 365 + 1);
if (n4 == 25)
n4 = 24;
days -= n4 * (4 * 365 + 1);
long n1 = divFloor(days, 365);
if (n1 == 4)
n1 = 3;
_year = 400 * n400 + 100 * n100 + 4 * n4 + n1 + 1601;
_dayOfYear = (int) (days - 365 * n1);
_isLeapYear = isLeapYear(_year);
}
public boolean isLeapYear()
{
return _isLeapYear;
}
/**
* Calculates the month based on the day of the year.
*/
private void calculateMonth()
{
_dayOfMonth = _dayOfYear;
for (_month = 0; _month < 12; _month++) {
if (_month == 1 && _isLeapYear) {
if (_dayOfMonth < 29)
return;
else
_dayOfMonth -= 29;
}
else if (_dayOfMonth < DAYS_IN_MONTH[(int) _month])
return;
else
_dayOfMonth -= DAYS_IN_MONTH[(int) _month];
}
}
/**
* Based on the current data, calculate the time since the epoch.
*
* @return time since the epoch, given the calendar components
*/
private long calculateJoin()
{
_year += divFloor(_month, 12);
_month -= 12 * divFloor(_month, 12);
_localTimeOfEpoch
= MS_PER_DAY * (yearToDayOfEpoch(_year)
+ monthToDayOfYear(_month, isLeapYear(_year))
+ _dayOfMonth);
_localTimeOfEpoch += _ms + 1000 * (_second + 60 * (_minute + 60 * _hour));
return _localTimeOfEpoch;
}
private long divFloor(long n, long d)
{
if (n > 0)
return n / d;
else
return (n - d + 1) / d;
}
@Override
public Object clone()
{
QDate newObj = new QDate(_timeZone);
newObj.calculateSplit(_localTimeOfEpoch);
return newObj;
}
@Override
public String toString()
{
return "QDate[" + printDate() + "]";
}
}