001 package railo.commons.date; 002 003 import java.util.Locale; 004 import java.util.TimeZone; 005 006 import railo.commons.lang.SystemOut; 007 import railo.runtime.engine.ThreadLocalPageContext; 008 import railo.runtime.exp.ExpressionException; 009 import railo.runtime.type.dt.DateTime; 010 import railo.runtime.type.dt.DateTimeImpl; 011 012 public abstract class DateTimeUtil { 013 014 private static final double DAY_MILLIS = 86400000D; 015 private static final long CF_UNIX_OFFSET = 2209161600000L; 016 017 public static final int SECOND = 0; 018 public static final int MINUTE = 1; 019 public static final int HOUR = 2; 020 public static final int DAY = 3; 021 public static final int YEAR = 10; 022 public static final int MONTH = 11; 023 public static final int WEEK = 12; 024 public static final int QUARTER = 20; 025 public static final int MILLISECOND =30; 026 027 028 029 private static DateTimeUtil instance; 030 031 public static DateTimeUtil getInstance(){ 032 if(instance==null) { 033 // try to load Joda Date TimeUtil 034 try{ 035 instance=new JREDateTimeUtil(); 036 SystemOut.printDate("using JRE Date Library"); 037 } 038 // when not available (jar) load Impl that is based on the JRE 039 catch(Throwable t){ 040 instance=new JREDateTimeUtil(); 041 SystemOut.printDate("using JRE Date Library"); 042 } 043 } 044 return instance; 045 } 046 047 public DateTime toDateTime(TimeZone tz,int year, int month, int day, int hour, int minute, int second, int milliSecond) throws DateTimeException { 048 return new DateTimeImpl(toTime(tz,year, month, day, hour, minute, second,milliSecond),false); 049 } 050 051 public DateTime toDateTime(TimeZone tz,int year, int month, int day, int hour, int minute, int second, int milliSecond, DateTime defaultValue) { 052 long time = toTime(tz,year, month, day, hour, minute, second,milliSecond,Long.MIN_VALUE); 053 if(time==Long.MIN_VALUE) return defaultValue; 054 return new DateTimeImpl(time,false); 055 } 056 057 /** 058 * returns a date time instance by a number, the conversion from the double to 059 * date is o the base of the CFML rules. 060 * @param days double value to convert to a number 061 * @return DateTime Instance 062 */ 063 public DateTime toDateTime(double days) { 064 long utc=Math.round(days*DAY_MILLIS); 065 utc-=CF_UNIX_OFFSET; 066 utc-=getLocalTimeZoneOffset(utc); 067 return new DateTimeImpl(utc,false); 068 } 069 070 071 public long toTime(TimeZone tz,int year,int month,int day,int hour,int minute,int second,int milliSecond,long defaultValue){ 072 tz=ThreadLocalPageContext.getTimeZone(tz); 073 year=toYear(year); 074 075 if(month<1) return defaultValue; 076 if(month>12) return defaultValue; 077 if(day<1) return defaultValue; 078 if(hour<0) return defaultValue; 079 if(minute<0) return defaultValue; 080 if(second<0) return defaultValue; 081 if(milliSecond<0) return defaultValue; 082 if(hour>24) return defaultValue; 083 if(minute>59) return defaultValue; 084 if(second>59) return defaultValue; 085 086 if(daysInMonth(year, month)<day) return defaultValue; 087 088 return _toTime(tz, year, month, day, hour, minute, second, milliSecond); 089 } 090 091 public long toTime(TimeZone tz,int year,int month,int day,int hour,int minute,int second,int milliSecond) throws DateTimeException{ 092 tz=ThreadLocalPageContext.getTimeZone(tz); 093 year=toYear(year); 094 095 if(month<1) throw new DateTimeException("month number ["+month+"] must be at least 1"); 096 if(month>12) throw new DateTimeException("month number ["+month+"] can not be greater than 12"); 097 if(day<1) throw new DateTimeException("day number ["+day+"] must be at least 1"); 098 if(hour<0) throw new DateTimeException("hour number ["+hour+"] must be at least 0"); 099 if(minute<0) throw new DateTimeException("minute number ["+minute+"] must be at least 0"); 100 if(second<0) throw new DateTimeException("second number ["+second+"] must be at least 0"); 101 if(milliSecond<0)throw new DateTimeException("milli second number ["+milliSecond+"] must be at least 0"); 102 103 if(hour>24) throw new DateTimeException("hour number ["+hour+"] can not be greater than 24"); 104 if(minute>59) throw new DateTimeException("minute number ["+minute+"] can not be greater than 59"); 105 if(second>59) throw new DateTimeException("second number ["+second+"] can not be greater than 59"); 106 107 if(daysInMonth(year, month)<day) 108 throw new DateTimeException("day number ["+day+"] can not be greater than "+daysInMonth(year, month)+" when month is "+month+" and year "+year); 109 110 return _toTime(tz, year, month, day, hour, minute, second, milliSecond); 111 } 112 113 /** 114 * return how much days given month in given year has 115 * @param year 116 * @param month 117 * @return 118 */ 119 public int daysInMonth(int year,int month){ 120 switch(month) { 121 case 1: 122 case 3: 123 case 5: 124 case 7: 125 case 8: 126 case 10: 127 case 12: 128 return 31; 129 case 4: 130 case 6: 131 case 9: 132 case 11: 133 return 30; 134 case 2: 135 return isLeapYear(year)?29:28; 136 } 137 return -1; 138 } 139 140 /** 141 * translate 2 digit numbers to a year; for example 10 to 2010 or 50 to 1950 142 * @param year 143 * @return year matching number 144 */ 145 public int toYear(int year) { 146 if(year<100) { 147 if(year<30)year=year+=2000; 148 else year=year+=1900; 149 } 150 return year; 151 } 152 153 /** 154 * return if given is is a leap year or not 155 * @param year 156 * @return is leap year 157 */ 158 public boolean isLeapYear(int year) { 159 return ((year%4 == 0) && ((year%100 != 0) || (year%400 == 0))); 160 } 161 162 /** 163 * cast boolean value 164 * @param dateTime 165 * @return boolean value 166 * @throws ExpressionException 167 */ 168 public boolean toBooleanValue(DateTime dateTime) throws DateTimeException { 169 throw new DateTimeException("can't cast Date ["+dateTime.toGMTString()+"] to boolean value"); 170 } 171 172 public double toDoubleValue(DateTime dateTime) { 173 long utc = dateTime.getTime(); 174 utc+=getLocalTimeZoneOffset (utc); 175 utc+=CF_UNIX_OFFSET; 176 return utc/DAY_MILLIS; 177 } 178 179 private static long getLocalTimeZoneOffset(long utc){ 180 return ThreadLocalPageContext.getTimeZone().getOffset(utc); 181 } 182 183 184 public long getMilliSecondsAdMidnight(TimeZone timeZone, long time) { 185 return time-getMilliSecondsInDay(timeZone, time); 186 } 187 188 abstract long _toTime(TimeZone tz,int year,int month,int day,int hour,int minute,int second,int milliSecond); 189 190 public abstract int getYear(TimeZone tz,railo.runtime.type.dt.DateTime dt); 191 192 public abstract int getMonth(TimeZone tz,DateTime dt); 193 194 public abstract int getDay(TimeZone tz,DateTime dt); 195 196 public abstract int getHour(TimeZone tz,DateTime dt); 197 198 public abstract int getMinute(TimeZone tz,DateTime dt); 199 200 public abstract int getSecond(TimeZone tz,DateTime dt); 201 202 public abstract int getMilliSecond(TimeZone tz,DateTime dt); 203 204 public abstract long getMilliSecondsInDay(TimeZone tz, long time); 205 206 public abstract int getDaysInMonth(TimeZone tz,DateTime dt); 207 208 public abstract int getDayOfYear(Locale locale,TimeZone tz, DateTime dt); 209 210 public abstract int getDayOfWeek(Locale locale,TimeZone tz, DateTime dt); 211 212 public abstract int getWeekOfYear(Locale locale,TimeZone tz,DateTime dt); 213 214 public abstract long getDiff(TimeZone tz, int datePart,DateTime left,DateTime right); 215 216 public abstract String toString(DateTime dt, TimeZone tz); 217 218 219 }