DERUTCTime.java revision c37f4a04ef89e73a39a59f3c5a179af8c8ab5974
1package org.bouncycastle.asn1; 2 3import java.io.IOException; 4import java.text.ParseException; 5import java.text.SimpleDateFormat; 6import java.util.Date; 7import java.util.SimpleTimeZone; 8 9/** 10 * UTC time object. 11 */ 12public class DERUTCTime 13 extends ASN1Object 14{ 15 String time; 16 17 /** 18 * return an UTC Time from the passed in object. 19 * 20 * @exception IllegalArgumentException if the object cannot be converted. 21 */ 22 public static DERUTCTime getInstance( 23 Object obj) 24 { 25 if (obj == null || obj instanceof DERUTCTime) 26 { 27 return (DERUTCTime)obj; 28 } 29 30 if (obj instanceof ASN1OctetString) 31 { 32 return new DERUTCTime(((ASN1OctetString)obj).getOctets()); 33 } 34 35 throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 36 } 37 38 /** 39 * return an UTC Time from a tagged object. 40 * 41 * @param obj the tagged object holding the object we want 42 * @param explicit true if the object is meant to be explicitly 43 * tagged false otherwise. 44 * @exception IllegalArgumentException if the tagged object cannot 45 * be converted. 46 */ 47 public static DERUTCTime getInstance( 48 ASN1TaggedObject obj, 49 boolean explicit) 50 { 51 return getInstance(obj.getObject()); 52 } 53 54 /** 55 * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were 56 * never encoded. When you're creating one of these objects from scratch, that's 57 * what you want to use, otherwise we'll try to deal with whatever gets read from 58 * the input stream... (this is why the input format is different from the getTime() 59 * method output). 60 * <p> 61 * 62 * @param time the time string. 63 */ 64 public DERUTCTime( 65 String time) 66 { 67 this.time = time; 68 try 69 { 70 this.getDate(); 71 } 72 catch (ParseException e) 73 { 74 throw new IllegalArgumentException("invalid date string: " + e.getMessage()); 75 } 76 } 77 78 /** 79 * base constructer from a java.util.date object 80 */ 81 public DERUTCTime( 82 Date time) 83 { 84 SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'"); 85 86 dateF.setTimeZone(new SimpleTimeZone(0,"Z")); 87 88 this.time = dateF.format(time); 89 } 90 91 DERUTCTime( 92 byte[] bytes) 93 { 94 // 95 // explicitly convert to characters 96 // 97 char[] dateC = new char[bytes.length]; 98 99 for (int i = 0; i != dateC.length; i++) 100 { 101 dateC[i] = (char)(bytes[i] & 0xff); 102 } 103 104 this.time = new String(dateC); 105 } 106 107 /** 108 * return the time as a date based on whatever a 2 digit year will return. For 109 * standardised processing use getAdjustedDate(). 110 * 111 * @return the resulting date 112 * @exception ParseException if the date string cannot be parsed. 113 */ 114 public Date getDate() 115 throws ParseException 116 { 117 SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz"); 118 119 return dateF.parse(getTime()); 120 } 121 122 /** 123 * return the time as an adjusted date 124 * in the range of 1950 - 2049. 125 * 126 * @return a date in the range of 1950 to 2049. 127 * @exception ParseException if the date string cannot be parsed. 128 */ 129 public Date getAdjustedDate() 130 throws ParseException 131 { 132 SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); 133 134 dateF.setTimeZone(new SimpleTimeZone(0, "Z")); 135 136 return dateF.parse(getAdjustedTime()); 137 } 138 139 /** 140 * return the time - always in the form of 141 * YYMMDDhhmmssGMT(+hh:mm|-hh:mm). 142 * <p> 143 * Normally in a certificate we would expect "Z" rather than "GMT", 144 * however adding the "GMT" means we can just use: 145 * <pre> 146 * dateF = new SimpleDateFormat("yyMMddHHmmssz"); 147 * </pre> 148 * To read in the time and get a date which is compatible with our local 149 * time zone. 150 * <p> 151 * <b>Note:</b> In some cases, due to the local date processing, this 152 * may lead to unexpected results. If you want to stick the normal 153 * convention of 1950 to 2049 use the getAdjustedTime() method. 154 */ 155 public String getTime() 156 { 157 // 158 // standardise the format. 159 // 160 if (time.indexOf('-') < 0 && time.indexOf('+') < 0) 161 { 162 if (time.length() == 11) 163 { 164 return time.substring(0, 10) + "00GMT+00:00"; 165 } 166 else 167 { 168 return time.substring(0, 12) + "GMT+00:00"; 169 } 170 } 171 else 172 { 173 int index = time.indexOf('-'); 174 if (index < 0) 175 { 176 index = time.indexOf('+'); 177 } 178 String d = time; 179 180 if (index == time.length() - 3) 181 { 182 d += "00"; 183 } 184 185 if (index == 10) 186 { 187 return d.substring(0, 10) + "00GMT" + d.substring(10, 13) + ":" + d.substring(13, 15); 188 } 189 else 190 { 191 return d.substring(0, 12) + "GMT" + d.substring(12, 15) + ":" + d.substring(15, 17); 192 } 193 } 194 } 195 196 /** 197 * return a time string as an adjusted date with a 4 digit year. This goes 198 * in the range of 1950 - 2049. 199 */ 200 public String getAdjustedTime() 201 { 202 String d = this.getTime(); 203 204 if (d.charAt(0) < '5') 205 { 206 return "20" + d; 207 } 208 else 209 { 210 return "19" + d; 211 } 212 } 213 214 private byte[] getOctets() 215 { 216 char[] cs = time.toCharArray(); 217 byte[] bs = new byte[cs.length]; 218 219 for (int i = 0; i != cs.length; i++) 220 { 221 bs[i] = (byte)cs[i]; 222 } 223 224 return bs; 225 } 226 227 void encode( 228 DEROutputStream out) 229 throws IOException 230 { 231 out.writeEncoded(UTC_TIME, this.getOctets()); 232 } 233 234 boolean asn1Equals( 235 DERObject o) 236 { 237 if (!(o instanceof DERUTCTime)) 238 { 239 return false; 240 } 241 242 return time.equals(((DERUTCTime)o).time); 243 } 244 245 public int hashCode() 246 { 247 return time.hashCode(); 248 } 249 250 public String toString() 251 { 252 return time; 253 } 254} 255