1package org.bouncycastle.asn1.cms; 2 3import java.text.ParseException; 4import java.text.SimpleDateFormat; 5import java.util.Calendar; 6import java.util.Date; 7import java.util.Locale; 8import java.util.SimpleTimeZone; 9 10import org.bouncycastle.asn1.ASN1Choice; 11import org.bouncycastle.asn1.ASN1GeneralizedTime; 12import org.bouncycastle.asn1.ASN1Object; 13import org.bouncycastle.asn1.ASN1Primitive; 14import org.bouncycastle.asn1.ASN1TaggedObject; 15import org.bouncycastle.asn1.ASN1UTCTime; 16import org.bouncycastle.asn1.DERGeneralizedTime; 17import org.bouncycastle.asn1.DERUTCTime; 18 19/** 20 * <a href="http://tools.ietf.org/html/rfc5652#section-11.3">RFC 5652</a>: 21 * Dual-mode timestamp format producing either UTCTIme or GeneralizedTime. 22 * <p> 23 * <pre> 24 * Time ::= CHOICE { 25 * utcTime UTCTime, 26 * generalTime GeneralizedTime } 27 * </pre> 28 * <p> 29 * This has a constructor using java.util.Date for input which generates 30 * a {@link org.bouncycastle.asn1.DERUTCTime DERUTCTime} object if the 31 * supplied datetime is in range 1950-01-01-00:00:00 UTC until 2049-12-31-23:59:60 UTC. 32 * If the datetime value is outside that range, the generated object will be 33 * {@link org.bouncycastle.asn1.DERGeneralizedTime DERGeneralizedTime}. 34 */ 35public class Time 36 extends ASN1Object 37 implements ASN1Choice 38{ 39 ASN1Primitive time; 40 41 public static Time getInstance( 42 ASN1TaggedObject obj, 43 boolean explicit) 44 { 45 return getInstance(obj.getObject()); 46 } 47 48 /** 49 * @deprecated use getInstance() 50 */ 51 public Time( 52 ASN1Primitive time) 53 { 54 if (!(time instanceof ASN1UTCTime) 55 && !(time instanceof ASN1GeneralizedTime)) 56 { 57 throw new IllegalArgumentException("unknown object passed to Time"); 58 } 59 60 this.time = time; 61 } 62 63 /** 64 * Creates a time object from a given date - if the date is between 1950 65 * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime 66 * is used. 67 * 68 * @param time a date object representing the time of interest. 69 */ 70 public Time( 71 Date time) 72 { 73 SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); 74 // BEGIN android-changed 75 // Was: SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); 76 SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); 77 // END android-changed 78 79 dateF.setTimeZone(tz); 80 81 String d = dateF.format(time) + "Z"; 82 int year = Integer.parseInt(d.substring(0, 4)); 83 84 if (year < 1950 || year > 2049) 85 { 86 this.time = new DERGeneralizedTime(d); 87 } 88 else 89 { 90 this.time = new DERUTCTime(d.substring(2)); 91 } 92 } 93 94 /** 95 * Creates a time object from a given date and locale - if the date is between 1950 96 * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime 97 * is used. You may need to use this constructor if the default locale 98 * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. 99 * 100 * @param time a date object representing the time of interest. 101 * @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value. 102 */ 103 public Time( 104 Date time, 105 Locale locale) 106 { 107 SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); 108 // BEGIN android-changed 109 // Was: SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", locale); 110 SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); 111 dateF.setCalendar(Calendar.getInstance(locale)); 112 // END android-changed 113 114 dateF.setTimeZone(tz); 115 116 String d = dateF.format(time) + "Z"; 117 int year = Integer.parseInt(d.substring(0, 4)); 118 119 if (year < 1950 || year > 2049) 120 { 121 this.time = new DERGeneralizedTime(d); 122 } 123 else 124 { 125 this.time = new DERUTCTime(d.substring(2)); 126 } 127 } 128 129 /** 130 * Return a Time object from the given object. 131 * <p> 132 * Accepted inputs: 133 * <ul> 134 * <li> null → null 135 * <li> {@link Time} object 136 * <li> {@link org.bouncycastle.asn1.DERUTCTime DERUTCTime} object 137 * <li> {@link org.bouncycastle.asn1.DERGeneralizedTime DERGeneralizedTime} object 138 * </ul> 139 * 140 * @param obj the object we want converted. 141 * @exception IllegalArgumentException if the object cannot be converted. 142 */ 143 public static Time getInstance( 144 Object obj) 145 { 146 if (obj == null || obj instanceof Time) 147 { 148 return (Time)obj; 149 } 150 else if (obj instanceof ASN1UTCTime) 151 { 152 return new Time((ASN1UTCTime)obj); 153 } 154 else if (obj instanceof ASN1GeneralizedTime) 155 { 156 return new Time((ASN1GeneralizedTime)obj); 157 } 158 159 throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); 160 } 161 162 /** 163 * Get the date+tine as a String in full form century format. 164 */ 165 public String getTime() 166 { 167 if (time instanceof ASN1UTCTime) 168 { 169 return ((ASN1UTCTime)time).getAdjustedTime(); 170 } 171 else 172 { 173 return ((ASN1GeneralizedTime)time).getTime(); 174 } 175 } 176 177 /** 178 * Get java.util.Date version of date+time. 179 */ 180 public Date getDate() 181 { 182 try 183 { 184 if (time instanceof ASN1UTCTime) 185 { 186 return ((ASN1UTCTime)time).getAdjustedDate(); 187 } 188 else 189 { 190 return ((ASN1GeneralizedTime)time).getDate(); 191 } 192 } 193 catch (ParseException e) 194 { // this should never happen 195 throw new IllegalStateException("invalid date string: " + e.getMessage()); 196 } 197 } 198 199 /** 200 * Produce an object suitable for an ASN1OutputStream. 201 */ 202 public ASN1Primitive toASN1Primitive() 203 { 204 return time; 205 } 206} 207