You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
671 lines
31 KiB
671 lines
31 KiB
// serverDate.java
|
|
// -------------------------------------------
|
|
// (C) by Michael Peter Christen; mc@anomic.de
|
|
// (C) by by Bjoern 'Fuchs' Krombholz; fox.box@gmail.com
|
|
// first published on http://www.anomic.de
|
|
// Frankfurt, Germany, 2005, 2007
|
|
// last major change: 14.03.2005
|
|
//
|
|
// This program 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.
|
|
//
|
|
// This program 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. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
// Using this software in any meaning (reading, learning, copying, compiling,
|
|
// running) means that you agree that the Author(s) is (are) not responsible
|
|
// for cost, loss of data or any harm that may be caused directly or indirectly
|
|
// by usage of this softare or this documentation. The usage of this software
|
|
// is on your own risk. The installation and usage (starting/running) of this
|
|
// software may allow other people or application to access your computer and
|
|
// any attached devices and is highly dependent on the configuration of the
|
|
// software which must be done by the user of the software; the author(s) is
|
|
// (are) also not responsible for proper configuration and usage of the
|
|
// software, even if provoked by documentation provided together with
|
|
// the software.
|
|
//
|
|
// Any changes to this file according to the GPL as documented in the file
|
|
// gpl.txt aside this file in the shipment you received can be done to the
|
|
// lines that follows this copyright notice here, but changes must not be
|
|
// done inside the copyright notive above. A re-distribution must contain
|
|
// the intact and unchanged copyright notice.
|
|
// Contributions and changes to the program code must be marked as such.
|
|
|
|
|
|
// this class is needed to replace the slow java built-in date method by a faster version
|
|
|
|
package de.anomic.server;
|
|
|
|
import java.text.DateFormat;
|
|
import java.text.ParseException;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.Calendar;
|
|
import java.util.Date;
|
|
import java.util.Locale;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.StringTokenizer;
|
|
import java.util.TimeZone;
|
|
|
|
import de.anomic.server.logging.serverLog;
|
|
|
|
public final class serverDate {
|
|
|
|
/** minimal date format without time information (fixed width: 8) */
|
|
public static final String PATTERN_SHORT_DAY = "yyyyMMdd";
|
|
/** minimal date format (fixed width: 14) */
|
|
public static final String PATTERN_SHORT_SECOND = "yyyyMMddHHmmss";
|
|
/** minimal date format including milliseconds (fixed width: 17) */
|
|
public static final String PATTERN_SHORT_MILSEC = "yyyyMMddHHmmssSSS";
|
|
|
|
/** default HTTP 1.1 header date format pattern */
|
|
public static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
|
|
/** date pattern used in older HTTP implementations */
|
|
public static final String PATTERN_ANSIC = "EEE MMM d HH:mm:ss yyyy";
|
|
/** date pattern used in older HTTP implementations */
|
|
public static final String PATTERN_RFC1036 = "EEEE, dd-MMM-yy HH:mm:ss zzz";
|
|
|
|
/** pattern for a W3C datetime variant of a non-localized ISO8601 date */
|
|
public static final String PATTERN_ISO8601 = "yyyy-MM-dd'T'HH:mm:ss'Z'";
|
|
|
|
/** predefined GMT TimeZone object */
|
|
private static final TimeZone TZ_GMT = TimeZone.getTimeZone("GMT");
|
|
|
|
/** predefined non-localized Calendar object for generic GMT dates */
|
|
private static final Calendar CAL_GMT = Calendar.getInstance(TZ_GMT, Locale.US);
|
|
|
|
/** Date formatter/parser for minimal yyyyMMdd pattern */
|
|
public static final SimpleDateFormat FORMAT_SHORT_DAY = new SimpleDateFormat(PATTERN_SHORT_DAY);
|
|
/** Date formatter/parser for minimal yyyyMMddHHmmss pattern */
|
|
public static final SimpleDateFormat FORMAT_SHORT_SECOND = new SimpleDateFormat(PATTERN_SHORT_SECOND);
|
|
/** Date formatter/parser for minimal yyyyMMddHHmmssSSS pattern */
|
|
public static final SimpleDateFormat FORMAT_SHORT_MILSEC = new SimpleDateFormat(PATTERN_SHORT_MILSEC);
|
|
|
|
/** Date formatter/non-sloppy parser for W3C datetime (ISO8601) in GMT/UTC */
|
|
public static final SimpleDateFormat FORMAT_ISO8601 = new SimpleDateFormat(PATTERN_ISO8601);
|
|
|
|
/** Date formatter/parser for standard compliant HTTP header dates (RFC 1123) */
|
|
public static final SimpleDateFormat FORMAT_RFC1123 = new SimpleDateFormat(PATTERN_RFC1123, Locale.US);
|
|
|
|
/**
|
|
* RFC 2616 requires that HTTP clients are able to parse all 3 different
|
|
* formats. All times MUST be in GMT/UTC, but ...
|
|
*/
|
|
public static SimpleDateFormat[] FORMATS_HTTP = new SimpleDateFormat[] {
|
|
// RFC 1123/822 (Standard) "Mon, 12 Nov 2007 10:11:12 GMT"
|
|
FORMAT_RFC1123,
|
|
// RFC 1036/850 (old) "Monday, 12-Nov-07 10:11:12 GMT"
|
|
new SimpleDateFormat(PATTERN_RFC1036, Locale.US),
|
|
// ANSI C asctime() "Mon Nov 12 10:11:12 2007"
|
|
new SimpleDateFormat(PATTERN_ANSIC, Locale.US),
|
|
};
|
|
|
|
/** Initialization of static formats */
|
|
static {
|
|
// 2-digit dates are automatically parsed by SimpleDateFormat,
|
|
// we need to detect the real year by adding 1900 or 2000 to
|
|
// the year value starting with 1970
|
|
CAL_GMT.setTimeInMillis(0);
|
|
|
|
for (int i = 0; i < serverDate.FORMATS_HTTP.length; i++) {
|
|
SimpleDateFormat f = serverDate.FORMATS_HTTP[i];
|
|
f.setTimeZone(TZ_GMT);
|
|
f.set2DigitYearStart(CAL_GMT.getTime());
|
|
}
|
|
|
|
// we want GMT times on the SHORT formats as well as they don't support any timezone
|
|
FORMAT_SHORT_DAY.setTimeZone(TZ_GMT);
|
|
FORMAT_SHORT_SECOND.setTimeZone(TZ_GMT);
|
|
FORMAT_SHORT_MILSEC.setTimeZone(TZ_GMT);
|
|
FORMAT_ISO8601.setTimeZone(TZ_GMT);
|
|
}
|
|
|
|
/**
|
|
* Parse a HTTP string representation of a date into a Date instance.
|
|
* @param s The date String to parse.
|
|
* @return The Date instance if successful, <code>null</code> otherwise.
|
|
*/
|
|
public static Date parseHTTPDate(String s) {
|
|
s = s.trim();
|
|
if ((s == null) || (s.length() < 9)) return null;
|
|
|
|
for(int i = 0; i < FORMATS_HTTP.length; i++) {
|
|
try {
|
|
return parse(FORMATS_HTTP[i], s);
|
|
} catch (ParseException e) {
|
|
// on ParseException try again with next parser
|
|
}
|
|
}
|
|
|
|
// the method didn't return a Date, so we got an illegal String
|
|
serverLog.logSevere("HTTPC-header", "DATE ERROR (Parse): " + s);
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Creates a String representation of a Date using the format defined
|
|
* in ISO8601/W3C datetime
|
|
* The result will be in UTC/GMT, e.g. "2007-12-19T10:20:30Z".
|
|
*
|
|
* @param date The Date instance to transform.
|
|
* @return A fixed width (20 chars) ISO8601 date String.
|
|
*/
|
|
public static String formatISO8601(Date date){
|
|
return format(FORMAT_ISO8601, date);
|
|
}
|
|
|
|
/**
|
|
* Parse dates as defined in {@linkplain http://www.w3.org/TR/NOTE-datetime}.
|
|
* This format (also specified in ISO8601) allows different "precisions".
|
|
* The following lower precision versions for the complete date
|
|
* "2007-12-19T10:20:30.567+0300" are allowed:<br>
|
|
* "2007"<br>
|
|
* "2007-12"<br>
|
|
* "2007-12-19"<br>
|
|
* "2007-12-19T10:20+0300<br>
|
|
* "2007-12-19T10:20:30+0300<br>
|
|
* "2007-12-19T10:20:30.567+0300<br>
|
|
* Additionally a timezone offset of "+0000" can be substituted as "Z".<br>
|
|
* Parsing is done in a fuzzy way. If there is an illegal character somewhere in
|
|
* the String, the date parsed so far will be returned, e.g. the input
|
|
* "2007-12-19FOO" would return a date that represents "2007-12-19".
|
|
*
|
|
* @param s
|
|
* @return
|
|
* @throws ParseException
|
|
*/
|
|
public static Date parseISO8601(String s) throws ParseException {
|
|
Calendar cal = Calendar.getInstance(TZ_GMT, Locale.US);
|
|
cal.clear();
|
|
|
|
// split 2007-12-19T10:20:30.789+0500 into its parts
|
|
// correct: yyyy['-'MM['-'dd['T'HH':'MM[':'ss['.'SSS]]('Z'|ZZZZZ)]]]
|
|
StringTokenizer t = new StringTokenizer(s, "-T:.Z+", true);
|
|
if (s == null || t.countTokens() == 0)
|
|
throw new ParseException("parseISO8601: Cannot parse '" + s + "'", 0);
|
|
|
|
try {
|
|
// year
|
|
cal.set(Calendar.YEAR, Integer.parseInt(t.nextToken()));
|
|
// month
|
|
if (t.nextToken().equals("-")) {
|
|
cal.set(Calendar.MONTH, Integer.parseInt(t.nextToken()) - 1);
|
|
} else {
|
|
return cal.getTime();
|
|
}
|
|
// day
|
|
if (t.nextToken().equals("-")) {
|
|
cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(t.nextToken()));
|
|
} else {
|
|
return cal.getTime();
|
|
}
|
|
// The standard says: if there is an hour there has to be a minute and a
|
|
// timezone token, too.
|
|
// hour
|
|
if (t.nextToken().equals("T")) {
|
|
int hour = Integer.parseInt(t.nextToken());
|
|
// no error, got hours
|
|
int min = 0;
|
|
int sec = 0;
|
|
int msec = 0;
|
|
if (t.nextToken().equals(":")) {
|
|
min = Integer.parseInt(t.nextToken());
|
|
// no error, got minutes
|
|
// need TZ or seconds
|
|
String token = t.nextToken();
|
|
if (token.equals(":")) {
|
|
sec = Integer.parseInt(t.nextToken());
|
|
// need millisecs or TZ
|
|
token = t.nextToken();
|
|
if (token.equals(".")) {
|
|
msec = Integer.parseInt(t.nextToken());
|
|
// need TZ
|
|
token = t.nextToken();
|
|
}
|
|
}
|
|
|
|
// check for TZ data
|
|
int offset;
|
|
if (token.equals("Z")) {
|
|
offset = 0;
|
|
} else {
|
|
int sign = 0;
|
|
if (token.equals("+")) {
|
|
sign = 1;
|
|
} else if (token.equals("-")) {
|
|
sign = -1;
|
|
} else {
|
|
// no legal TZ offset found
|
|
return cal.getTime();
|
|
}
|
|
offset = sign * Integer.parseInt(t.nextToken()) * 10 * 3600;
|
|
}
|
|
cal.set(Calendar.ZONE_OFFSET, offset);
|
|
}
|
|
cal.set(Calendar.HOUR_OF_DAY, hour);
|
|
cal.set(Calendar.MINUTE, min);
|
|
cal.set(Calendar.SECOND, sec);
|
|
cal.set(Calendar.MILLISECOND, msec);
|
|
}
|
|
} catch (NoSuchElementException e) {
|
|
// ignore this as it is perfectly fine to have non-complete date in this format
|
|
} catch (Exception e) {
|
|
// catch all Exceptions and return what we parsed so far
|
|
serverLog.logInfo("SERVER", "parseISO8601: DATE ERROR with: '" + s + "' got so far: '" + cal.toString());
|
|
}
|
|
|
|
// in case we couldn't even parse a year
|
|
if (!cal.isSet(Calendar.YEAR))
|
|
throw new ParseException("parseISO8601: Cannot parse '" + s + "'", 0);
|
|
|
|
return cal.getTime();
|
|
}
|
|
|
|
/**
|
|
* Note: The short day format doesn't include any timezone information. This method
|
|
* transforms the date into the GMT/UTC timezone. Example: If the local system time is,
|
|
* 2007-12-18 01:15:00 +0200, then the resulting String will be "2007-12-17".
|
|
* In case you need a format with a timezon offset, use {@link #formatShortDay(TimeZone)}
|
|
* @return a String representation of the current system date in GMT using the
|
|
* short day format, e.g. "20071218".
|
|
*/
|
|
public static String formatShortDay() {
|
|
return format(FORMAT_SHORT_DAY, new Date());
|
|
}
|
|
|
|
/**
|
|
* @see #formatShortDay()
|
|
* @param date the Date to transform
|
|
*/
|
|
public static String formatShortDay(Date date) {
|
|
return format(FORMAT_SHORT_DAY, date);
|
|
}
|
|
|
|
/**
|
|
* This should only be used, if you need a short date String that needs to be aligned to
|
|
* a special timezone other than GMT/UTC. Be aware that a receiver won't be able to
|
|
* recreate the original Date without additional timezone information.
|
|
* @see #formatShortDay()
|
|
* @param date the Date to transform
|
|
* @param tz a TimeZone the resulting date String should be aligned to.
|
|
*/
|
|
public static String formatShortDay(Date date, TimeZone tz) {
|
|
return format(FORMAT_SHORT_DAY, date, tz);
|
|
}
|
|
|
|
/**
|
|
* Parse a String representation of a Date in short day format assuming the date
|
|
* is aligned to the GMT/UTC timezone. An example for such a date string is "20071218".
|
|
* @see #formatShortDay()
|
|
* @throws ParseException The exception is thrown if an error occured during while parsing
|
|
* the String.
|
|
*/
|
|
public static Date parseShortDay(String timeString) throws ParseException {
|
|
return parse(FORMAT_SHORT_DAY, timeString);
|
|
}
|
|
|
|
/**
|
|
* Returns the current date in short second format which is a fixed width (14 chars)
|
|
* String including the date and the time like "20071218233510". The result is in GMT/UTC.
|
|
* @see #formatShortDay()
|
|
*/
|
|
public static String formatShortSecond() {
|
|
return formatShortSecond(new Date());
|
|
}
|
|
|
|
/**
|
|
* Identical to {@link #formatShortDay(Date)}, but for short second format.
|
|
*/
|
|
public static String formatShortSecond(Date date) {
|
|
return format(FORMAT_SHORT_SECOND, date);
|
|
}
|
|
|
|
/**
|
|
* Identical to {@link #formatShortDay(Date, TimeZone)}, but for short second format.
|
|
*/
|
|
public static String formatShortSecond(Date date, TimeZone tz) {
|
|
return format(FORMAT_SHORT_SECOND, date, tz);
|
|
}
|
|
|
|
//TODO check the following 2 parse methods for correct use (GMT vs. different timezone)
|
|
/**
|
|
* Like {@link #parseShortDay(String)}, but for the "short second" format which is short date
|
|
* plus a 6 digit day time value, like "20071218233510". The String should be in GMT/UTC to
|
|
* get a correct Date.
|
|
*/
|
|
public static Date parseShortSecond(String timeString) throws ParseException {
|
|
return parse(FORMAT_SHORT_SECOND, timeString);
|
|
}
|
|
|
|
/**
|
|
* Like {@link #parseShortSecond(String)} using additional timezone information provided in an
|
|
* offset String, like "+0100" for CET.
|
|
*/
|
|
public static Date parseShortSecond(String remoteTimeString, String remoteUTCOffset) {
|
|
// FIXME: This method returns an incorrect date, check callers!
|
|
// ex: de.anomic.server.serverDate.parseShortSecond("20070101120000", "+0200").toGMTString()
|
|
// => 1 Jan 2007 13:00:00 GMT
|
|
if (remoteTimeString == null || remoteTimeString.length() == 0) { return new Date(); }
|
|
if (remoteUTCOffset == null || remoteUTCOffset.length() == 0) { return new Date(); }
|
|
try {
|
|
return new Date(parse(FORMAT_SHORT_SECOND, remoteTimeString).getTime() - serverDate.UTCDiff() + serverDate.UTCDiff(remoteUTCOffset));
|
|
} catch (java.text.ParseException e) {
|
|
serverLog.logFinest("parseUniversalDate", e.getMessage() + ", remoteTimeString=[" + remoteTimeString + "]");
|
|
return new Date();
|
|
} catch (java.lang.NumberFormatException e) {
|
|
serverLog.logFinest("parseUniversalDate", e.getMessage() + ", remoteTimeString=[" + remoteTimeString + "]");
|
|
return new Date();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Format a time inteval in milliseconds into a String of the form
|
|
* X 'day'['s'] HH':'mm
|
|
*/
|
|
public static String formatInterval(long millis) {
|
|
try {
|
|
long mins = millis / 60000;
|
|
|
|
StringBuffer uptime = new StringBuffer();
|
|
|
|
int uptimeDays = (int) (Math.floor(mins/1440));
|
|
int uptimeHours = (int) (Math.floor(mins/60)%24);
|
|
int uptimeMins = (int) mins%60;
|
|
|
|
uptime.append(uptimeDays)
|
|
.append(((uptimeDays == 1)?" day ":" days "))
|
|
.append((uptimeHours < 10)?"0":"")
|
|
.append(uptimeHours)
|
|
.append(":")
|
|
.append((uptimeMins < 10)?"0":"")
|
|
.append(uptimeMins);
|
|
|
|
return uptime.toString();
|
|
} catch (Exception e) {
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
/** called by all public format...(..., TimeZone) methods */
|
|
private static String format(SimpleDateFormat format, Date date, TimeZone tz) {
|
|
TimeZone bakTZ = format.getTimeZone();
|
|
String result;
|
|
|
|
synchronized (format) {
|
|
format.setTimeZone(tz == null ? TZ_GMT : tz);
|
|
result = format.format(date);
|
|
format.setTimeZone(bakTZ);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/** called by all public format...(...) methods */
|
|
private static String format(SimpleDateFormat format, Date date) {
|
|
synchronized (format) {
|
|
return format.format(date);
|
|
}
|
|
}
|
|
|
|
/** calles by all public parse...(...) methods */
|
|
private static Date parse(SimpleDateFormat format, String dateString) throws ParseException {
|
|
synchronized (format) {
|
|
return format.parse(dateString);
|
|
}
|
|
}
|
|
|
|
// statics
|
|
public final static long secondMillis = 1000;
|
|
public final static long minuteMillis = 60 * secondMillis;
|
|
public final static long hourMillis = 60 * minuteMillis;
|
|
public final static long dayMillis = 24 * hourMillis;
|
|
public final static long normalyearMillis = 365 * dayMillis;
|
|
public final static long leapyearMillis = 366 * dayMillis;
|
|
public final static int january = 31, normalfebruary = 28, leapfebruary = 29, march = 31,
|
|
april = 30, may = 31, june = 30, july = 31, august = 31,
|
|
september = 30, october = 31, november = 30, december = 31;
|
|
public final static int[] dimnormal = {january, normalfebruary, march, april, may, june, july, august, september, october, november, december};
|
|
public final static int[] dimleap = {january, leapfebruary, march, april, may, june, july, august, september, october, november, december};
|
|
public final static String[] wkday = {"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
|
|
//private final static String[] month = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
|
|
|
|
// find out time zone and DST offset
|
|
private static Calendar thisCalendar = Calendar.getInstance();
|
|
|
|
// pre-calculation of time tables
|
|
private final static long[] dimnormalacc, dimleapacc;
|
|
private static long[] utimeyearsacc;
|
|
static {
|
|
long millis = 0;
|
|
utimeyearsacc = new long[67];
|
|
for (int i = 0; i < 67; i++) {
|
|
utimeyearsacc[i] = millis;
|
|
millis += ((i & 3) == 0) ? leapyearMillis : normalyearMillis;
|
|
}
|
|
millis = 0;
|
|
dimnormalacc = new long[12];
|
|
for (int i = 0; i < 12; i++) {
|
|
dimnormalacc[i] = millis;
|
|
millis += (dayMillis * dimnormal[i]);
|
|
}
|
|
millis = 0;
|
|
dimleapacc = new long[12];
|
|
for (int i = 0; i < 12; i++) {
|
|
dimleapacc[i] = millis;
|
|
millis += (dayMillis * dimleap[i]);
|
|
}
|
|
}
|
|
|
|
// class variables
|
|
private int milliseconds, seconds, minutes, hours, days, months, years; // years since 1970
|
|
private int dow; // day-of-week
|
|
private long utime;
|
|
|
|
public static String UTCDiffString() {
|
|
// we express the UTC Difference in 5 digits:
|
|
// SHHMM
|
|
// S ::= '+'|'-'
|
|
// HH ::= '00'|'01'|'02'|'03'|'04'|'05'|'06'|'07'|'08'|'09'|'10'|'11'|'12'
|
|
// MM ::= '00'|'15'|'30'|'45'
|
|
// since there are some places on earth where there is a time shift of half an hour
|
|
// we need too show also the minutes of the time shift
|
|
// Examples: http://www.timeanddate.com/library/abbreviations/timezones/
|
|
long offsetHours = UTCDiff();
|
|
int om = Math.abs((int) (offsetHours / minuteMillis)) % 60;
|
|
int oh = Math.abs((int) (offsetHours / hourMillis));
|
|
String diff = Integer.toString(om);
|
|
if (diff.length() < 2) diff = "0" + diff;
|
|
diff = Integer.toString(oh) + diff;
|
|
if (diff.length() < 4) diff = "0" + diff;
|
|
if (offsetHours >= 0) {
|
|
return "+" + diff;
|
|
} else {
|
|
return "-" + diff;
|
|
}
|
|
}
|
|
|
|
public static long UTCDiff() {
|
|
// DST_OFFSET is dependent on the time of the Calendar, so it has to be updated
|
|
// to get the correct current offset
|
|
thisCalendar.setTimeInMillis(System.currentTimeMillis());
|
|
long zoneOffsetHours = thisCalendar.get(Calendar.ZONE_OFFSET);
|
|
long DSTOffsetHours = thisCalendar.get(Calendar.DST_OFFSET);
|
|
return zoneOffsetHours + DSTOffsetHours;
|
|
}
|
|
|
|
public static long UTCDiff(String diffString) {
|
|
if (diffString.length() != 5) throw new IllegalArgumentException("UTC String malformed (wrong size):" + diffString);
|
|
boolean ahead = true;
|
|
if (diffString.charAt(0) == '+') ahead = true;
|
|
else if (diffString.charAt(0) == '-') ahead = false;
|
|
else throw new IllegalArgumentException("UTC String malformed (wrong sign):" + diffString);
|
|
long oh = Long.parseLong(diffString.substring(1, 3));
|
|
long om = Long.parseLong(diffString.substring(3));
|
|
return ((ahead) ? (long) 1 : (long) -1) * (oh * hourMillis + om * minuteMillis);
|
|
}
|
|
|
|
|
|
public static long correctedUTCTime() {
|
|
return System.currentTimeMillis() - UTCDiff();
|
|
}
|
|
|
|
public serverDate() {
|
|
this(System.currentTimeMillis());
|
|
}
|
|
|
|
public serverDate(long utime) {
|
|
// set the time as the difference, measured in milliseconds,
|
|
// between the current time and midnight, January 1, 1970 UTC/GMT
|
|
this.utime = utime;
|
|
dow = (int) (((utime / dayMillis) + 3) % 7);
|
|
years = (int) (utime / normalyearMillis); // a guess
|
|
if (utime < utimeyearsacc[years]) years--; // the correction
|
|
long remain = utime - utimeyearsacc[years];
|
|
months = (int) (remain / (29 * dayMillis)); // a guess
|
|
if (months > 11) months = 11;
|
|
if ((years & 3) == 0) {
|
|
if (remain < dimleapacc[months]) months--; // correction
|
|
remain = remain - dimleapacc[months];
|
|
} else {
|
|
if (remain < dimnormalacc[months]) months--; // correction
|
|
remain = remain - dimnormalacc[months];
|
|
}
|
|
days = (int) (remain / dayMillis); remain = remain % dayMillis;
|
|
hours = (int) (remain / hourMillis); remain = remain % hourMillis;
|
|
minutes = (int) (remain / minuteMillis); remain = remain % minuteMillis;
|
|
seconds = (int) (remain / secondMillis); remain = remain % secondMillis;
|
|
milliseconds = (int) remain;
|
|
}
|
|
|
|
private void calcUTime() {
|
|
this.utime = utimeyearsacc[years] + dimleapacc[months - 1] + dayMillis * (days - 1) +
|
|
hourMillis * hours + minuteMillis * minutes + secondMillis * seconds + milliseconds;
|
|
this.dow = (int) (((utime / dayMillis) + 3) % 7);
|
|
}
|
|
|
|
public serverDate(String datestring) throws java.text.ParseException {
|
|
// parse a date string; othervise throw a java.text.ParseException
|
|
if ((datestring.length() == 14) || (datestring.length() == 17)) {
|
|
// parse a ShortString
|
|
try {years = Integer.parseInt(datestring.substring(0, 4)) - 1970;} catch (NumberFormatException e) {
|
|
throw new java.text.ParseException("serverDate '" + datestring + "' wrong year", 0);
|
|
}
|
|
if (years < 0) throw new java.text.ParseException("serverDate '" + datestring + "' wrong year", 0);
|
|
try {months = Integer.parseInt(datestring.substring(4, 6)) - 1;} catch (NumberFormatException e) {
|
|
throw new java.text.ParseException("serverDate '" + datestring + "' wrong month", 4);
|
|
}
|
|
if ((months < 0) || (months > 11)) throw new java.text.ParseException("serverDate '" + datestring + "' wrong month", 4);
|
|
try {days = Integer.parseInt(datestring.substring(6, 8)) - 1;} catch (NumberFormatException e) {
|
|
throw new java.text.ParseException("serverDate '" + datestring + "' wrong day", 6);
|
|
}
|
|
if ((days < 0) || (days > 30)) throw new java.text.ParseException("serverDate '" + datestring + "' wrong day", 6);
|
|
try {hours = Integer.parseInt(datestring.substring(8, 10));} catch (NumberFormatException e) {
|
|
throw new java.text.ParseException("serverDate '" + datestring + "' wrong hour", 8);
|
|
}
|
|
if ((hours < 0) || (hours > 23)) throw new java.text.ParseException("serverDate '" + datestring + "' wrong hour", 8);
|
|
try {minutes = Integer.parseInt(datestring.substring(10, 12));} catch (NumberFormatException e) {
|
|
throw new java.text.ParseException("serverDate '" + datestring + "' wrong minute", 10);
|
|
}
|
|
if ((minutes < 0) || (minutes > 59)) throw new java.text.ParseException("serverDate '" + datestring + "' wrong minute", 10);
|
|
try {seconds = Integer.parseInt(datestring.substring(12, 14));} catch (NumberFormatException e) {
|
|
throw new java.text.ParseException("serverDate '" + datestring + "' wrong second", 12);
|
|
}
|
|
if ((seconds < 0) || (seconds > 59)) throw new java.text.ParseException("serverDate '" + datestring + "' wrong second", 12);
|
|
if (datestring.length() == 17) {
|
|
try {milliseconds = Integer.parseInt(datestring.substring(14, 17));} catch (NumberFormatException e) {
|
|
throw new java.text.ParseException("serverDate '" + datestring + "' wrong millisecond", 14);
|
|
}
|
|
} else {
|
|
milliseconds = 0;
|
|
}
|
|
if ((milliseconds < 0) || (milliseconds > 999)) throw new java.text.ParseException("serverDate '" + datestring + "' wrong millisecond", 14);
|
|
calcUTime();
|
|
return;
|
|
}
|
|
throw new java.text.ParseException("serverDate '" + datestring + "' format unknown", 0);
|
|
}
|
|
|
|
public String toString() {
|
|
return "utime=" + utime + ", year=" + (years + 1970) +
|
|
", month=" + (months + 1) + ", day=" + (days + 1) +
|
|
", hour=" + hours + ", minute=" + minutes +
|
|
", second=" + seconds + ", millis=" + milliseconds +
|
|
", day-of-week=" + wkday[dow];
|
|
}
|
|
|
|
public String toShortString(boolean millis) {
|
|
// returns a "yyyyMMddHHmmssSSS"
|
|
byte[] result = new byte[(millis) ? 17 : 14];
|
|
int x = 1970 + years;
|
|
result[ 0] = (byte) (48 + (x / 1000)); x = x % 1000;
|
|
result[ 1] = (byte) (48 + (x / 100)); x = x % 100;
|
|
result[ 2] = (byte) (48 + (x / 10)); x = x % 10;
|
|
result[ 3] = (byte) (48 + x);
|
|
x = months + 1;
|
|
result[ 4] = (byte) (48 + (x / 10));
|
|
result[ 5] = (byte) (48 + (x % 10));
|
|
x = days + 1;
|
|
result[ 6] = (byte) (48 + (x / 10));
|
|
result[ 7] = (byte) (48 + (x % 10));
|
|
result[ 8] = (byte) (48 + (hours / 10));
|
|
result[ 9] = (byte) (48 + (hours % 10));
|
|
result[10] = (byte) (48 + (minutes / 10));
|
|
result[11] = (byte) (48 + (minutes % 10));
|
|
result[12] = (byte) (48 + (seconds / 10));
|
|
result[13] = (byte) (48 + (seconds % 10));
|
|
if (millis) {
|
|
x = milliseconds;
|
|
result[14] = (byte) (48 + (x / 100)); x = x % 100;
|
|
result[15] = (byte) (48 + (x / 10)); x = x % 10;
|
|
result[16] = (byte) (48 + x);
|
|
}
|
|
return new String(result);
|
|
}
|
|
|
|
public static long remainingTime(long start, long due, long minimum) {
|
|
if (due < 0) return -1;
|
|
long r = due + start - System.currentTimeMillis();
|
|
if (r <= 0) return minimum; else return r;
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
//System.out.println("kelondroDate is (" + new kelondroDate().toString() + ")");
|
|
System.out.println("offset is " + (UTCDiff()/1000/60/60) + " hours, javaDate is " + new Date() + ", correctedDate is " + new Date(correctedUTCTime()));
|
|
System.out.println("serverDate : " + new serverDate().toShortString(false));
|
|
System.out.println(" javaDate : " + formatShortSecond());
|
|
System.out.println("serverDate : " + new serverDate().toString());
|
|
System.out.println(" JavaDate : " + DateFormat.getDateInstance().format(new Date()));
|
|
System.out.println("serverDate0: " + new serverDate(0).toShortString(false));
|
|
System.out.println(" JavaDate0: " + FORMAT_SHORT_SECOND.format(new Date(0)));
|
|
System.out.println("serverDate0: " + new serverDate(0).toString());
|
|
System.out.println(" JavaDate0: " + DateFormat.getDateInstance().format(new Date(0)));
|
|
// parse test
|
|
try {
|
|
System.out.println("serverDate re-parse short: " + new serverDate(new serverDate().toShortString(false)).toShortString(true));
|
|
System.out.println("serverDate re-parse long : " + new serverDate(new serverDate().toShortString(true)).toShortString(true));
|
|
} catch (java.text.ParseException e) {
|
|
System.out.println("Parse Exception: " + e.getMessage() + ", pos " + e.getErrorOffset());
|
|
}
|
|
//String testresult;
|
|
int cycles = 10000;
|
|
long start;
|
|
|
|
String[] testresult = new String[10000];
|
|
start = System.currentTimeMillis();
|
|
for (int i = 0; i < cycles; i++) testresult[i] = new serverDate().toShortString(false);
|
|
System.out.println("time for " + cycles + " calls to serverDate:" + (System.currentTimeMillis() - start) + " milliseconds");
|
|
|
|
start = System.currentTimeMillis();
|
|
for (int i = 0; i < cycles; i++) testresult[i] = FORMAT_SHORT_SECOND.format(new Date());
|
|
System.out.println("time for " + cycles + " calls to javaDate:" + (System.currentTimeMillis() - start) + " milliseconds");
|
|
}
|
|
}
|