001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.functions.displayFormatting; 020 021import java.text.DateFormatSymbols; 022import java.text.SimpleDateFormat; 023import java.util.Locale; 024import java.util.TimeZone; 025 026import lucee.commons.date.TimeZoneUtil; 027import lucee.commons.lang.StringUtil; 028import lucee.runtime.PageContext; 029import lucee.runtime.engine.ThreadLocalPageContext; 030import lucee.runtime.exp.ExpressionException; 031import lucee.runtime.exp.PageException; 032import lucee.runtime.functions.BIF; 033import lucee.runtime.op.Caster; 034import lucee.runtime.type.dt.DateTime; 035 036/** 037 * Implements the CFML Function dateformat 038 */ 039public final class DateTimeFormat extends BIF { 040 041 private static final long serialVersionUID = 134840879454373440L; 042 public static final String DEFAULT_MASK = "dd-MMM-yyyy HH:mm:ss";// this is already a SimpleDateFormat mask! 043 private static final String[] AP = new String[]{"A","P"}; 044 045 /** 046 * @param pc 047 * @param object 048 * @return Formated Time Object as String 049 * @throws ExpressionException 050 */ 051 public static String call(PageContext pc , Object object) throws ExpressionException { 052 return invoke(pc,object, null,Locale.US,ThreadLocalPageContext.getTimeZone(pc)); 053 } 054 055 /** 056 * @param pc 057 * @param object 058 * @param mask Characters that show how CFML displays a date: 059 * @return Formated Time Object as String 060 * @throws ExpressionException 061 */ 062 public static String call(PageContext pc , Object object, String mask) throws ExpressionException { 063 return invoke(pc,object,mask,Locale.US,ThreadLocalPageContext.getTimeZone(pc)); 064 } 065 066 public static String call(PageContext pc , Object object, String mask,String strTimezone) throws ExpressionException { 067 return invoke(pc,object,mask, Locale.US,strTimezone==null?ThreadLocalPageContext.getTimeZone(pc):TimeZoneUtil.toTimeZone(strTimezone)); 068 } 069 070 public static String invoke(PageContext pc , Object object, String mask,Locale locale,TimeZone tz) throws ExpressionException { 071 if(locale==null) locale=Locale.US; 072 DateTime datetime = Caster.toDate(object,true,tz,null); 073 if(datetime==null) { 074 if(object.toString().trim().length()==0) return ""; 075 throw new ExpressionException("can't convert value "+object+" to a datetime value"); 076 } 077 java.text.DateFormat format=null; 078 079 if("short".equalsIgnoreCase(mask)) 080 format=java.text.DateFormat.getDateTimeInstance(java.text.DateFormat.SHORT, java.text.DateFormat.SHORT, locale); 081 else if("medium".equalsIgnoreCase(mask)) 082 format=java.text.DateFormat.getDateTimeInstance(java.text.DateFormat.MEDIUM, java.text.DateFormat.MEDIUM, locale); 083 else if("long".equalsIgnoreCase(mask)) 084 format=java.text.DateFormat.getDateTimeInstance(java.text.DateFormat.LONG, java.text.DateFormat.LONG, locale); 085 else if("full".equalsIgnoreCase(mask)) 086 format=java.text.DateFormat.getDateTimeInstance(java.text.DateFormat.FULL, java.text.DateFormat.FULL, locale); 087 else if ("iso8601".equalsIgnoreCase(mask)) 088 format = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssZ" ); 089 else { 090 SimpleDateFormat sdf; 091 format = sdf= new SimpleDateFormat(convertMask(mask), locale); 092 if(mask!=null && StringUtil.indexOfIgnoreCase(mask, "tt")==-1 && StringUtil.indexOfIgnoreCase(mask, "t")!=-1) { 093 DateFormatSymbols dfs = new DateFormatSymbols(locale); 094 dfs.setAmPmStrings(AP); 095 sdf.setDateFormatSymbols(dfs); 096 } 097 } 098 format.setTimeZone(tz); 099 return format.format(datetime); 100 } 101 102 @Override 103 public Object invoke(PageContext pc, Object[] args) throws PageException { 104 if(args.length==1)return call(pc,args[0]); 105 if(args.length==2)return call(pc,args[0],Caster.toString(args[1])); 106 return call(pc,args[0],Caster.toString(args[1]),Caster.toString(args[2])); 107 } 108 109 110 111 private static String convertMask(String mask) { 112 if(mask==null) return DEFAULT_MASK; 113 boolean inside=false; 114 char[] carr = mask.toCharArray(); 115 StringBuilder sb=new StringBuilder(); 116 for(int i=0;i<carr.length;i++){ 117 118 switch(carr[i]){ 119 case 'm': if(!inside){sb.append('M');}else{sb.append(carr[i]);} break; 120 case 'S': if(!inside){sb.append('s');}else{sb.append(carr[i]);} break; 121 case 't': if(!inside){sb.append('a');}else{sb.append(carr[i]);} break; 122 case 'T': if(!inside){sb.append('a');}else{sb.append(carr[i]);} break; 123 case 'n': if(!inside){sb.append('m');}else{sb.append(carr[i]);} break; 124 case 'N': if(!inside){sb.append('m');}else{sb.append(carr[i]);} break; 125 case 'l': if(!inside){sb.append('S');}else{sb.append(carr[i]);} break; 126 case 'L': if(!inside){sb.append('S');}else{sb.append(carr[i]);} break; 127 128 case 'f': if(!inside){sb.append("'f'");}else{sb.append(carr[i]);} break; 129 case 'e': if(!inside){sb.append("'e'");}else{sb.append(carr[i]);} break; 130 131 case 'G': 132 case 'y': 133 case 'M': 134 case 'W': 135 case 'w': 136 case 'D': 137 case 'd': 138 case 'F': 139 case 'E': 140 case 'a': 141 case 'H': 142 case 'h': 143 case 'K': 144 case 'k': 145 case 'Z': 146 case 'z': 147 case 's': 148 //case '.': 149 sb.append(carr[i]); 150 break; 151 152 153 case '\'': 154 if(carr.length-1>i) { 155 if(carr[i+1]=='\'') { 156 i++; 157 sb.append("''"); 158 break; 159 } 160 } 161 162 163 inside=!inside; 164 sb.append(carr[i]); 165 break; 166 /*case '\'': 167 if(carr.length-1>i) { 168 if(carr[i+1]=='\'') { 169 i++; 170 sb.append("''"); 171 break; 172 } 173 } 174 sb.append("''"); 175 break;*/ 176 default: 177 char c=carr[i]; 178 if(!inside && ((c>='a' && c<='z') || (c>='A' && c<='Z'))) 179 sb.append('\'').append(c).append('\''); 180 else 181 sb.append(c); 182 } 183 } 184 return sb.toString(); 185 } 186}