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