/*
 * Copyright 2004-2019 H2 Group. Multiple-Licensed under the MPL 2.0, and the
 * EPL 1.0 (http://h2database.com/html/license.html).
 * Initial Developer: H2 Group
 * Iso8601: Initial Developer: Robert Rathsack (firstName dot lastName at gmx
 * dot de)
 */
package org.h2.util;

import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.h2.engine.Mode;
import org.h2.value.Value;
import org.h2.value.ValueDate;
import org.h2.value.ValueNull;
import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone;

This utility class contains time conversion functions.

Date value: a bit field with bits for the year, month, and day. Absolute day: the day number (0 means 1970-01-01).

/** * This utility class contains time conversion functions. * <p> * Date value: a bit field with bits for the year, month, and day. Absolute day: * the day number (0 means 1970-01-01). */
public class DateTimeUtils {
The number of milliseconds per day.
/** * The number of milliseconds per day. */
public static final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000L;
The number of seconds per day.
/** * The number of seconds per day. */
public static final long SECONDS_PER_DAY = 24 * 60 * 60;
UTC time zone.
/** * UTC time zone. */
public static final TimeZone UTC = TimeZone.getTimeZone("UTC");
The number of nanoseconds per second.
/** * The number of nanoseconds per second. */
public static final long NANOS_PER_SECOND = 1_000_000_000;
The number of nanoseconds per minute.
/** * The number of nanoseconds per minute. */
public static final long NANOS_PER_MINUTE = 60 * NANOS_PER_SECOND;
The number of nanoseconds per hour.
/** * The number of nanoseconds per hour. */
public static final long NANOS_PER_HOUR = 60 * NANOS_PER_MINUTE;
The number of nanoseconds per day.
/** * The number of nanoseconds per day. */
public static final long NANOS_PER_DAY = MILLIS_PER_DAY * 1_000_000; private static final int SHIFT_YEAR = 9; private static final int SHIFT_MONTH = 5;
Date value for 1970-01-01.
/** * Date value for 1970-01-01. */
public static final int EPOCH_DATE_VALUE = (1970 << SHIFT_YEAR) + (1 << SHIFT_MONTH) + 1; private static final int[] NORMAL_DAYS_PER_MONTH = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Offsets of month within a year, starting with March, April,...
/** * Offsets of month within a year, starting with March, April,... */
private static final int[] DAYS_OFFSET = { 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337, 366 };
Multipliers for convertScale(long, int).
/** * Multipliers for {@link #convertScale(long, int)}. */
private static final int[] CONVERT_SCALE_TABLE = { 1_000_000_000, 100_000_000, 10_000_000, 1_000_000, 100_000, 10_000, 1_000, 100, 10 };
The thread local. Can not override initialValue because this would result in an inner class, which would not be garbage collected in a web container, and prevent the class loader of H2 from being garbage collected. Using a ThreadLocal on a system class like Calendar does not have that problem, and while it is still a small memory leak, it is not a class loader memory leak.
/** * The thread local. Can not override initialValue because this would result * in an inner class, which would not be garbage collected in a web * container, and prevent the class loader of H2 from being garbage * collected. Using a ThreadLocal on a system class like Calendar does not * have that problem, and while it is still a small memory leak, it is not a * class loader memory leak. */
private static final ThreadLocal<GregorianCalendar> CACHED_CALENDAR = new ThreadLocal<>();
A cached instance of Calendar used when a timezone is specified.
/** * A cached instance of Calendar used when a timezone is specified. */
private static final ThreadLocal<GregorianCalendar> CACHED_CALENDAR_NON_DEFAULT_TIMEZONE = new ThreadLocal<>();
Cached local time zone.
/** * Cached local time zone. */
private static volatile TimeZone timeZone;
Raw offset doesn't change during DST transitions, but changes during other transitions that some time zones have. H2 1.4.193 and later versions use zone offset that is valid for startup time for performance reasons. This code is now used only by old PageStore engine and its datetime storage code has issues with all time zone transitions, so this buggy logic is preserved as is too.
/** * Raw offset doesn't change during DST transitions, but changes during * other transitions that some time zones have. H2 1.4.193 and later * versions use zone offset that is valid for startup time for performance * reasons. This code is now used only by old PageStore engine and its * datetime storage code has issues with all time zone transitions, so this * buggy logic is preserved as is too. */
private static int zoneOffsetMillis = createGregorianCalendar().get(Calendar.ZONE_OFFSET); private DateTimeUtils() { // utility class }
Returns local time zone offset for a specified timestamp.
Params:
  • ms – milliseconds since Epoch in UTC
Returns:local time zone offset
/** * Returns local time zone offset for a specified timestamp. * * @param ms milliseconds since Epoch in UTC * @return local time zone offset */
public static int getTimeZoneOffset(long ms) { TimeZone tz = timeZone; if (tz == null) { timeZone = tz = TimeZone.getDefault(); } return tz.getOffset(ms); }
Reset the cached calendar for default timezone, for example after changing the default timezone.
/** * Reset the cached calendar for default timezone, for example after * changing the default timezone. */
public static void resetCalendar() { CACHED_CALENDAR.remove(); timeZone = null; zoneOffsetMillis = createGregorianCalendar().get(Calendar.ZONE_OFFSET); }
Get a calendar for the default timezone.
Returns:a calendar instance. A cached instance is returned where possible
/** * Get a calendar for the default timezone. * * @return a calendar instance. A cached instance is returned where possible */
public static GregorianCalendar getCalendar() { GregorianCalendar c = CACHED_CALENDAR.get(); if (c == null) { c = createGregorianCalendar(); CACHED_CALENDAR.set(c); } c.clear(); return c; }
Get a calendar for the given timezone.
Params:
  • tz – timezone for the calendar, is never null
Returns:a calendar instance. A cached instance is returned where possible
/** * Get a calendar for the given timezone. * * @param tz timezone for the calendar, is never null * @return a calendar instance. A cached instance is returned where possible */
private static GregorianCalendar getCalendar(TimeZone tz) { GregorianCalendar c = CACHED_CALENDAR_NON_DEFAULT_TIMEZONE.get(); if (c == null || !c.getTimeZone().equals(tz)) { c = createGregorianCalendar(tz); CACHED_CALENDAR_NON_DEFAULT_TIMEZONE.set(c); } c.clear(); return c; }
Creates a Gregorian calendar for the default timezone using the default locale. Dates in H2 are represented in a Gregorian calendar. So this method should be used instead of Calendar.getInstance() to ensure that the Gregorian calendar is used for all date processing instead of a default locale calendar that can be non-Gregorian in some locales.
Returns:a new calendar instance.
/** * Creates a Gregorian calendar for the default timezone using the default * locale. Dates in H2 are represented in a Gregorian calendar. So this * method should be used instead of Calendar.getInstance() to ensure that * the Gregorian calendar is used for all date processing instead of a * default locale calendar that can be non-Gregorian in some locales. * * @return a new calendar instance. */
public static GregorianCalendar createGregorianCalendar() { return new GregorianCalendar(); }
Creates a Gregorian calendar for the given timezone using the default locale. Dates in H2 are represented in a Gregorian calendar. So this method should be used instead of Calendar.getInstance() to ensure that the Gregorian calendar is used for all date processing instead of a default locale calendar that can be non-Gregorian in some locales.
Params:
  • tz – timezone for the calendar, is never null
Returns:a new calendar instance.
/** * Creates a Gregorian calendar for the given timezone using the default * locale. Dates in H2 are represented in a Gregorian calendar. So this * method should be used instead of Calendar.getInstance() to ensure that * the Gregorian calendar is used for all date processing instead of a * default locale calendar that can be non-Gregorian in some locales. * * @param tz timezone for the calendar, is never null * @return a new calendar instance. */
public static GregorianCalendar createGregorianCalendar(TimeZone tz) { return new GregorianCalendar(tz); }
Convert the date to the specified time zone.
Params:
  • value – the date (might be ValueNull)
  • calendar – the calendar
Returns:the date using the correct time zone
/** * Convert the date to the specified time zone. * * @param value the date (might be ValueNull) * @param calendar the calendar * @return the date using the correct time zone */
public static Date convertDate(Value value, Calendar calendar) { if (value == ValueNull.INSTANCE) { return null; } ValueDate d = (ValueDate) value.convertTo(Value.DATE); Calendar cal = (Calendar) calendar.clone(); cal.clear(); cal.setLenient(true); long dateValue = d.getDateValue(); long ms = convertToMillis(cal, yearFromDateValue(dateValue), monthFromDateValue(dateValue), dayFromDateValue(dateValue), 0, 0, 0, 0); return new Date(ms); }
Convert the time to the specified time zone.
Params:
  • value – the time (might be ValueNull)
  • calendar – the calendar
Returns:the time using the correct time zone
/** * Convert the time to the specified time zone. * * @param value the time (might be ValueNull) * @param calendar the calendar * @return the time using the correct time zone */
public static Time convertTime(Value value, Calendar calendar) { if (value == ValueNull.INSTANCE) { return null; } ValueTime t = (ValueTime) value.convertTo(Value.TIME); Calendar cal = (Calendar) calendar.clone(); cal.clear(); cal.setLenient(true); long nanos = t.getNanos(); long millis = nanos / 1_000_000; nanos -= millis * 1_000_000; long s = millis / 1_000; millis -= s * 1_000; long m = s / 60; s -= m * 60; long h = m / 60; m -= h * 60; return new Time(convertToMillis(cal, 1970, 1, 1, (int) h, (int) m, (int) s, (int) millis)); }
Convert the timestamp to the specified time zone.
Params:
  • value – the timestamp (might be ValueNull)
  • calendar – the calendar
Returns:the timestamp using the correct time zone
/** * Convert the timestamp to the specified time zone. * * @param value the timestamp (might be ValueNull) * @param calendar the calendar * @return the timestamp using the correct time zone */
public static Timestamp convertTimestamp(Value value, Calendar calendar) { if (value == ValueNull.INSTANCE) { return null; } ValueTimestamp ts = (ValueTimestamp) value.convertTo(Value.TIMESTAMP); Calendar cal = (Calendar) calendar.clone(); cal.clear(); cal.setLenient(true); long dateValue = ts.getDateValue(); long nanos = ts.getTimeNanos(); long millis = nanos / 1_000_000; nanos -= millis * 1_000_000; long s = millis / 1_000; millis -= s * 1_000; long m = s / 60; s -= m * 60; long h = m / 60; m -= h * 60; long ms = convertToMillis(cal, yearFromDateValue(dateValue), monthFromDateValue(dateValue), dayFromDateValue(dateValue), (int) h, (int) m, (int) s, (int) millis); Timestamp x = new Timestamp(ms); x.setNanos((int) (nanos + millis * 1_000_000)); return x; }
Convert a java.util.Date using the specified calendar.
Params:
  • x – the date
  • calendar – the calendar
Returns:the date
/** * Convert a java.util.Date using the specified calendar. * * @param x the date * @param calendar the calendar * @return the date */
public static ValueDate convertDate(Date x, Calendar calendar) { Calendar cal = (Calendar) calendar.clone(); cal.setTimeInMillis(x.getTime()); long dateValue = dateValueFromCalendar(cal); return ValueDate.fromDateValue(dateValue); }
Convert the time using the specified calendar.
Params:
  • x – the time
  • calendar – the calendar
Returns:the time
/** * Convert the time using the specified calendar. * * @param x the time * @param calendar the calendar * @return the time */
public static ValueTime convertTime(Time x, Calendar calendar) { Calendar cal = (Calendar) calendar.clone(); cal.setTimeInMillis(x.getTime()); long nanos = nanosFromCalendar(cal); return ValueTime.fromNanos(nanos); }
Convert the timestamp using the specified calendar.
Params:
  • x – the time
  • calendar – the calendar
Returns:the timestamp
/** * Convert the timestamp using the specified calendar. * * @param x the time * @param calendar the calendar * @return the timestamp */
public static ValueTimestamp convertTimestamp(Timestamp x, Calendar calendar) { Calendar cal = (Calendar) calendar.clone(); cal.setTimeInMillis(x.getTime()); long dateValue = dateValueFromCalendar(cal); long nanos = nanosFromCalendar(cal); nanos += x.getNanos() % 1_000_000; return ValueTimestamp.fromDateValueAndNanos(dateValue, nanos); }
Parse a date string. The format is: [+|-]year-month-day or [+|-]yyyyMMdd.
Params:
  • s – the string to parse
  • start – the parse index start
  • end – the parse index end
Throws:
Returns:the date value
/** * Parse a date string. The format is: [+|-]year-month-day * or [+|-]yyyyMMdd. * * @param s the string to parse * @param start the parse index start * @param end the parse index end * @return the date value * @throws IllegalArgumentException if there is a problem */
public static long parseDateValue(String s, int start, int end) { if (s.charAt(start) == '+') { // +year start++; } // start at position 1 to support "-year" int yEnd = s.indexOf('-', start + 1); int mStart, mEnd, dStart; if (yEnd > 0) { // Standard [+|-]year-month-day format mStart = yEnd + 1; mEnd = s.indexOf('-', mStart); if (mEnd <= mStart) { throw new IllegalArgumentException(s); } dStart = mEnd + 1; } else { // Additional [+|-]yyyyMMdd format for compatibility mEnd = dStart = end - 2; yEnd = mStart = mEnd - 2; // Accept only 3 or more digits in year for now if (yEnd < start + 3) { throw new IllegalArgumentException(s); } } int year = Integer.parseInt(s.substring(start, yEnd)); int month = StringUtils.parseUInt31(s, mStart, mEnd); int day = StringUtils.parseUInt31(s, dStart, end); if (!isValidDate(year, month, day)) { throw new IllegalArgumentException(year + "-" + month + "-" + day); } return dateValue(year, month, day); }
Parse a time string. The format is: hour:minute[:second[.nanos]], hhmm[ss[.nanos]], or hour.minute.second[.nanos].
Params:
  • s – the string to parse
  • start – the parse index start
  • end – the parse index end
Throws:
Returns:the time in nanoseconds
/** * Parse a time string. The format is: hour:minute[:second[.nanos]], * hhmm[ss[.nanos]], or hour.minute.second[.nanos]. * * @param s the string to parse * @param start the parse index start * @param end the parse index end * @return the time in nanoseconds * @throws IllegalArgumentException if there is a problem */
public static long parseTimeNanos(String s, int start, int end) { int hour, minute, second, nanos; int hEnd = s.indexOf(':', start); int mStart, mEnd, sStart, sEnd; if (hEnd > 0) { mStart = hEnd + 1; mEnd = s.indexOf(':', mStart); if (mEnd >= mStart) { // Standard hour:minute:second[.nanos] format sStart = mEnd + 1; sEnd = s.indexOf('.', sStart); } else { // Additional hour:minute format for compatibility mEnd = end; sStart = sEnd = -1; } } else { int t = s.indexOf('.', start); if (t < 0) { // Additional hhmm[ss] format for compatibility hEnd = mStart = start + 2; mEnd = mStart + 2; int len = end - start; if (len == 6) { sStart = mEnd; sEnd = -1; } else if (len == 4) { sStart = sEnd = -1; } else { throw new IllegalArgumentException(s); } } else if (t >= start + 6) { // Additional hhmmss.nanos format for compatibility if (t - start != 6) { throw new IllegalArgumentException(s); } hEnd = mStart = start + 2; mEnd = sStart = mStart + 2; sEnd = t; } else { // Additional hour.minute.second[.nanos] IBM DB2 time format hEnd = t; mStart = hEnd + 1; mEnd = s.indexOf('.', mStart); if (mEnd <= mStart) { throw new IllegalArgumentException(s); } sStart = mEnd + 1; sEnd = s.indexOf('.', sStart); } } hour = StringUtils.parseUInt31(s, start, hEnd); if (hour >= 24) { throw new IllegalArgumentException(s); } minute = StringUtils.parseUInt31(s, mStart, mEnd); if (sStart > 0) { if (sEnd < 0) { second = StringUtils.parseUInt31(s, sStart, end); nanos = 0; } else { second = StringUtils.parseUInt31(s, sStart, sEnd); nanos = parseNanos(s, sEnd + 1, end); } } else { second = nanos = 0; } if (minute >= 60 || second >= 60) { throw new IllegalArgumentException(s); } return ((((hour * 60L) + minute) * 60) + second) * NANOS_PER_SECOND + nanos; }
Parse nanoseconds.
Params:
  • s – String to parse.
  • start – Begin position at the string to read.
  • end – End position at the string to read.
Returns:Parsed nanoseconds.
/** * Parse nanoseconds. * * @param s String to parse. * @param start Begin position at the string to read. * @param end End position at the string to read. * @return Parsed nanoseconds. */
static int parseNanos(String s, int start, int end) { if (start >= end) { throw new IllegalArgumentException(s); } int nanos = 0, mul = 100_000_000; do { char c = s.charAt(start); if (c < '0' || c > '9') { throw new IllegalArgumentException(s); } nanos += mul * (c - '0'); // mul can become 0, but continue loop anyway to ensure that all // remaining digits are valid mul /= 10; } while (++start < end); return nanos; }
See: https://stackoverflow.com/questions/3976616/how-to-find-nth-occurrence-of-character-in-a-string#answer-3976656
/** * See: * https://stackoverflow.com/questions/3976616/how-to-find-nth-occurrence-of-character-in-a-string#answer-3976656 */
private static int findNthIndexOf(String str, char chr, int n) { int pos = str.indexOf(chr); while (--n > 0 && pos != -1) { pos = str.indexOf(chr, pos + 1); } return pos; }
Parses timestamp value from the specified string.
Params:
Returns:parsed timestamp
/** * Parses timestamp value from the specified string. * * @param s * string to parse * @param mode * database mode, or {@code null} * @param withTimeZone * if {@code true} return {@link ValueTimestampTimeZone} instead of * {@link ValueTimestamp} * @return parsed timestamp */
public static Value parseTimestamp(String s, Mode mode, boolean withTimeZone) { int dateEnd = s.indexOf(' '); if (dateEnd < 0) { // ISO 8601 compatibility dateEnd = s.indexOf('T'); if (dateEnd < 0 && mode != null && mode.allowDB2TimestampFormat) { // DB2 also allows dash between date and time dateEnd = findNthIndexOf(s, '-', 3); } } int timeStart; if (dateEnd < 0) { dateEnd = s.length(); timeStart = -1; } else { timeStart = dateEnd + 1; } long dateValue = parseDateValue(s, 0, dateEnd); long nanos; short tzMinutes = 0; if (timeStart < 0) { nanos = 0; } else { int timeEnd = s.length(); TimeZone tz = null; if (s.endsWith("Z")) { tz = UTC; timeEnd--; } else { int timeZoneStart = s.indexOf('+', dateEnd + 1); if (timeZoneStart < 0) { timeZoneStart = s.indexOf('-', dateEnd + 1); } if (timeZoneStart >= 0) { // Allow [timeZoneName] part after time zone offset int offsetEnd = s.indexOf('[', timeZoneStart + 1); if (offsetEnd < 0) { offsetEnd = s.length(); } String tzName = "GMT" + s.substring(timeZoneStart, offsetEnd); tz = TimeZone.getTimeZone(tzName); if (!tz.getID().startsWith(tzName)) { throw new IllegalArgumentException( tzName + " (" + tz.getID() + "?)"); } if (s.charAt(timeZoneStart - 1) == ' ') { timeZoneStart--; } timeEnd = timeZoneStart; } else { timeZoneStart = s.indexOf(' ', dateEnd + 1); if (timeZoneStart > 0) { String tzName = s.substring(timeZoneStart + 1); tz = TimeZone.getTimeZone(tzName); if (!tz.getID().startsWith(tzName)) { throw new IllegalArgumentException(tzName); } timeEnd = timeZoneStart; } } } nanos = parseTimeNanos(s, dateEnd + 1, timeEnd); if (tz != null) { if (withTimeZone) { if (tz != UTC) { long millis = convertDateTimeValueToMillis(tz, dateValue, nanos / 1_000_000); tzMinutes = (short) (tz.getOffset(millis) / 60_000); } } else { long millis = convertDateTimeValueToMillis(tz, dateValue, nanos / 1_000_000); millis += getTimeZoneOffset(millis); dateValue = dateValueFromLocalMillis(millis); nanos = nanos % 1_000_000 + nanosFromLocalMillis(millis); } } } if (withTimeZone) { return ValueTimestampTimeZone.fromDateValueAndNanos(dateValue, nanos, tzMinutes); } return ValueTimestamp.fromDateValueAndNanos(dateValue, nanos); }
Calculates the time zone offset in minutes for the specified time zone, date value, and nanoseconds since midnight.
Params:
  • tz – time zone, or null for default
  • dateValue – date value
  • timeNanos – nanoseconds since midnight
Returns:time zone offset in milliseconds
/** * Calculates the time zone offset in minutes for the specified time zone, date * value, and nanoseconds since midnight. * * @param tz * time zone, or {@code null} for default * @param dateValue * date value * @param timeNanos * nanoseconds since midnight * @return time zone offset in milliseconds */
public static int getTimeZoneOffsetMillis(TimeZone tz, long dateValue, long timeNanos) { long msec = timeNanos / 1_000_000; long utc = convertDateTimeValueToMillis(tz, dateValue, msec); long local = absoluteDayFromDateValue(dateValue) * MILLIS_PER_DAY + msec; return (int) (local - utc); }
Calculates the milliseconds since epoch for the specified date value, nanoseconds since midnight, and time zone offset.
Params:
  • dateValue – date value
  • timeNanos – nanoseconds since midnight
  • offsetMins – time zone offset in minutes
Returns:milliseconds since epoch in UTC
/** * Calculates the milliseconds since epoch for the specified date value, * nanoseconds since midnight, and time zone offset. * @param dateValue * date value * @param timeNanos * nanoseconds since midnight * @param offsetMins * time zone offset in minutes * @return milliseconds since epoch in UTC */
public static long getMillis(long dateValue, long timeNanos, short offsetMins) { return absoluteDayFromDateValue(dateValue) * MILLIS_PER_DAY + timeNanos / 1_000_000 - offsetMins * 60_000; }
Calculate the milliseconds since 1970-01-01 (UTC) for the given date and time (in the specified timezone).
Params:
  • tz – the timezone of the parameters, or null for the default timezone
  • year – the absolute year (positive or negative)
  • month – the month (1-12)
  • day – the day (1-31)
  • hour – the hour (0-23)
  • minute – the minutes (0-59)
  • second – the number of seconds (0-59)
  • millis – the number of milliseconds
Returns:the number of milliseconds (UTC)
/** * Calculate the milliseconds since 1970-01-01 (UTC) for the given date and * time (in the specified timezone). * * @param tz the timezone of the parameters, or null for the default * timezone * @param year the absolute year (positive or negative) * @param month the month (1-12) * @param day the day (1-31) * @param hour the hour (0-23) * @param minute the minutes (0-59) * @param second the number of seconds (0-59) * @param millis the number of milliseconds * @return the number of milliseconds (UTC) */
public static long getMillis(TimeZone tz, int year, int month, int day, int hour, int minute, int second, int millis) { GregorianCalendar c; if (tz == null) { c = getCalendar(); } else { c = getCalendar(tz); } c.setLenient(false); try { return convertToMillis(c, year, month, day, hour, minute, second, millis); } catch (IllegalArgumentException e) { // special case: if the time simply doesn't exist because of // daylight saving time changes, use the lenient version String message = e.toString(); if (message.indexOf("HOUR_OF_DAY") > 0) { if (hour < 0 || hour > 23) { throw e; } } else if (message.indexOf("DAY_OF_MONTH") > 0) { int maxDay; if (month == 2) { maxDay = c.isLeapYear(year) ? 29 : 28; } else { maxDay = NORMAL_DAYS_PER_MONTH[month]; } if (day < 1 || day > maxDay) { throw e; } // DAY_OF_MONTH is thrown for years > 2037 // using the timezone Brasilia and others, // for example for 2042-10-12 00:00:00. hour += 6; } c.setLenient(true); return convertToMillis(c, year, month, day, hour, minute, second, millis); } } private static long convertToMillis(Calendar cal, int year, int month, int day, int hour, int minute, int second, int millis) { if (year <= 0) { cal.set(Calendar.ERA, GregorianCalendar.BC); cal.set(Calendar.YEAR, 1 - year); } else { cal.set(Calendar.ERA, GregorianCalendar.AD); cal.set(Calendar.YEAR, year); } // january is 0 cal.set(Calendar.MONTH, month - 1); cal.set(Calendar.DAY_OF_MONTH, day); cal.set(Calendar.HOUR_OF_DAY, hour); cal.set(Calendar.MINUTE, minute); cal.set(Calendar.SECOND, second); cal.set(Calendar.MILLISECOND, millis); return cal.getTimeInMillis(); }
Extracts date value and nanos of day from the specified value.
Params:
  • value – value to extract fields from
Returns:array with date value and nanos of day
/** * Extracts date value and nanos of day from the specified value. * * @param value * value to extract fields from * @return array with date value and nanos of day */
public static long[] dateAndTimeFromValue(Value value) { long dateValue = EPOCH_DATE_VALUE; long timeNanos = 0; if (value instanceof ValueTimestamp) { ValueTimestamp v = (ValueTimestamp) value; dateValue = v.getDateValue(); timeNanos = v.getTimeNanos(); } else if (value instanceof ValueDate) { dateValue = ((ValueDate) value).getDateValue(); } else if (value instanceof ValueTime) { timeNanos = ((ValueTime) value).getNanos(); } else if (value instanceof ValueTimestampTimeZone) { ValueTimestampTimeZone v = (ValueTimestampTimeZone) value; dateValue = v.getDateValue(); timeNanos = v.getTimeNanos(); } else { ValueTimestamp v = (ValueTimestamp) value.convertTo(Value.TIMESTAMP); dateValue = v.getDateValue(); timeNanos = v.getTimeNanos(); } return new long[] {dateValue, timeNanos}; }
Creates a new date-time value with the same type as original value. If original value is a ValueTimestampTimeZone, returned value will have the same time zone offset as original value.
Params:
  • original – original value
  • dateValue – date value for the returned value
  • timeNanos – nanos of day for the returned value
  • forceTimestamp – if true return ValueTimestamp if original argument is ValueDate or ValueTime
Returns:new value with specified date value and nanos of day
/** * Creates a new date-time value with the same type as original value. If * original value is a ValueTimestampTimeZone, returned value will have the same * time zone offset as original value. * * @param original * original value * @param dateValue * date value for the returned value * @param timeNanos * nanos of day for the returned value * @param forceTimestamp * if {@code true} return ValueTimestamp if original argument is * ValueDate or ValueTime * @return new value with specified date value and nanos of day */
public static Value dateTimeToValue(Value original, long dateValue, long timeNanos, boolean forceTimestamp) { if (!(original instanceof ValueTimestamp)) { if (!forceTimestamp) { if (original instanceof ValueDate) { return ValueDate.fromDateValue(dateValue); } if (original instanceof ValueTime) { return ValueTime.fromNanos(timeNanos); } } if (original instanceof ValueTimestampTimeZone) { return ValueTimestampTimeZone.fromDateValueAndNanos(dateValue, timeNanos, ((ValueTimestampTimeZone) original).getTimeZoneOffsetMins()); } } return ValueTimestamp.fromDateValueAndNanos(dateValue, timeNanos); }
Get the number of milliseconds since 1970-01-01 in the local timezone, but without daylight saving time into account.
Params:
  • d – the date
Returns:the milliseconds
/** * Get the number of milliseconds since 1970-01-01 in the local timezone, * but without daylight saving time into account. * * @param d the date * @return the milliseconds */
public static long getTimeLocalWithoutDst(java.util.Date d) { return d.getTime() + zoneOffsetMillis; }
Convert the number of milliseconds since 1970-01-01 in the local timezone to UTC, but without daylight saving time into account.
Params:
  • millis – the number of milliseconds in the local timezone
Returns:the number of milliseconds in UTC
/** * Convert the number of milliseconds since 1970-01-01 in the local timezone * to UTC, but without daylight saving time into account. * * @param millis the number of milliseconds in the local timezone * @return the number of milliseconds in UTC */
public static long getTimeUTCWithoutDst(long millis) { return millis - zoneOffsetMillis; }
Returns day of week.
Params:
  • dateValue – the date value
  • firstDayOfWeek – first day of week, Monday as 1, Sunday as 7 or 0
See Also:
Returns:day of week
/** * Returns day of week. * * @param dateValue * the date value * @param firstDayOfWeek * first day of week, Monday as 1, Sunday as 7 or 0 * @return day of week * @see #getIsoDayOfWeek(long) */
public static int getDayOfWeek(long dateValue, int firstDayOfWeek) { return getDayOfWeekFromAbsolute(absoluteDayFromDateValue(dateValue), firstDayOfWeek); }
Get the day of the week from the absolute day value.
Params:
  • absoluteValue – the absolute day
  • firstDayOfWeek – the first day of the week
Returns:the day of week
/** * Get the day of the week from the absolute day value. * * @param absoluteValue the absolute day * @param firstDayOfWeek the first day of the week * @return the day of week */
public static int getDayOfWeekFromAbsolute(long absoluteValue, int firstDayOfWeek) { return absoluteValue >= 0 ? (int) ((absoluteValue - firstDayOfWeek + 11) % 7) + 1 : (int) ((absoluteValue - firstDayOfWeek - 2) % 7) + 7; }
Returns number of day in year.
Params:
  • dateValue – the date value
Returns:number of day in year
/** * Returns number of day in year. * * @param dateValue * the date value * @return number of day in year */
public static int getDayOfYear(long dateValue) { return (int) (absoluteDayFromDateValue(dateValue) - absoluteDayFromYear(yearFromDateValue(dateValue))) + 1; }
Returns ISO day of week.
Params:
  • dateValue – the date value
See Also:
Returns:ISO day of week, Monday as 1 to Sunday as 7
/** * Returns ISO day of week. * * @param dateValue * the date value * @return ISO day of week, Monday as 1 to Sunday as 7 * @see #getSundayDayOfWeek(long) */
public static int getIsoDayOfWeek(long dateValue) { return getDayOfWeek(dateValue, 1); }
Returns ISO number of week in year.
Params:
  • dateValue – the date value
See Also:
Returns:number of week in year
/** * Returns ISO number of week in year. * * @param dateValue * the date value * @return number of week in year * @see #getIsoWeekYear(long) * @see #getWeekOfYear(long, int, int) */
public static int getIsoWeekOfYear(long dateValue) { return getWeekOfYear(dateValue, 1, 4); }
Returns ISO week year.
Params:
  • dateValue – the date value
See Also:
Returns:ISO week year
/** * Returns ISO week year. * * @param dateValue * the date value * @return ISO week year * @see #getIsoWeekOfYear(long) * @see #getWeekYear(long, int, int) */
public static int getIsoWeekYear(long dateValue) { return getWeekYear(dateValue, 1, 4); }
Returns day of week with Sunday as 1.
Params:
  • dateValue – the date value
See Also:
Returns:day of week, Sunday as 1 to Monday as 7
/** * Returns day of week with Sunday as 1. * * @param dateValue * the date value * @return day of week, Sunday as 1 to Monday as 7 * @see #getIsoDayOfWeek(long) */
public static int getSundayDayOfWeek(long dateValue) { return getDayOfWeek(dateValue, 0); }
Returns number of week in year.
Params:
  • dateValue – the date value
  • firstDayOfWeek – first day of week, Monday as 1, Sunday as 7 or 0
  • minimalDaysInFirstWeek – minimal days in first week of year
See Also:
Returns:number of week in year
/** * Returns number of week in year. * * @param dateValue * the date value * @param firstDayOfWeek * first day of week, Monday as 1, Sunday as 7 or 0 * @param minimalDaysInFirstWeek * minimal days in first week of year * @return number of week in year * @see #getIsoWeekOfYear(long) */
public static int getWeekOfYear(long dateValue, int firstDayOfWeek, int minimalDaysInFirstWeek) { long abs = absoluteDayFromDateValue(dateValue); int year = yearFromDateValue(dateValue); long base = getWeekOfYearBase(year, firstDayOfWeek, minimalDaysInFirstWeek); if (abs - base < 0) { base = getWeekOfYearBase(year - 1, firstDayOfWeek, minimalDaysInFirstWeek); } else if (monthFromDateValue(dateValue) == 12 && 24 + minimalDaysInFirstWeek < dayFromDateValue(dateValue)) { if (abs >= getWeekOfYearBase(year + 1, firstDayOfWeek, minimalDaysInFirstWeek)) { return 1; } } return (int) ((abs - base) / 7) + 1; } private static long getWeekOfYearBase(int year, int firstDayOfWeek, int minimalDaysInFirstWeek) { long first = absoluteDayFromYear(year); int daysInFirstWeek = 8 - getDayOfWeekFromAbsolute(first, firstDayOfWeek); long base = first + daysInFirstWeek; if (daysInFirstWeek >= minimalDaysInFirstWeek) { base -= 7; } return base; }
Returns week year.
Params:
  • dateValue – the date value
  • firstDayOfWeek – first day of week, Monday as 1, Sunday as 7 or 0
  • minimalDaysInFirstWeek – minimal days in first week of year
See Also:
Returns:week year
/** * Returns week year. * * @param dateValue * the date value * @param firstDayOfWeek * first day of week, Monday as 1, Sunday as 7 or 0 * @param minimalDaysInFirstWeek * minimal days in first week of year * @return week year * @see #getIsoWeekYear(long) */
public static int getWeekYear(long dateValue, int firstDayOfWeek, int minimalDaysInFirstWeek) { long abs = absoluteDayFromDateValue(dateValue); int year = yearFromDateValue(dateValue); long base = getWeekOfYearBase(year, firstDayOfWeek, minimalDaysInFirstWeek); if (abs - base < 0) { return year - 1; } else if (monthFromDateValue(dateValue) == 12 && 24 + minimalDaysInFirstWeek < dayFromDateValue(dateValue)) { if (abs >= getWeekOfYearBase(year + 1, firstDayOfWeek, minimalDaysInFirstWeek)) { return year + 1; } } return year; }
Returns number of days in month.
Params:
  • year – the year
  • month – the month
Returns:number of days in the specified month
/** * Returns number of days in month. * * @param year the year * @param month the month * @return number of days in the specified month */
public static int getDaysInMonth(int year, int month) { if (month != 2) { return NORMAL_DAYS_PER_MONTH[month]; } // All leap years divisible by 4 return (year & 3) == 0 // All such years before 1582 are Julian and leap && (year < 1582 // Otherwise check Gregorian conditions || year % 100 != 0 || year % 400 == 0) ? 29 : 28; }
Verify if the specified date is valid.
Params:
  • year – the year
  • month – the month (January is 1)
  • day – the day (1 is the first of the month)
Returns:true if it is valid
/** * Verify if the specified date is valid. * * @param year the year * @param month the month (January is 1) * @param day the day (1 is the first of the month) * @return true if it is valid */
public static boolean isValidDate(int year, int month, int day) { if (month < 1 || month > 12 || day < 1) { return false; } if (year == 1582 && month == 10) { // special case: days 1582-10-05 .. 1582-10-14 don't exist return day < 5 || (day > 14 && day <= 31); } return day <= getDaysInMonth(year, month); }
Convert an encoded date value to a java.util.Date, using the default timezone.
Params:
  • dateValue – the date value
Returns:the date
/** * Convert an encoded date value to a java.util.Date, using the default * timezone. * * @param dateValue the date value * @return the date */
public static Date convertDateValueToDate(long dateValue) { long millis = getMillis(null, yearFromDateValue(dateValue), monthFromDateValue(dateValue), dayFromDateValue(dateValue), 0, 0, 0, 0); return new Date(millis); }
Convert an encoded date-time value to millis, using the supplied timezone.
Params:
  • tz – the timezone
  • dateValue – the date value
  • ms – milliseconds of day
Returns:the date
/** * Convert an encoded date-time value to millis, using the supplied timezone. * * @param tz the timezone * @param dateValue the date value * @param ms milliseconds of day * @return the date */
public static long convertDateTimeValueToMillis(TimeZone tz, long dateValue, long ms) { long second = ms / 1000; ms -= second * 1000; int minute = (int) (second / 60); second -= minute * 60; int hour = minute / 60; minute -= hour * 60; return getMillis(tz, yearFromDateValue(dateValue), monthFromDateValue(dateValue), dayFromDateValue(dateValue), hour, minute, (int) second, (int) ms); }
Convert an encoded date value / time value to a timestamp, using the default timezone.
Params:
  • dateValue – the date value
  • timeNanos – the nanoseconds since midnight
Returns:the timestamp
/** * Convert an encoded date value / time value to a timestamp, using the * default timezone. * * @param dateValue the date value * @param timeNanos the nanoseconds since midnight * @return the timestamp */
public static Timestamp convertDateValueToTimestamp(long dateValue, long timeNanos) { Timestamp ts = new Timestamp(convertDateTimeValueToMillis(null, dateValue, timeNanos / 1_000_000)); // This method expects the complete nanoseconds value including milliseconds ts.setNanos((int) (timeNanos % NANOS_PER_SECOND)); return ts; }
Convert an encoded date value / time value to a timestamp using the specified time zone offset.
Params:
  • dateValue – the date value
  • timeNanos – the nanoseconds since midnight
  • offsetMins – time zone offset in minutes
Returns:the timestamp
/** * Convert an encoded date value / time value to a timestamp using the specified * time zone offset. * * @param dateValue the date value * @param timeNanos the nanoseconds since midnight * @param offsetMins time zone offset in minutes * @return the timestamp */
public static Timestamp convertTimestampTimeZoneToTimestamp(long dateValue, long timeNanos, short offsetMins) { Timestamp ts = new Timestamp(getMillis(dateValue, timeNanos, offsetMins)); ts.setNanos((int) (timeNanos % NANOS_PER_SECOND)); return ts; }
Convert a time value to a time, using the default timezone.
Params:
  • nanosSinceMidnight – the nanoseconds since midnight
Returns:the time
/** * Convert a time value to a time, using the default timezone. * * @param nanosSinceMidnight the nanoseconds since midnight * @return the time */
public static Time convertNanoToTime(long nanosSinceMidnight) { long millis = nanosSinceMidnight / 1_000_000; long s = millis / 1_000; millis -= s * 1_000; long m = s / 60; s -= m * 60; long h = m / 60; m -= h * 60; long ms = getMillis(null, 1970, 1, 1, (int) (h % 24), (int) m, (int) s, (int) millis); return new Time(ms); }
Get the year from a date value.
Params:
  • x – the date value
Returns:the year
/** * Get the year from a date value. * * @param x the date value * @return the year */
public static int yearFromDateValue(long x) { return (int) (x >>> SHIFT_YEAR); }
Get the month from a date value.
Params:
  • x – the date value
Returns:the month (1..12)
/** * Get the month from a date value. * * @param x the date value * @return the month (1..12) */
public static int monthFromDateValue(long x) { return (int) (x >>> SHIFT_MONTH) & 15; }
Get the day of month from a date value.
Params:
  • x – the date value
Returns:the day (1..31)
/** * Get the day of month from a date value. * * @param x the date value * @return the day (1..31) */
public static int dayFromDateValue(long x) { return (int) (x & 31); }
Get the date value from a given date.
Params:
  • year – the year
  • month – the month (1..12)
  • day – the day (1..31)
Returns:the date value
/** * Get the date value from a given date. * * @param year the year * @param month the month (1..12) * @param day the day (1..31) * @return the date value */
public static long dateValue(long year, int month, int day) { return (year << SHIFT_YEAR) | (month << SHIFT_MONTH) | day; }
Get the date value from a given denormalized date with possible out of range values of month and/or day. Used after addition or subtraction month or years to (from) it to get a valid date.
Params:
  • year – the year
  • month – the month, if out of range month and year will be normalized
  • day – the day of the month, if out of range it will be saturated
Returns:the date value
/** * Get the date value from a given denormalized date with possible out of range * values of month and/or day. Used after addition or subtraction month or years * to (from) it to get a valid date. * * @param year * the year * @param month * the month, if out of range month and year will be normalized * @param day * the day of the month, if out of range it will be saturated * @return the date value */
public static long dateValueFromDenormalizedDate(long year, long month, int day) { long mm1 = month - 1; long yd = mm1 / 12; if (mm1 < 0 && yd * 12 != mm1) { yd--; } int y = (int) (year + yd); int m = (int) (month - yd * 12); if (day < 1) { day = 1; } else { int max = getDaysInMonth(y, m); if (day > max) { day = max; } } return dateValue(y, m, day); }
Convert a local datetime in millis to an encoded date.
Params:
  • ms – the milliseconds
Returns:the date value
/** * Convert a local datetime in millis to an encoded date. * * @param ms the milliseconds * @return the date value */
public static long dateValueFromLocalMillis(long ms) { long absoluteDay = ms / MILLIS_PER_DAY; // Round toward negative infinity if (ms < 0 && (absoluteDay * MILLIS_PER_DAY != ms)) { absoluteDay--; } return dateValueFromAbsoluteDay(absoluteDay); }
Calculate the encoded date value from a given calendar.
Params:
  • cal – the calendar
Returns:the date value
/** * Calculate the encoded date value from a given calendar. * * @param cal the calendar * @return the date value */
private static long dateValueFromCalendar(Calendar cal) { int year = cal.get(Calendar.YEAR); if (cal.get(Calendar.ERA) == GregorianCalendar.BC) { year = 1 - year; } int month = cal.get(Calendar.MONTH) + 1; int day = cal.get(Calendar.DAY_OF_MONTH); return ((long) year << SHIFT_YEAR) | (month << SHIFT_MONTH) | day; }
Convert a time in milliseconds in local time to the nanoseconds since midnight.
Params:
  • ms – the milliseconds
Returns:the nanoseconds
/** * Convert a time in milliseconds in local time to the nanoseconds since midnight. * * @param ms the milliseconds * @return the nanoseconds */
public static long nanosFromLocalMillis(long ms) { long absoluteDay = ms / MILLIS_PER_DAY; // Round toward negative infinity if (ms < 0 && (absoluteDay * MILLIS_PER_DAY != ms)) { absoluteDay--; } return (ms - absoluteDay * MILLIS_PER_DAY) * 1_000_000; }
Convert a java.util.Calendar to nanoseconds since midnight.
Params:
  • cal – the calendar
Returns:the nanoseconds
/** * Convert a java.util.Calendar to nanoseconds since midnight. * * @param cal the calendar * @return the nanoseconds */
private static long nanosFromCalendar(Calendar cal) { int h = cal.get(Calendar.HOUR_OF_DAY); int m = cal.get(Calendar.MINUTE); int s = cal.get(Calendar.SECOND); int millis = cal.get(Calendar.MILLISECOND); return ((((((h * 60L) + m) * 60) + s) * 1000) + millis) * 1000000; }
Calculate the normalized timestamp.
Params:
  • absoluteDay – the absolute day
  • nanos – the nanoseconds (may be negative or larger than one day)
Returns:the timestamp
/** * Calculate the normalized timestamp. * * @param absoluteDay the absolute day * @param nanos the nanoseconds (may be negative or larger than one day) * @return the timestamp */
public static ValueTimestamp normalizeTimestamp(long absoluteDay, long nanos) { if (nanos > NANOS_PER_DAY || nanos < 0) { long d; if (nanos > NANOS_PER_DAY) { d = nanos / NANOS_PER_DAY; } else { d = (nanos - NANOS_PER_DAY + 1) / NANOS_PER_DAY; } nanos -= d * NANOS_PER_DAY; absoluteDay += d; } return ValueTimestamp.fromDateValueAndNanos( dateValueFromAbsoluteDay(absoluteDay), nanos); }
Converts local date value and nanoseconds to timestamp with time zone.
Params:
  • dateValue – date value
  • timeNanos – nanoseconds since midnight
Returns:timestamp with time zone
/** * Converts local date value and nanoseconds to timestamp with time zone. * * @param dateValue * date value * @param timeNanos * nanoseconds since midnight * @return timestamp with time zone */
public static ValueTimestampTimeZone timestampTimeZoneFromLocalDateValueAndNanos(long dateValue, long timeNanos) { int timeZoneOffset = getTimeZoneOffsetMillis(null, dateValue, timeNanos); int offsetMins = timeZoneOffset / 60_000; int correction = timeZoneOffset % 60_000; if (correction != 0) { timeNanos -= correction; if (timeNanos < 0) { timeNanos += NANOS_PER_DAY; dateValue = decrementDateValue(dateValue); } else if (timeNanos >= NANOS_PER_DAY) { timeNanos -= NANOS_PER_DAY; dateValue = incrementDateValue(dateValue); } } return ValueTimestampTimeZone.fromDateValueAndNanos(dateValue, timeNanos, (short) offsetMins); }
Creates the instance of the ValueTimestampTimeZone from milliseconds.
Params:
  • ms – milliseconds since 1970-01-01 (UTC)
Returns:timestamp with time zone with specified value and current time zone
/** * Creates the instance of the {@link ValueTimestampTimeZone} from milliseconds. * * @param ms milliseconds since 1970-01-01 (UTC) * @return timestamp with time zone with specified value and current time zone */
public static ValueTimestampTimeZone timestampTimeZoneFromMillis(long ms) { int offset = getTimeZoneOffset(ms); ms += offset; long absoluteDay = ms / MILLIS_PER_DAY; // Round toward negative infinity if (ms < 0 && (absoluteDay * MILLIS_PER_DAY != ms)) { absoluteDay--; } return ValueTimestampTimeZone.fromDateValueAndNanos( dateValueFromAbsoluteDay(absoluteDay), (ms - absoluteDay * MILLIS_PER_DAY) * 1_000_000, (short) (offset / 60_000)); }
Calculate the absolute day for a January, 1 of the specified year.
Params:
  • year – the year
Returns:the absolute day
/** * Calculate the absolute day for a January, 1 of the specified year. * * @param year * the year * @return the absolute day */
public static long absoluteDayFromYear(long year) { year--; long a = ((year * 1461L) >> 2) - 719_177; if (year < 1582) { // Julian calendar a += 13; } else if (year < 1900 || year > 2099) { // Gregorian calendar (slow mode) a += (year / 400) - (year / 100) + 15; } return a; }
Calculate the absolute day from an encoded date value.
Params:
  • dateValue – the date value
Returns:the absolute day
/** * Calculate the absolute day from an encoded date value. * * @param dateValue the date value * @return the absolute day */
public static long absoluteDayFromDateValue(long dateValue) { long y = yearFromDateValue(dateValue); int m = monthFromDateValue(dateValue); int d = dayFromDateValue(dateValue); if (m <= 2) { y--; m += 12; } long a = ((y * 1461L) >> 2) + DAYS_OFFSET[m - 3] + d - 719_484; if (y <= 1582 && ((y < 1582) || (m * 100 + d < 10_15))) { // Julian calendar (cutover at 1582-10-04 / 1582-10-15) a += 13; } else if (y < 1900 || y > 2099) { // Gregorian calendar (slow mode) a += (y / 400) - (y / 100) + 15; } return a; }
Calculate the absolute day from an encoded date value in proleptic Gregorian calendar.
Params:
  • dateValue – the date value
Returns:the absolute day in proleptic Gregorian calendar
/** * Calculate the absolute day from an encoded date value in proleptic Gregorian * calendar. * * @param dateValue the date value * @return the absolute day in proleptic Gregorian calendar */
public static long prolepticGregorianAbsoluteDayFromDateValue(long dateValue) { long y = yearFromDateValue(dateValue); int m = monthFromDateValue(dateValue); int d = dayFromDateValue(dateValue); if (m <= 2) { y--; m += 12; } long a = ((y * 1461L) >> 2) + DAYS_OFFSET[m - 3] + d - 719_484; if (y < 1900 || y > 2099) { // Slow mode a += (y / 400) - (y / 100) + 15; } return a; }
Calculate the encoded date value from an absolute day.
Params:
  • absoluteDay – the absolute day
Returns:the date value
/** * Calculate the encoded date value from an absolute day. * * @param absoluteDay the absolute day * @return the date value */
public static long dateValueFromAbsoluteDay(long absoluteDay) { long d = absoluteDay + 719_468; long y100, offset; if (d > 578_040) { // Gregorian calendar long y400 = d / 146_097; d -= y400 * 146_097; y100 = d / 36_524; d -= y100 * 36_524; offset = y400 * 400 + y100 * 100; } else { // Julian calendar y100 = 0; d += 292_200_000_002L; offset = -800_000_000; } long y4 = d / 1461; d -= y4 * 1461; long y = d / 365; d -= y * 365; if (d == 0 && (y == 4 || y100 == 4)) { y--; d += 365; } y += offset + y4 * 4; // month of a day int m = ((int) d * 2 + 1) * 5 / 306; d -= DAYS_OFFSET[m] - 1; if (m >= 10) { y++; m -= 12; } return dateValue(y, m + 3, (int) d); }
Return the next date value.
Params:
  • dateValue – the date value
Returns:the next date value
/** * Return the next date value. * * @param dateValue * the date value * @return the next date value */
public static long incrementDateValue(long dateValue) { int year = yearFromDateValue(dateValue); if (year == 1582) { // Use slow way instead of rarely needed large custom code. return dateValueFromAbsoluteDay(absoluteDayFromDateValue(dateValue) + 1); } int day = dayFromDateValue(dateValue); if (day < 28) { return dateValue + 1; } int month = monthFromDateValue(dateValue); if (day < getDaysInMonth(year, month)) { return dateValue + 1; } if (month < 12) { month++; } else { month = 1; year++; } return dateValue(year, month, 1); }
Return the previous date value.
Params:
  • dateValue – the date value
Returns:the previous date value
/** * Return the previous date value. * * @param dateValue * the date value * @return the previous date value */
public static long decrementDateValue(long dateValue) { int year = yearFromDateValue(dateValue); if (year == 1582) { // Use slow way instead of rarely needed large custom code. return dateValueFromAbsoluteDay(absoluteDayFromDateValue(dateValue) - 1); } if (dayFromDateValue(dateValue) > 1) { return dateValue - 1; } int month = monthFromDateValue(dateValue); if (month > 1) { month--; } else { month = 12; year--; } return dateValue(year, month, getDaysInMonth(year, month)); }
Append a date to the string builder.
Params:
  • buff – the target string builder
  • dateValue – the date value
/** * Append a date to the string builder. * * @param buff the target string builder * @param dateValue the date value */
public static void appendDate(StringBuilder buff, long dateValue) { int y = yearFromDateValue(dateValue); int m = monthFromDateValue(dateValue); int d = dayFromDateValue(dateValue); if (y > 0 && y < 10_000) { StringUtils.appendZeroPadded(buff, 4, y); } else { buff.append(y); } buff.append('-'); StringUtils.appendZeroPadded(buff, 2, m); buff.append('-'); StringUtils.appendZeroPadded(buff, 2, d); }
Append a time to the string builder.
Params:
  • buff – the target string builder
  • nanos – the time in nanoseconds
/** * Append a time to the string builder. * * @param buff the target string builder * @param nanos the time in nanoseconds */
public static void appendTime(StringBuilder buff, long nanos) { if (nanos < 0) { buff.append('-'); nanos = -nanos; } /* * nanos now either in range from 0 to Long.MAX_VALUE or equals to * Long.MIN_VALUE. We need to divide nanos by 1000000 with unsigned division to * get correct result. The simplest way to do this with such constraints is to * divide -nanos by -1000000. */ long ms = -nanos / -1_000_000; nanos -= ms * 1_000_000; long s = ms / 1_000; ms -= s * 1_000; long m = s / 60; s -= m * 60; long h = m / 60; m -= h * 60; StringUtils.appendZeroPadded(buff, 2, h); buff.append(':'); StringUtils.appendZeroPadded(buff, 2, m); buff.append(':'); StringUtils.appendZeroPadded(buff, 2, s); if (ms > 0 || nanos > 0) { buff.append('.'); StringUtils.appendZeroPadded(buff, 3, ms); if (nanos > 0) { StringUtils.appendZeroPadded(buff, 6, nanos); } stripTrailingZeroes(buff); } }
Skip trailing zeroes.
Params:
  • buff – String buffer.
/** * Skip trailing zeroes. * * @param buff String buffer. */
static void stripTrailingZeroes(StringBuilder buff) { int i = buff.length() - 1; if (buff.charAt(i) == '0') { while (buff.charAt(--i) == '0') { // do nothing } buff.setLength(i + 1); } }
Append a time zone to the string builder.
Params:
  • buff – the target string builder
  • tz – the time zone in minutes
/** * Append a time zone to the string builder. * * @param buff the target string builder * @param tz the time zone in minutes */
public static void appendTimeZone(StringBuilder buff, short tz) { if (tz < 0) { buff.append('-'); tz = (short) -tz; } else { buff.append('+'); } int hours = tz / 60; tz -= hours * 60; int mins = tz; StringUtils.appendZeroPadded(buff, 2, hours); if (mins != 0) { buff.append(':'); StringUtils.appendZeroPadded(buff, 2, mins); } }
Formats timestamp with time zone as string.
Params:
  • buff – the target string builder
  • dateValue – the year-month-day bit field
  • timeNanos – nanoseconds since midnight
  • timeZoneOffsetMins – the time zone offset in minutes
/** * Formats timestamp with time zone as string. * * @param buff the target string builder * @param dateValue the year-month-day bit field * @param timeNanos nanoseconds since midnight * @param timeZoneOffsetMins the time zone offset in minutes */
public static void appendTimestampTimeZone(StringBuilder buff, long dateValue, long timeNanos, short timeZoneOffsetMins) { appendDate(buff, dateValue); buff.append(' '); appendTime(buff, timeNanos); appendTimeZone(buff, timeZoneOffsetMins); }
Generates time zone name for the specified offset in minutes.
Params:
  • offsetMins – offset in minutes
Returns:time zone name
/** * Generates time zone name for the specified offset in minutes. * * @param offsetMins * offset in minutes * @return time zone name */
public static String timeZoneNameFromOffsetMins(int offsetMins) { if (offsetMins == 0) { return "UTC"; } StringBuilder b = new StringBuilder(9); b.append("GMT"); if (offsetMins < 0) { b.append('-'); offsetMins = -offsetMins; } else { b.append('+'); } StringUtils.appendZeroPadded(b, 2, offsetMins / 60); b.append(':'); StringUtils.appendZeroPadded(b, 2, offsetMins % 60); return b.toString(); }
Converts scale of nanoseconds.
Params:
  • nanosOfDay – nanoseconds of day
  • scale – fractional seconds precision
Returns:scaled value
/** * Converts scale of nanoseconds. * * @param nanosOfDay nanoseconds of day * @param scale fractional seconds precision * @return scaled value */
public static long convertScale(long nanosOfDay, int scale) { if (scale >= 9) { return nanosOfDay; } int m = CONVERT_SCALE_TABLE[scale]; long mod = nanosOfDay % m; if (mod >= m >>> 1) { nanosOfDay += m; } return nanosOfDay - mod; } }