![JAR search and dependency download from the Maven repository](/logo.png)
org.dsa.iot.dslink.util.TimeUtils Maven / Gradle / Ivy
package org.dsa.iot.dslink.util;
import java.text.*;
import java.util.*;
/**
* @author Samuel Grenier
*/
public class TimeUtils {
private static Calendar calendarCache;
public static final int MILLIS_MINUTE = 60 * 1000;
public static final int MILLIS_HOUR = 60 * MILLIS_MINUTE;
private static final Map timezones = new HashMap();
private static final ThreadLocal FORMAT_TIME_ZONE;
private static final ThreadLocal FORMAT;
private static final String TIME_PATTERN_TZ;
private static final String TIME_PATTERN;
private static final String TIME_ZONE_COLON;
private static final String TIME_ZONE;
static {
long currentTime = new Date().getTime();
int offset = TimeZone.getDefault().getOffset(currentTime) / (1000 * 60);
String s = "+";
if (offset < 0) {
offset = -offset;
s = "-";
}
int hh = offset / 60;
int mm = offset % 60;
TIME_ZONE_COLON = s + (hh < 10 ? "0" : "") + hh + ":" + (mm < 10 ? "0" : "") + mm;
TIME_ZONE = TIME_ZONE_COLON.replace(":", "");
TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS";
TIME_PATTERN_TZ = TIME_PATTERN + "Z";
FORMAT = new ThreadLocal() {
@Override
public DateFormat initialValue() {
return new SimpleDateFormat(getTimePattern());
}
};
FORMAT_TIME_ZONE = new ThreadLocal() {
@Override
public DateFormat initialValue() {
return new SimpleDateFormat(getTimePatternTz());
}
};
}
/**
* Do not allow instantiation.
*/
private TimeUtils() {
}
/**
* @deprecated
*/
public static String getTimePatternTz() {
return TIME_PATTERN_TZ;
}
/**
* @deprecated
*/
public static String getTimePattern() {
return TIME_PATTERN;
}
public static String format(long time) {
return encode(time, true).toString();
}
public static String format(Date time) {
return encode(time.getTime(), true).toString();
}
public static Date parseTz(String time) {
return new Date(decode(time));
}
/**
* @deprecated
*/
public static String fixTime(String time) {
return time;
}
/**
* Adds or subtracts the corresponding time field, does not
* perform any alignment.
*
* @param count The quantity to change, can be negative.
* @param timestamp The calendar to modify.
* @return The timestamp parameter.
*/
public static Calendar addDays(int count, Calendar timestamp) {
timestamp.add(Calendar.DATE, count);
return timestamp;
}
/**
* Adds or subtracts the corresponding time field, does not
* perform any alignment.
*
* @param count The quantity to change, can be negative.
* @param timestamp The calendar to modify.
* @return The timestamp parameter.
*/
public static Calendar addHours(int count, Calendar timestamp) {
timestamp.add(Calendar.HOUR_OF_DAY, count);
return timestamp;
}
/**
* Adds or subtracts the corresponding time field, does not
* perform any alignment.
*
* @param count The quantity to change, can be negative.
* @param timestamp The calendar to modify.
* @return The timestamp parameter.
*/
public static Calendar addMinutes(int count, Calendar timestamp) {
timestamp.add(Calendar.MINUTE, count);
return timestamp;
}
/**
* Adds or subtracts the corresponding time field, does not
* perform any alignment.
*
* @param count The quantity to change, can be negative.
* @param timestamp The calendar to modify.
* @return The timestamp parameter.
*/
public static Calendar addMonths(int count, Calendar timestamp) {
timestamp.add(Calendar.MONTH, count);
return timestamp;
}
/**
* Adds or subtracts the corresponding time field, does not
* perform any alignment.
*
* @param count The quantity to change, can be negative.
* @param timestamp The calendar to modify.
* @return The timestamp parameter.
*/
public static Calendar addSeconds(int count, Calendar timestamp) {
timestamp.add(Calendar.SECOND, count);
return timestamp;
}
/**
* Adds or subtracts the corresponding time field, does not
* perform any alignment.
*
* @param count The quantity to change, can be negative.
* @param timestamp The calendar to modify.
* @return The timestamp parameter.
*/
public static Calendar addWeeks(int count, Calendar timestamp) {
return addDays(count * 7, timestamp);
}
/**
* Adds or subtracts the corresponding time field, does not
* perform any alignment.
*
* @param count The quantity to change, can be negative.
* @param timestamp The calendar to modify.
* @return The timestamp parameter.
*/
public static Calendar addYears(int count, Calendar timestamp) {
timestamp.add(Calendar.YEAR, count);
return timestamp;
}
/**
* Aligns the time fields to the start of the day.
*
* @param timestamp The calendar to align.
* @return The parameter.
*/
public static Calendar alignDay(Calendar timestamp) {
timestamp.set(Calendar.HOUR_OF_DAY, 0);
timestamp.set(Calendar.MINUTE, 0);
timestamp.set(Calendar.SECOND, 0);
timestamp.set(Calendar.MILLISECOND, 0);
return timestamp;
}
/**
* Aligns the time fields to the start of given interval.
*
* @param interval The number of days in the interval to align to.
* @param timestamp The calendar to align.
* @return The calendar parameter, aligned.
*/
public static Calendar alignDays(int interval, Calendar timestamp) {
int value = timestamp.get(Calendar.DATE);
value = value - (value % interval);
timestamp.set(Calendar.DATE, value);
return alignDay(timestamp);
}
/**
* Aligns the time fields to the start of the hour.
*
* @param timestamp The calendar to align.
* @return The parameter.
*/
public static Calendar alignHour(Calendar timestamp) {
timestamp.set(Calendar.MINUTE, 0);
timestamp.set(Calendar.SECOND, 0);
timestamp.set(Calendar.MILLISECOND, 0);
return timestamp;
}
/**
* Aligns the time fields to the start of given interval.
*
* @param interval The number of hours in the interval to align to.
* @param timestamp The calendar to align.
* @return The calendar parameter, aligned.
*/
public static Calendar alignHours(int interval, Calendar timestamp) {
int value = timestamp.get(Calendar.HOUR_OF_DAY);
value = value - (value % interval);
timestamp.set(Calendar.HOUR_OF_DAY, value);
return alignHour(timestamp);
}
/**
* Aligns the time fields to the start of the minute.
*
* @param timestamp The calendar to align.
* @return The parameter.
*/
public static Calendar alignMinute(Calendar timestamp) {
timestamp.set(Calendar.SECOND, 0);
timestamp.set(Calendar.MILLISECOND, 0);
return timestamp;
}
/**
* Aligns the time fields to the start of given interval.
*
* @param interval The number of minutes in the interval to align to.
* @param timestamp The calendar to align.
* @return The calendar parameter, aligned.
*/
public static Calendar alignMinutes(int interval, Calendar timestamp) {
int value = timestamp.get(Calendar.MINUTE);
value = value - (value % interval);
timestamp.set(Calendar.MINUTE, value);
return alignMinute(timestamp);
}
/**
* Aligns the time fields to the start of the month.
*
* @param timestamp The calendar to align.
* @return The parameter.
*/
public static Calendar alignMonth(Calendar timestamp) {
timestamp.set(Calendar.DAY_OF_MONTH, 1);
return alignDay(timestamp);
}
/**
* Aligns the time fields to the start of the second.
*
* @param timestamp The calendar to align.
* @return The parameter.
*/
public static Calendar alignSecond(Calendar timestamp) {
timestamp.set(Calendar.MILLISECOND, 0);
return timestamp;
}
/**
* Aligns the time fields to the start of given interval.
*
* @param interval The number of seconds in the interval to align to.
* @param timestamp The calendar to align.
* @return The calendar parameter, aligned.
*/
public static Calendar alignSeconds(int interval, Calendar timestamp) {
int value = timestamp.get(Calendar.SECOND);
value = value - (value % interval);
timestamp.set(Calendar.SECOND, value);
return alignSecond(timestamp);
}
/**
* Aligns the time fields to the start of the week.
*
* @param timestamp The calendar to align.
* @return The parameter.
*/
public static Calendar alignWeek(Calendar timestamp) {
timestamp = alignDay(timestamp);
int dayOfWeek = timestamp.get(Calendar.DAY_OF_WEEK);
int offset = 1 - dayOfWeek;
if (offset == 0) {
return timestamp;
}
return addDays(offset, timestamp);
}
/**
* Aligns the time fields to the start of the year.
*
* @param timestamp The calendar to align.
* @return The parameter.
*/
public static Calendar alignYear(Calendar timestamp) {
timestamp.set(Calendar.MONTH, 0);
return alignMonth(timestamp);
}
/**
* Converts the characters into an int.
*/
private static int convertDigits(char tens, char ones) {
return (toDigit(tens) * 10) + toDigit(ones);
}
/**
* Converts the characters into an int.
*/
private static int convertDigits(char thousands, char hundreds, char tens, char ones) {
return toDigit(thousands) * 1000 +
toDigit(hundreds) * 100 +
toDigit(tens) * 10 +
toDigit(ones);
}
/**
* This is a convenience that uses reuses and recycles a calendar instance to
* get the time in millis.
*/
public static long decode(String timestamp) {
Calendar cal = reuseCalendar();
decode(timestamp, cal);
long millis = cal.getTimeInMillis();
recycleCalendar(cal);
return millis;
}
/**
* Converts a DSA encoded timestamp into a Java Calendar. DSA encoding is based
* on ISO 8601 but allows for an unspecified timezone.
*
* @param timestamp The encoded timestamp.
* @param calendar The instance to decode into and returnt, may be null. If the
* timestamp does not specify a timezone, the zone in this
* instance will be used.
*/
public static Calendar decode(String timestamp, Calendar calendar) {
if (calendar == null) {
calendar = reuseCalendar();
}
try {
char[] chars = timestamp.toCharArray();
int idx = 0;
int year = convertDigits(chars[idx++], chars[idx++], chars[idx++], chars[idx++]);
validateChar(chars[idx++], '-');
int month = convertDigits(chars[idx++], chars[idx++]) - 1;
validateChar(chars[idx++], '-');
int day = convertDigits(chars[idx++], chars[idx++]);
validateChar(chars[idx++], 'T');
int hour = convertDigits(chars[idx++], chars[idx++]);
validateChar(chars[idx++], ':');
int minute = convertDigits(chars[idx++], chars[idx++]);
validateChar(chars[idx++], ':');
int second = convertDigits(chars[idx++], chars[idx++]);
int millis = 0;
if ((chars.length > idx) && (chars[idx] == '.')) {
idx++;
millis = convertDigits('0', chars[idx++], chars[idx++], chars[idx++]);
}
//more than 3 millis digits is possible
while ((chars.length > idx)
&& (chars[idx] != 'Z')
&& (chars[idx] != '+')
&& (chars[idx] != '-')) {
idx++;
}
// timezone offset sign
if (idx < chars.length) {
char sign = chars[idx++];
if (sign == 'Z') {
calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
} else {
int tzOff;
if (sign != '+' && sign != '-')
throw new Exception();
int hrOff = convertDigits(chars[idx++], chars[idx++]);
int minOff = 0;
//minutes are optional in 8601
if (idx < chars.length) { //minutes optional
validateChar(chars[idx++], ':');
minOff = convertDigits(chars[idx++], chars[idx++]);
}
tzOff = (hrOff * MILLIS_HOUR) + (minOff * MILLIS_MINUTE);
if (sign == '-') {
tzOff *= -1;
}
TimeZone timezone = calendar.getTimeZone();
int localOffset = timezone.getOffset(calendar.getTimeInMillis());
if (localOffset != tzOff) {
String timeZoneName = "Offset" + tzOff;
synchronized (timezones) {
timezone = timezones.get(timeZoneName);
if (timezone == null) {
timezone = new SimpleTimeZone(tzOff, timeZoneName);
timezones.put(timeZoneName, timezone);
}
}
calendar.setTimeZone(timezone);
}
}
}
calendar.set(year, month, day, hour, minute, second);
calendar.set(Calendar.MILLISECOND, millis);
} catch (Exception x) {
throw new IllegalArgumentException("Invalid timestamp: " + timestamp);
}
return calendar;
}
/**
* Converts a Java Calendar into a DSA encoded timestamp. DSA encoding is based
* on ISO 8601 but allows the timezone offset to not be specified.
*
* @param timestamp What to encode.
* @param encodeTzOffset Whether or not to encode the timezone offset.
* @return The buffer containing the encoding.
*/
public static StringBuilder encode(long timestamp, boolean encodeTzOffset) {
Calendar cal = reuseCalendar(timestamp);
StringBuilder buf = encode(cal, encodeTzOffset, new StringBuilder());
recycleCalendar(cal);
return buf;
}
/**
* Converts a Java Calendar into a DSA encoded timestamp. DSA encoding is based
* on ISO 8601 but allows the timezone offset to not be specified.
*
* @param calendar The calendar representing the timestamp to encode.
* @param encodeTzOffset Whether or not to encode the timezone offset.
* @param buf The buffer to append the encoded timestamp and return, can be null.
* @return The buf argument, or if that was null, a new StringBuilder.
*/
public static StringBuilder encode(
Calendar calendar, boolean encodeTzOffset, StringBuilder buf) {
if (buf == null) {
buf = new StringBuilder();
}
long millis = calendar.getTimeInMillis();
int tmp = calendar.get(Calendar.YEAR);
buf.append(tmp).append('-');
//month
tmp = calendar.get(Calendar.MONTH) + 1;
if (tmp < 10) buf.append('0');
buf.append(tmp).append('-');
//date
tmp = calendar.get(Calendar.DAY_OF_MONTH);
if (tmp < 10) buf.append('0');
buf.append(tmp).append('T');
//hour
tmp = calendar.get(Calendar.HOUR_OF_DAY);
if (tmp < 10) buf.append('0');
buf.append(tmp).append(':');
//minute
tmp = calendar.get(Calendar.MINUTE);
if (tmp < 10) buf.append('0');
buf.append(tmp).append(':');
//second
tmp = calendar.get(Calendar.SECOND);
if (tmp < 10) buf.append('0');
buf.append(tmp).append('.');
//millis
tmp = calendar.get(Calendar.MILLISECOND);
if (tmp < 10) buf.append('0');
if (tmp < 100) buf.append('0');
buf.append(tmp);
if (encodeTzOffset) {
int offset = calendar.getTimeZone().getOffset(millis);
if (offset == 0) {
buf.append('Z');
} else {
int hrOff = Math.abs(offset / MILLIS_HOUR);
int minOff = Math.abs((offset % MILLIS_HOUR) / MILLIS_MINUTE);
if (offset < 0) buf.append('-');
else buf.append('+');
if (hrOff < 10) buf.append('0');
buf.append(hrOff);
buf.append(':');
if (minOff < 10) buf.append('0');
buf.append(minOff);
}
}
return buf;
}
/**
* Return a calendar instance for reuse.
*/
public static void recycleCalendar(Calendar cal) {
synchronized (TimeUtils.class) {
calendarCache = cal;
}
}
/**
* Attempts to reuse a calendar instance, the timezone will be set to
* TimeZone.getDefault().
*/
public static Calendar reuseCalendar() {
Calendar cal = null;
synchronized (TimeUtils.class) {
cal = calendarCache;
calendarCache = null;
}
if (cal == null) {
cal = Calendar.getInstance();
} else {
cal.setTimeZone(TimeZone.getDefault());
}
return cal;
}
/**
* Attempts to reuse a calendar instance and sets the time in millis to the argument
* the timezone to TimeZone.getDefault().
*/
public static Calendar reuseCalendar(long timestamp) {
Calendar cal = null;
synchronized (TimeUtils.class) {
cal = calendarCache;
calendarCache = null;
}
if (cal == null) {
cal = Calendar.getInstance();
} else {
cal.setTimeZone(TimeZone.getDefault());
}
cal.setTimeInMillis(timestamp);
return cal;
}
/**
* Converts the character to a digit, throws an IllegalStateException if it isn't a
* valid digit.
*/
private static int toDigit(char ch) {
if (('0' <= ch) && (ch <= '9')) {
return ch - '0';
}
throw new IllegalStateException();
}
/**
* Used for decoding timestamp, throws an IllegalStateException if the two characters are
* not equal.
*/
private static void validateChar(char c1, char c2) {
if (c1 != c2)
throw new IllegalStateException();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy