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