1package org.bouncycastle.asn1;
2
3import java.io.IOException;
4import java.text.SimpleDateFormat;
5import java.util.Date;
6import java.util.SimpleTimeZone;
7
8/**
9 * UTC time object.
10 */
11public class DERUTCTime
12    extends DERObject
13{
14    String      time;
15
16    /**
17     * return an UTC Time from the passed in object.
18     *
19     * @exception IllegalArgumentException if the object cannot be converted.
20     */
21    public static DERUTCTime getInstance(
22        Object  obj)
23    {
24        if (obj == null || obj instanceof DERUTCTime)
25        {
26            return (DERUTCTime)obj;
27        }
28
29        if (obj instanceof ASN1OctetString)
30        {
31            return new DERUTCTime(((ASN1OctetString)obj).getOctets());
32        }
33
34        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
35    }
36
37    /**
38     * return an UTC Time from a tagged object.
39     *
40     * @param obj the tagged object holding the object we want
41     * @param explicit true if the object is meant to be explicitly
42     *              tagged false otherwise.
43     * @exception IllegalArgumentException if the tagged object cannot
44     *               be converted.
45     */
46    public static DERUTCTime getInstance(
47        ASN1TaggedObject obj,
48        boolean          explicit)
49    {
50        return getInstance(obj.getObject());
51    }
52
53    /**
54     * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were
55     * never encoded. When you're creating one of these objects from scratch, that's
56     * what you want to use, otherwise we'll try to deal with whatever gets read from
57     * the input stream... (this is why the input format is different from the getTime()
58     * method output).
59     * <p>
60     *
61     * @param time the time string.
62     */
63    public DERUTCTime(
64        String  time)
65    {
66        this.time = time;
67    }
68
69    /**
70     * base constructer from a java.util.date object
71     */
72    public DERUTCTime(
73        Date time)
74    {
75        SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'");
76
77        dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
78
79        this.time = dateF.format(time);
80    }
81
82    DERUTCTime(
83        byte[]  bytes)
84    {
85        //
86        // explicitly convert to characters
87        //
88        char[]  dateC = new char[bytes.length];
89
90        for (int i = 0; i != dateC.length; i++)
91        {
92            dateC[i] = (char)(bytes[i] & 0xff);
93        }
94
95        this.time = new String(dateC);
96    }
97
98    /**
99     * return the time - always in the form of
100     *  YYMMDDhhmmssGMT(+hh:mm|-hh:mm).
101     * <p>
102     * Normally in a certificate we would expect "Z" rather than "GMT",
103     * however adding the "GMT" means we can just use:
104     * <pre>
105     *     dateF = new SimpleDateFormat("yyMMddHHmmssz");
106     * </pre>
107     * To read in the time and get a date which is compatible with our local
108     * time zone.
109     * <p>
110     * <b>Note:</b> In some cases, due to the local date processing, this
111     * may lead to unexpected results. If you want to stick the normal
112     * convention of 1950 to 2049 use the getAdjustedTime() method.
113     */
114    public String getTime()
115    {
116        //
117        // standardise the format.
118        //
119        if (time.length() == 11)
120        {
121            return time.substring(0, 10) + "00GMT+00:00";
122        }
123        else if (time.length() == 13)
124        {
125            return time.substring(0, 12) + "GMT+00:00";
126        }
127        else if (time.length() == 17)
128        {
129            return time.substring(0, 12) + "GMT" + time.substring(12, 15) + ":" + time.substring(15, 17);
130        }
131
132        return time;
133    }
134
135    /**
136     * return the time as an adjusted date with a 4 digit year. This goes
137     * in the range of 1950 - 2049.
138     */
139    public String getAdjustedTime()
140    {
141        String   d = this.getTime();
142
143        if (d.charAt(0) < '5')
144        {
145            return "20" + d;
146        }
147        else
148        {
149            return "19" + d;
150        }
151    }
152
153    private byte[] getOctets()
154    {
155        char[]  cs = time.toCharArray();
156        byte[]  bs = new byte[cs.length];
157
158        for (int i = 0; i != cs.length; i++)
159        {
160            bs[i] = (byte)cs[i];
161        }
162
163        return bs;
164    }
165
166    void encode(
167        DEROutputStream  out)
168        throws IOException
169    {
170        out.writeEncoded(UTC_TIME, this.getOctets());
171    }
172
173    public boolean equals(
174        Object  o)
175    {
176        if ((o == null) || !(o instanceof DERUTCTime))
177        {
178            return false;
179        }
180
181        return time.equals(((DERUTCTime)o).time);
182    }
183
184    public int hashCode()
185    {
186        return time.hashCode();
187    }
188
189    public String toString()
190    {
191      return time;
192    }
193}
194