1 package org.bouncycastle.asn1.x509; 2 3 import java.text.ParseException; 4 import java.text.SimpleDateFormat; 5 // Android-added: Localization support 6 import java.util.Calendar; 7 import java.util.Date; 8 import java.util.Locale; 9 import java.util.SimpleTimeZone; 10 11 import org.bouncycastle.asn1.ASN1Choice; 12 import org.bouncycastle.asn1.ASN1GeneralizedTime; 13 import org.bouncycastle.asn1.ASN1Object; 14 import org.bouncycastle.asn1.ASN1Primitive; 15 import org.bouncycastle.asn1.ASN1TaggedObject; 16 import org.bouncycastle.asn1.ASN1UTCTime; 17 import org.bouncycastle.asn1.DERGeneralizedTime; 18 import org.bouncycastle.asn1.DERUTCTime; 19 20 public class Time 21 extends ASN1Object 22 implements ASN1Choice 23 { 24 ASN1Primitive time; 25 26 public static Time getInstance( 27 ASN1TaggedObject obj, 28 boolean explicit) 29 { 30 return getInstance(obj.getObject()); // must be explicitly tagged 31 } 32 33 public Time( 34 ASN1Primitive time) 35 { 36 if (!(time instanceof ASN1UTCTime) 37 && !(time instanceof ASN1GeneralizedTime)) 38 { 39 throw new IllegalArgumentException("unknown object passed to Time"); 40 } 41 42 this.time = time; 43 } 44 45 /** 46 * Creates a time object from a given date - if the date is between 1950 47 * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime 48 * is used. 49 * 50 * @param time a date object representing the time of interest. 51 */ 52 public Time( 53 Date time) 54 { 55 SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); 56 // Android-changed: Use localized version 57 // SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); 58 SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); 59 60 dateF.setTimeZone(tz); 61 62 String d = dateF.format(time) + "Z"; 63 int year = Integer.parseInt(d.substring(0, 4)); 64 65 if (year < 1950 || year > 2049) 66 { 67 this.time = new DERGeneralizedTime(d); 68 } 69 else 70 { 71 this.time = new DERUTCTime(d.substring(2)); 72 } 73 } 74 75 /** 76 * Creates a time object from a given date and locale - if the date is between 1950 77 * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime 78 * is used. You may need to use this constructor if the default locale 79 * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. 80 * 81 * @param time a date object representing the time of interest. 82 * @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value. 83 */ 84 public Time( 85 Date time, 86 Locale locale) 87 { 88 SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); 89 // BEGIN Android-changed: Use localized version 90 // SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", locale); 91 SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); 92 dateF.setCalendar(Calendar.getInstance(locale)); 93 // END android-changed 94 95 dateF.setTimeZone(tz); 96 97 String d = dateF.format(time) + "Z"; 98 int year = Integer.parseInt(d.substring(0, 4)); 99 100 if (year < 1950 || year > 2049) 101 { 102 this.time = new DERGeneralizedTime(d); 103 } 104 else 105 { 106 this.time = new DERUTCTime(d.substring(2)); 107 } 108 } 109 110 public static Time getInstance( 111 Object obj) 112 { 113 if (obj == null || obj instanceof Time) 114 { 115 return (Time)obj; 116 } 117 else if (obj instanceof ASN1UTCTime) 118 { 119 return new Time((ASN1UTCTime)obj); 120 } 121 else if (obj instanceof ASN1GeneralizedTime) 122 { 123 return new Time((ASN1GeneralizedTime)obj); 124 } 125 126 throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); 127 } 128 129 public String getTime() 130 { 131 if (time instanceof ASN1UTCTime) 132 { 133 return ((ASN1UTCTime)time).getAdjustedTime(); 134 } 135 else 136 { 137 return ((ASN1GeneralizedTime)time).getTime(); 138 } 139 } 140 141 public Date getDate() 142 { 143 try 144 { 145 if (time instanceof ASN1UTCTime) 146 { 147 return ((ASN1UTCTime)time).getAdjustedDate(); 148 } 149 else 150 { 151 return ((ASN1GeneralizedTime)time).getDate(); 152 } 153 } 154 catch (ParseException e) 155 { // this should never happen 156 throw new IllegalStateException("invalid date string: " + e.getMessage()); 157 } 158 } 159 160 /** 161 * Produce an object suitable for an ASN1OutputStream. 162 * <pre> 163 * Time ::= CHOICE { 164 * utcTime UTCTime, 165 * generalTime GeneralizedTime } 166 * </pre> 167 */ 168 public ASN1Primitive toASN1Primitive() 169 { 170 return time; 171 } 172 173 public String toString() 174 { 175 return getTime(); 176 } 177 } 178