
net.snowflake.common.core.CalendarCache Maven / Gradle / Ivy
package net.snowflake.common.core;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.TimeZone;
/**
* Created by mzukowski on 3/13/16.
*
* Implements a simple thread-local cache for GregorianCalendar objects.
* Note, by default it is not enabled, and will re-create the objects.
*
*/
public class CalendarCache
{
private static class CalendarCacheState
{
HashMap map;
boolean enabled;
/** If set, we always use Gregorian calendar, even before 1582 */
boolean alwaysGregorian;
public CalendarCacheState()
{
map = new HashMap();
enabled = false;
alwaysGregorian = false;
}
};
/** Thread local state */
private static final ThreadLocal localState =
new ThreadLocal()
{
@Override protected CalendarCacheState initialValue()
{
return new CalendarCacheState();
}
};
/**
* Enable or disable the cache
* @param enabled true to enable cache or false
*/
public static void setEnabled(boolean enabled)
{
localState.get().enabled = enabled;
}
/**
* Set if the the calendars produced should not observe Julian calendar
* before 1582.
*
* Calling this function also clears the cache.
*/
public static void setAlwaysGregorian(boolean alwaysGregorian)
{
localState.get().alwaysGregorian = alwaysGregorian;
// Clear the cache, in case old values had a different setting
localState.get().map.clear();
}
/**
* Helper function.
* Returns a GregorianCalendar object.
* @param timezone Timezone to create the calendar in.
* @param tzId The id of the timezone (e.g. "America/Los_Angeles")
* @param calId Explicit ID of the calendar. Can be used e.g.
* if more than one copy of the calendar for the same
* timezone is needed.
* Note, if specified, the caller is responsible for
* making sure it's always the same timezone.
* @return The GregorianCalendar object. Note, it can be reused by other
* consumers, so be careful changing any settings in it
*/
public static GregorianCalendar get(TimeZone timezone,
String tzId,
String calId)
{
CalendarCacheState state = localState.get();
GregorianCalendar res;
if (state.enabled)
{
res = state.map.get(calId);
if (res == null)
{ // Not found, create it
if (timezone == null)
{
// If not specified, create a timezone
timezone = TimeZone.getTimeZone(tzId);
}
res = new GregorianCalendar(timezone);
state.map.put(calId, res);
}
else
{ // Found
// Verify it's the same
if (timezone != null & !res.getTimeZone().hasSameRules(timezone))
{
throw new IllegalArgumentException(
"Cached timezone is not equivalent to the requested one:"
+ timezone + " VS " + res.getTimeZone());
}
}
}
else
{
if (timezone == null)
{
// If not specified, create a timezone
timezone = TimeZone.getTimeZone(tzId);
}
res = new GregorianCalendar(timezone);
}
// It is possible the previous user changed something in the calendar.
// Clear it.
// @note Actually, it seems even freshly created calendar instances
// should be cleared.
res.clear();
// Force full Gregorian calendar
if (state.alwaysGregorian)
{
res.setGregorianChange(new Date(Long.MIN_VALUE));
}
return res;
}
/**
* Return a GregorianCalendar object identified by id.
* If caching is enabled and an object with the same id existed, it will be returned,
* otherwise a new object will be created.
* @param timezone Timezone to create the calendar in
* @param calId Explicit ID of the calendar. Can be used e.g.
* if more than one copy of the calendar for the same
* timezone is needed.
* Note, if specified, the caller is responsible for
* making sure it's always the same timezone.
* @return The GregorianCalendar object. Note, it can be reused by other
* consumers, so be careful changing any settings in it
*/
public static GregorianCalendar get(TimeZone timezone, String calId)
{
return get(timezone, null, calId);
}
/**
* Return a cached GregorianCalendar object. If doesn't exist, will be created.
* @param timezone Timezone to create the calendar in
* @return The GregorianCalendar object. Note, it can be reused by other
* consumers, so do not change any non-basic settings in it
* (like date).
*/
public static GregorianCalendar get(TimeZone timezone)
{
// Use TimeZone id to lookup the Calendar
return get(timezone, null, timezone.getID());
}
/**
* Return a cached GregorianCalendar object. If doesn't exist, will be created.
* @param tzId The id of the timezone (e.g. "America/Los_Angeles")
* @return The GregorianCalendar object. Note, it can be reused by other
* consumers, so do not change any non-basic settings in it
* (like date).
*/
public static GregorianCalendar get(String tzId)
{
// Pass null as timezone - we'll create it when needed.
// We use tzId also as a calendar ID.
return get(null, tzId, tzId);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy