001/* 002 * Copyright (c) 2009-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2015-07-15 00:38:07 +0000 (Wed, 15 Jul 2015) $' 007 * '$Revision: 33547 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.kepler.date; 031 032import java.text.ParseException; 033import java.text.SimpleDateFormat; 034import java.util.Arrays; 035import java.util.Date; 036import java.util.TimeZone; 037 038import ptolemy.actor.lib.LimitedFiringSource; 039import ptolemy.actor.parameters.PortParameter; 040import ptolemy.data.DateToken; 041import ptolemy.data.StringToken; 042import ptolemy.data.expr.StringParameter; 043import ptolemy.data.type.BaseType; 044import ptolemy.kernel.CompositeEntity; 045import ptolemy.kernel.util.Attribute; 046import ptolemy.kernel.util.IllegalActionException; 047import ptolemy.kernel.util.NameDuplicationException; 048import ptolemy.kernel.util.Workspace; 049 050/** 051 * Create a date token. If a date string is not given on <i>input</i>, the 052 * current date and time is used. 053 * 054 * @author Daniel Crawl 055 * @version $Id: CreateDate.java 33547 2015-07-15 00:38:07Z crawl $ 056 */ 057 058public class CreateDate extends LimitedFiringSource { 059 060 /** 061 * Construct a CreateDate with the given container and name. 062 * 063 * @param name 064 * The name of this actor. 065 * @exception IllegalActionException 066 * If the entity cannot be contained by the proposed 067 * container. 068 * @exception NameDuplicationException 069 * If the container already has an actor with this name. 070 */ 071 public CreateDate(CompositeEntity container, String name) 072 throws NameDuplicationException, IllegalActionException { 073 super(container, name); 074 075 inputFormat = new PortParameter(this, "format"); 076 inputFormat.setStringMode(true); 077 inputFormat.getPort().setTypeEquals(BaseType.STRING); 078 new Attribute(inputFormat.getPort(), "_showName"); 079 080 for (int i = 0; i < dateFormats.length; i++) { 081 inputFormat.addChoice(dateFormats[i]); 082 } 083 084 input = new PortParameter(this, "input"); 085 input.setStringMode(true); 086 input.getPort().setTypeEquals(BaseType.STRING); 087 new Attribute(input.getPort(), "_showName"); 088 089 output.setTypeEquals(BaseType.DATE); 090 output.setMultiport(true); 091 output.setDefaultWidth(1); 092 093 defaultTimezone = new StringParameter(this, "defaultTimezone"); 094 String[] timezones = TimeZone.getAvailableIDs(); 095 Arrays.sort(timezones); 096 for(String timeZoneID : timezones) { 097 defaultTimezone.addChoice(timeZoneID); 098 } 099 // set the default 100 defaultTimezone.setExpression(TimeZone.getDefault().getID()); 101 102 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"0\" y=\"0\" " 103 + "width=\"60\" height=\"20\" " + "style=\"fill:white\"/>\n" 104 + "</svg>\n"); 105 } 106 107 // ///////////////////////////////////////////////////////////////// 108 // // ports and parameters //// 109 110 /** 111 * A string date and time. If not used, the current date and time is used. 112 */ 113 public PortParameter input; 114 115 /** 116 * The format of the input date and time. See java.text.SimpleDateFormat for 117 * the syntax. 118 */ 119 public PortParameter inputFormat; 120 121 /** The time zone to use when <i>inputFormat</i> is specified, but no time 122 * zone is found in the format (specified with 'z' or 'Z'). This value is 123 * not used when <i>inputFormat</i> is the milliseconds or seconds since 124 * the epoch. 125 */ 126 public StringParameter defaultTimezone; 127 128 // ///////////////////////////////////////////////////////////////// 129 // // public methods //// 130 131 /** React to an attribute change. */ 132 @Override 133 public void attributeChanged(Attribute attribute) throws IllegalActionException { 134 135 if(attribute == defaultTimezone) { 136 String str = defaultTimezone.stringValue(); 137 if(str.trim().isEmpty()) { 138 _defaultTimeZone = TimeZone.getDefault(); 139 } else { 140 // make sure it's valid 141 boolean found = false; 142 final String[] timezones = TimeZone.getAvailableIDs(); 143 for(String timezone : timezones) { 144 if(timezone.equals(str)) { 145 found = true; 146 break; 147 } 148 } 149 if(!found) { 150 throw new IllegalActionException(this, "Unknown time zone: " + str); 151 } 152 _defaultTimeZone = TimeZone.getTimeZone(str); 153 } 154 } else { 155 super.attributeChanged(attribute); 156 } 157 158 } 159 160 /** Clone the actor into the specified workspace. */ 161 @Override 162 public Object clone(Workspace workspace) throws CloneNotSupportedException { 163 CreateDate newObject = (CreateDate) super.clone(workspace); 164 newObject._defaultTimeZone = TimeZone.getDefault(); 165 return newObject; 166 } 167 168 /** Create a date token. */ 169 @Override 170 public void fire() throws IllegalActionException { 171 super.fire(); 172 173 inputFormat.update(); 174 input.update(); 175 176 Date outDate; 177 178 // see if there's input 179 String dateStr = ((StringToken) input.getToken()).stringValue(); 180 if (dateStr.equals("")) { 181 // output the current date/time. 182 outDate = new Date(); 183 } else { 184 // see if there's a format 185 String formatStr = ((StringToken) inputFormat.getToken()) 186 .stringValue(); 187 if (formatStr.equals("")) { 188 // no format specified, so use default 189 SimpleDateFormat sdf = new SimpleDateFormat(); 190 sdf.setTimeZone(_defaultTimeZone); 191 try { 192 outDate = sdf.parse(dateStr); 193 } catch (ParseException e) { 194 throw new IllegalActionException(this, e, "Error parsing date string."); 195 } 196 } else if (formatStr.equals(MS_SINCE_EPOCH)) { 197 // first parse as a double since the parser 198 // for longs cannot handle scientific notation. 199 long millisec = new Double(dateStr).longValue(); 200 outDate = new Date(millisec); 201 } else if (formatStr.equals(S_SINCE_EPOCH)) { 202 long sec = new Double(dateStr).longValue(); 203 outDate = new Date(sec * 1000); 204 } else { 205 try { 206 SimpleDateFormat sdf = new SimpleDateFormat(formatStr); 207 208 // see if the format contains the time zone 209 if(!formatStr.contains("z") && !formatStr.contains("Z")) { 210 sdf.setTimeZone(_defaultTimeZone); 211 } 212 213 outDate = sdf.parse(dateStr); 214 215 } catch (IllegalArgumentException e) { 216 throw new IllegalActionException(this, e, 217 "Error in input format."); 218 } catch (ParseException e) { 219 throw new IllegalActionException(this, e, 220 "Error parsing input date."); 221 } 222 } 223 } 224 225 output.broadcast(new DateToken(outDate.getTime())); 226 } 227 228 /** Constant string for special case of milliseconds since epoch. 229 * There does not appear to be formatting symbols for this. 230 */ 231 public final static String MS_SINCE_EPOCH = "milliseconds since epoch"; 232 233 /** Constant string for seconds since epoch. */ 234 public final static String S_SINCE_EPOCH = "seconds since epoch"; 235 236 /** Common date formats. 237 * @see java.text.SimpleDateFormat 238 */ 239 final static String[] dateFormats = { "MM-dd-yyyy", "MM-dd-yy", 240 "yyyyMMdd", "yyyy.MM.dd G 'at' HH:mm:ss z", "EEE, MMM d, ''yy", 241 "h:mm a", "hh 'o''clock' a, zzzz", "K:mm a, z", 242 "yyyyy.MMMMM.dd GGG hh:mm aaa", "EEE, d MMM yyyy HH:mm:ss Z", 243 "yyMMddHHmmssZ", "yyyy-MM-dd'T'HH:mm:ss.SSSZ", MS_SINCE_EPOCH, 244 S_SINCE_EPOCH }; 245 246 /** The time zone to use when a format is specified without a timezone. TODO */ 247 private TimeZone _defaultTimeZone = TimeZone.getDefault(); 248}