/**
* Copyright (c) 2014, the Railo Company Ltd.
* Copyright (c) 2015, Lucee Assosication Switzerland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
package lucee.commons.date;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import lucee.runtime.PageContext;
import lucee.runtime.PageContextImpl;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.op.Caster;
import lucee.runtime.type.dt.DateTime;
public class JREDateTimeUtil extends DateTimeUtil {
private static CalendarThreadLocal _calendar=new CalendarThreadLocal();
private static CalendarThreadLocal calendar=new CalendarThreadLocal();
private static LocaleCalendarThreadLocal _localeCalendar=new LocaleCalendarThreadLocal();
private static LocaleCalendarThreadLocal localeCalendar=new LocaleCalendarThreadLocal();
//Calendar string;
JREDateTimeUtil() {
}
@Override
long _toTime(TimeZone tz, int year, int month, int day, int hour,int minute, int second, int milliSecond) {
if(tz==null)tz=ThreadLocalPageContext.getTimeZone(tz);
Calendar time = _getThreadCalendar((PageContext)null,tz);
time.set(year,month-1,day,hour,minute,second);
time.set(Calendar.MILLISECOND,milliSecond);
return time.getTimeInMillis();
}
private static int _get(TimeZone tz, DateTime dt, int field) {
Calendar c = _getThreadCalendar((PageContext)null,tz);
c.setTimeInMillis(dt.getTime());
return c.get(field);
}
private static void _set(TimeZone tz, DateTime dt, int value, int field) {
Calendar c = _getThreadCalendar((PageContext)null,tz);
c.setTimeInMillis(dt.getTime());
c.set(field, value);
dt.setTime(c.getTimeInMillis());
}
private static int _get(Locale l,TimeZone tz, DateTime dt, int field) {
Calendar c = _getThreadCalendar(l,tz);
c.setTimeInMillis(dt.getTime());
return c.get(field);
}
@Override
public int getYear(TimeZone tz, DateTime dt) {
return _get(tz,dt,Calendar.YEAR);
}
@Override
public void setYear(TimeZone tz, DateTime dt, int value) {
_set(tz,dt,value,Calendar.YEAR);
}
@Override
public int getMonth(TimeZone tz, DateTime dt) {
return _get(tz,dt,Calendar.MONTH)+1;
}
@Override
public void setMonth(TimeZone tz, DateTime dt, int value) {
_set(tz,dt,value-1,Calendar.MONTH);
}
@Override
public int getDay(TimeZone tz, DateTime dt) {
return _get(tz,dt,Calendar.DAY_OF_MONTH);
}
@Override
public void setDay(TimeZone tz, DateTime dt, int value) {
_set(tz,dt,value,Calendar.DAY_OF_MONTH);
}
@Override
public int getHour(TimeZone tz, DateTime dt) {
return _get(tz,dt,Calendar.HOUR_OF_DAY);
}
@Override
public void setHour(TimeZone tz, DateTime dt, int value) {
_set(tz,dt,value,Calendar.HOUR_OF_DAY);
}
@Override
public int getMinute(TimeZone tz, DateTime dt) {
return _get(tz,dt,Calendar.MINUTE);
}
@Override
public void setMinute(TimeZone tz, DateTime dt, int value) {
_set(tz,dt,value,Calendar.MINUTE);
}
@Override
public int getSecond(TimeZone tz, DateTime dt) {
return _get(tz,dt,Calendar.SECOND);
}
@Override
public void setSecond(TimeZone tz, DateTime dt, int value) {
_set(tz,dt,value,Calendar.SECOND);
}
@Override
public int getMilliSecond(TimeZone tz, DateTime dt) {
return _get(tz,dt,Calendar.MILLISECOND);
}
@Override
public void setMilliSecond(TimeZone tz, DateTime dt, int value) {
_set(tz,dt,value,Calendar.MILLISECOND);
}
@Override
public synchronized int getDayOfYear(Locale locale,TimeZone tz, DateTime dt) {
return _get(locale,tz,dt,Calendar.DAY_OF_YEAR);
}
@Override
public synchronized int getDayOfWeek(Locale locale,TimeZone tz, DateTime dt) {
return _get(locale,tz,dt,Calendar.DAY_OF_WEEK);
}
@Override
public synchronized int getFirstDayOfMonth(TimeZone tz, DateTime dt) {
Calendar c = _getThreadCalendar((PageContext)null,tz);
c.setTimeInMillis(dt.getTime());
c.set(Calendar.DATE,1);
return c.get(Calendar.DAY_OF_YEAR);
}
@Override
public synchronized int getWeekOfYear(Locale locale,TimeZone tz, DateTime dt) {
Calendar c=_getThreadCalendar(locale,tz);
c.setTimeInMillis(dt.getTime());
int week=c.get(Calendar.WEEK_OF_YEAR);
if(week==1 && c.get(Calendar.MONTH)==Calendar.DECEMBER) {
if(isLeapYear(c.get(Calendar.YEAR)) && c.get(Calendar.DAY_OF_WEEK)==1){
return 54;
}
return 53;
}
return week;
}
@Override
public synchronized long getMilliSecondsInDay(TimeZone tz,long time) {
Calendar c = _getThreadCalendar((PageContext)null,tz);
c.setTimeInMillis(time);
return (c.get(Calendar.HOUR_OF_DAY)*3600000)+
(c.get(Calendar.MINUTE)*60000)+
(c.get(Calendar.SECOND)*1000)+
(c.get(Calendar.MILLISECOND));
}
@Override
public synchronized int getDaysInMonth(TimeZone tz, DateTime dt) {
Calendar c = _getThreadCalendar((PageContext)null,tz);
c.setTimeInMillis(dt.getTime());
return daysInMonth(c.get(Calendar.YEAR), c.get(Calendar.MONTH)+1);
}
@Override
public String toString(PageContext pc,DateTime dt, TimeZone tz, Boolean addTimeZoneOffset) {
Calendar c = _getThreadCalendar(pc,tz);
c.setTimeInMillis(dt.getTime());
//"HH:mm:ss"
StringBuilder sb=new StringBuilder();
sb.append("{ts '");
toString(sb,c.get(Calendar.YEAR),4);
sb.append("-");
toString(sb,c.get(Calendar.MONTH)+1,2);
sb.append("-");
toString(sb,c.get(Calendar.DATE),2);
sb.append(" ");
toString(sb,c.get(Calendar.HOUR_OF_DAY),2);
sb.append(":");
toString(sb,c.get(Calendar.MINUTE),2);
sb.append(":");
toString(sb,c.get(Calendar.SECOND),2);
if(addTimeZoneOffset!=Boolean.FALSE) {
if(addTimeZoneOffset==null && pc!=null) addTimeZoneOffset=((PageContextImpl)pc).getTimestampWithTSOffset();
if(addTimeZoneOffset==Boolean.TRUE) addTimeZoneOffset(c,sb);
}
sb.append("'}");
return sb.toString();
}
/*public static void main(String[] args) {
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("Pacific/Marquesas"));
//c = Calendar.getInstance(TimeZoneConstants.AUSTRALIA_DARWIN);
c.setTimeInMillis(0);
print.e(c.getTimeZone());
print.e(toTimeZoneOffset(c));
print.e(c.get(Calendar.ZONE_OFFSET)+c.get(Calendar.DST_OFFSET) );
print.e(c.getTimeZone().getOffset(c.getTimeInMillis()));
c.set(Calendar.MONTH,7);
print.e(c.get(Calendar.ZONE_OFFSET)+c.get(Calendar.DST_OFFSET) );
print.e(c.getTimeZone().getOffset(c.getTimeInMillis()));
}*/
private void addTimeZoneOffset(Calendar c, StringBuilder sb) {
int min = (c.get(Calendar.ZONE_OFFSET)+c.get(Calendar.DST_OFFSET))/60000;
char op;
if(min<0) {
op='-';
min=min-min-min;
}
else op='+';
int hours=min/60;
min=min-(hours*60);
sb.append(op);
toString(sb,hours,2);
sb.append(':');
toString(sb,min,2);
}
public static Calendar newInstance(TimeZone tz,Locale l) {
if(tz==null)tz=ThreadLocalPageContext.getTimeZone();
return Calendar.getInstance(tz,l);
}
/**
* important:this function returns always the same instance for a specific thread,
* so make sure only use one thread calendar instance at time.
* @return calendar instance
*/
public static Calendar getThreadCalendar(){
Calendar c = calendar.get();
c.clear();
return c;
}
/**
* important:this function returns always the same instance for a specific thread,
* so make sure only use one thread calendar instance at time.
* @return calendar instance
*/
public static Calendar getThreadCalendar(TimeZone tz){
Calendar c = calendar.get();
c.clear();
if(tz==null)tz=ThreadLocalPageContext.getTimeZone();
c.setTimeZone(tz);
return c;
}
/**
* important:this function returns always the same instance for a specific thread,
* so make sure only use one thread calendar instance at time.
* @return calendar instance
*/
public static Calendar getThreadCalendar(Locale l,TimeZone tz){
if(tz==null)tz=ThreadLocalPageContext.getTimeZone();
Calendar c = localeCalendar.get(tz,l);
c.setTimeZone(tz);
return c;
}
/*
* internally we use a other instance to avoid conflicts
*/
private static Calendar _getThreadCalendar(PageContext pc, TimeZone tz){
Calendar c = _calendar.get();
c.clear();
if(tz==null)tz=ThreadLocalPageContext.getTimeZone(pc);
c.setTimeZone(tz);
return c;
}
/*
* internally we use a other instance to avoid conflicts
*/
private static Calendar _getThreadCalendar(Locale l,TimeZone tz){
Calendar c = _localeCalendar.get(tz,l);
if(tz==null)tz=ThreadLocalPageContext.getTimeZone();
c.setTimeZone(tz);
return c;
}
static void toString(StringBuilder sb,int i, int amount) {
String str = Caster.toString(i);
amount = amount - str.length();
while( amount-- > 0 ){
sb.append( '0');
}
sb.append(str);
}
}
class CalendarThreadLocal extends ThreadLocal<Calendar> {
@Override
protected synchronized Calendar initialValue() {
return Calendar.getInstance();
}
}
class LocaleCalendarThreadLocal extends ThreadLocal<Map<String,Calendar>> {
@Override
protected synchronized Map<String,Calendar> initialValue() {
return new HashMap<String, Calendar>();
}
public Calendar get(TimeZone tz,Locale l) {
Map<String, Calendar> map = get();
Calendar c = map.get(l+":"+tz);
if(c==null) {
c=JREDateTimeUtil.newInstance(tz,l);
map.put(l+":"+tz, c);
}
else c.clear();
return c;
}
}