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 Show documentation
Show all versions of resin Show documentation
Resin Java Application Server
/*
* Copyright (c) 1998-2018 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() + "]";
}
}