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