1/*
2* Conditions Of Use
3*
4* This software was developed by employees of the National Institute of
5* Standards and Technology (NIST), an agency of the Federal Government.
6* Pursuant to title 15 Untied States Code Section 105, works of NIST
7* employees are not subject to copyright protection in the United States
8* and are considered to be in the public domain.  As a result, a formal
9* license is not needed to use the software.
10*
11* This software is provided by NIST as a service and is expressly
12* provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15* AND DATA ACCURACY.  NIST does not warrant or make any representations
16* regarding the use of the software or the results thereof, including but
17* not limited to the correctness, accuracy, reliability or usefulness of
18* the software.
19*
20* Permission to use this software is contingent upon your acceptance
21* of the terms of this agreement
22*
23* .
24*
25*/
26/*******************************************************************************
27* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *
28*******************************************************************************/
29package gov.nist.javax.sip.header;
30import gov.nist.core.*;
31import java.util.Calendar;
32import java.util.TimeZone;
33import java.util.Locale;
34import java.util.GregorianCalendar;
35import java.io.Serializable;
36import java.lang.IllegalArgumentException;
37
38/**
39* Implements a parser class for tracking expiration time
40* when specified as a Date value.
41*<pre>
42* From the HTTP 1.1 spec
43*14.18 Date
44*
45*   The Date general-header field represents the date and time at which
46*   the message was originated, having the same semantics as orig-date in
47*   RFC 822. The field value is an HTTP-date, as described in section
48*   3.3.1; it MUST be sent in RFC 1123 [8]-date format.
49
50*       Date  = "Date" ":" HTTP-date
51*
52*   An example is
53*
54*       Date: Tue, 15 Nov 1994 08:12:31 GMT
55*</pre>
56*
57*@version 1.2 $Revision: 1.9 $ $Date: 2009/10/18 13:46:33 $
58*
59*@author M. Ranganathan   <br/>
60*
61*
62*
63*
64*/
65
66public class SIPDate implements Cloneable,Serializable {
67    /**
68     * Comment for <code>serialVersionUID</code>
69     */
70    private static final long serialVersionUID = 8544101899928346909L;
71    public static final String GMT = "GMT";
72    public static final String MON = "Mon";
73    public static final String TUE = "Tue";
74    public static final String WED = "Wed";
75    public static final String THU = "Thu";
76    public static final String FRI = "Fri";
77    public static final String SAT = "Sat";
78    public static final String SUN = "Sun";
79    public static final String JAN = "Jan";
80    public static final String FEB = "Feb";
81    public static final String MAR = "Mar";
82    public static final String APR = "Apr";
83    public static final String MAY = "May";
84    public static final String JUN = "Jun";
85    public static final String JUL = "Jul";
86    public static final String AUG = "Aug";
87    public static final String SEP = "Sep";
88    public static final String OCT = "Oct";
89    public static final String NOV = "Nov";
90    public static final String DEC = "Dec";
91
92    /** sipWkDay member
93     */
94    protected String sipWkDay;
95
96    /** sipMonth member
97    */
98    protected String sipMonth;
99
100    /** wkday member
101    */
102    protected int wkday;
103
104    /** day member
105    */
106    protected int day;
107
108    /** month member
109    */
110    protected int month;
111
112    /** year member
113    */
114    protected int year;
115
116    /** hour member
117    */
118    protected int hour;
119
120    /** minute member
121    */
122    protected int minute;
123
124    /** second member
125    */
126    protected int second;
127
128    /** javaCal member
129    */
130    private java.util.Calendar javaCal;
131
132    /** equality check.
133     *
134     *@return true if the two date fields are equals
135     */
136    public boolean equals(Object that){
137        if (that.getClass() != this.getClass())return false;
138        SIPDate other = (SIPDate)that;
139        return this.wkday == other.wkday &&
140        this.day == other.day &&
141        this.month == other.month &&
142        this.year == other.year &&
143        this.hour == other.hour &&
144        this.minute == other.minute &&
145        this.second == other.second;
146    }
147
148    /**
149     * Initializer, sets all the fields to invalid values.
150     */
151    public SIPDate() {
152        wkday = -1;
153        day = -1;
154        month = -1;
155        year = -1;
156        hour = -1;
157        minute = -1;
158        second = -1;
159        javaCal = null;
160    }
161
162    /**
163     * Construct a SIP date from the time offset given in miliseconds
164     * @param timeMillis long to set
165     */
166    public SIPDate(long timeMillis) {
167        javaCal =
168            new GregorianCalendar(
169                TimeZone.getTimeZone("GMT:0"),
170                Locale.getDefault());
171        java.util.Date date = new java.util.Date(timeMillis);
172        javaCal.setTime(date);
173        wkday = javaCal.get(Calendar.DAY_OF_WEEK);
174        switch (wkday) {
175            case Calendar.MONDAY :
176                sipWkDay = MON;
177                break;
178            case Calendar.TUESDAY :
179                sipWkDay = TUE;
180                break;
181            case Calendar.WEDNESDAY :
182                sipWkDay = WED;
183                break;
184            case Calendar.THURSDAY :
185                sipWkDay = THU;
186                break;
187            case Calendar.FRIDAY :
188                sipWkDay = FRI;
189                break;
190            case Calendar.SATURDAY :
191                sipWkDay = SAT;
192                break;
193            case Calendar.SUNDAY :
194                sipWkDay = SUN;
195                break;
196            default :
197                InternalErrorHandler.handleException(
198                    "No date map for wkday " + wkday);
199        }
200
201        day = javaCal.get(Calendar.DAY_OF_MONTH);
202        month = javaCal.get(Calendar.MONTH);
203        switch (month) {
204            case Calendar.JANUARY :
205                sipMonth = JAN;
206                break;
207            case Calendar.FEBRUARY :
208                sipMonth = FEB;
209                break;
210            case Calendar.MARCH :
211                sipMonth = MAR;
212                break;
213            case Calendar.APRIL :
214                sipMonth = APR;
215                break;
216            case Calendar.MAY :
217                sipMonth = MAY;
218                break;
219            case Calendar.JUNE :
220                sipMonth = JUN;
221                break;
222            case Calendar.JULY :
223                sipMonth = JUL;
224                break;
225            case Calendar.AUGUST :
226                sipMonth = AUG;
227                break;
228            case Calendar.SEPTEMBER :
229                sipMonth = SEP;
230                break;
231            case Calendar.OCTOBER :
232                sipMonth = OCT;
233                break;
234            case Calendar.NOVEMBER :
235                sipMonth = NOV;
236                break;
237            case Calendar.DECEMBER :
238                sipMonth = DEC;
239                break;
240            default :
241                InternalErrorHandler.handleException(
242                    "No date map for month " + month);
243        }
244        year = javaCal.get(Calendar.YEAR);
245        // Bug report by Bruno Konik
246        hour = javaCal.get(Calendar.HOUR_OF_DAY);
247        minute = javaCal.get(Calendar.MINUTE);
248        second = javaCal.get(Calendar.SECOND);
249    }
250
251    /**
252     * Get canonical string representation.
253     * @return String
254     */
255    public String encode() {
256
257        String dayString;
258        if (day < 10) {
259            dayString = "0" + day;
260        } else
261            dayString = "" + day;
262
263        String hourString;
264        if (hour < 10) {
265            hourString = "0" + hour;
266        } else
267            hourString = "" + hour;
268
269        String minuteString;
270        if (minute < 10) {
271            minuteString = "0" + minute;
272        } else
273            minuteString = "" + minute;
274
275        String secondString;
276        if (second < 10) {
277            secondString = "0" + second;
278        } else
279            secondString = "" + second;
280
281        String encoding = "";
282
283        if (sipWkDay != null)
284            encoding += sipWkDay + Separators.COMMA + Separators.SP;
285
286        encoding += dayString + Separators.SP;
287
288        if (sipMonth != null)
289            encoding += sipMonth + Separators.SP;
290
291        encoding += year
292            + Separators.SP
293            + hourString
294            + Separators.COLON
295            + minuteString
296            + Separators.COLON
297            + secondString
298            + Separators.SP
299            + GMT;
300
301        return encoding;
302    }
303
304    /**
305     * The only accessor we allow is to the java calendar record.
306     * All other fields are for this package only.
307     * @return Calendar
308     */
309    public java.util.Calendar getJavaCal() {
310        if (javaCal == null)
311            setJavaCal();
312        return javaCal;
313    }
314
315    /** get the WkDay field
316     * @return String
317     */
318    public String getWkday() {
319        return sipWkDay;
320    }
321
322    /** get the month
323     * @return String
324     */
325    public String getMonth() {
326        return sipMonth;
327    }
328
329    /** get the hour
330     * @return int
331     */
332    public int getHour() {
333        return hour;
334    }
335
336    /** get the minute
337     * @return int
338     */
339    public int getMinute() {
340        return minute;
341    }
342
343    /** get the second
344     *  @return int
345     */
346    public int getSecond() {
347        return second;
348    }
349
350    /**
351     * convert the SIP Date of this structure to a Java Date.
352     * SIP Dates are forced to be GMT. Stores the converted time
353     * as a java Calendar class.
354     */
355    private void setJavaCal() {
356        javaCal =
357            new GregorianCalendar(
358                TimeZone.getTimeZone("GMT:0"),
359                Locale.getDefault());
360        if (year != -1)
361            javaCal.set(Calendar.YEAR, year);
362        if (day != -1)
363            javaCal.set(Calendar.DAY_OF_MONTH, day);
364        if (month != -1)
365            javaCal.set(Calendar.MONTH, month);
366        if (wkday != -1)
367            javaCal.set(Calendar.DAY_OF_WEEK, wkday);
368        if (hour != -1)
369            javaCal.set(Calendar.HOUR, hour);
370        if (minute != -1)
371            javaCal.set(Calendar.MINUTE, minute);
372        if (second != -1)
373            javaCal.set(Calendar.SECOND, second);
374    }
375
376    /**
377     * Set the wkday member
378     * @param w String to set
379     * @throws IllegalArgumentException if w is not a valid day.
380     */
381    public void setWkday(String w) throws IllegalArgumentException {
382        sipWkDay = w;
383        if (sipWkDay.compareToIgnoreCase(MON) == 0) {
384            wkday = Calendar.MONDAY;
385        } else if (sipWkDay.compareToIgnoreCase(TUE) == 0) {
386            wkday = Calendar.TUESDAY;
387        } else if (sipWkDay.compareToIgnoreCase(WED) == 0) {
388            wkday = Calendar.WEDNESDAY;
389        } else if (sipWkDay.compareToIgnoreCase(THU) == 0) {
390            wkday = Calendar.THURSDAY;
391        } else if (sipWkDay.compareToIgnoreCase(FRI) == 0) {
392            wkday = Calendar.FRIDAY;
393        } else if (sipWkDay.compareToIgnoreCase(SAT) == 0) {
394            wkday = Calendar.SATURDAY;
395        } else if (sipWkDay.compareToIgnoreCase(SUN) == 0) {
396            wkday = Calendar.SUNDAY;
397        } else {
398            throw new IllegalArgumentException("Illegal Week day :" + w);
399        }
400    }
401
402    /**
403     * Set the day member
404     * @param d int to set
405     * @throws IllegalArgumentException if d is not a valid day
406     */
407    public void setDay(int d) throws IllegalArgumentException {
408        if (d < 1 || d > 31)
409            throw new IllegalArgumentException(
410                "Illegal Day of the month " + Integer.toString(d));
411        day = d;
412    }
413
414    /**
415     * Set the month member
416     * @param m String to set.
417     * @throws IllegalArgumentException if m is not a valid month
418     */
419    public void setMonth(String m) throws IllegalArgumentException {
420        sipMonth = m;
421        if (sipMonth.compareToIgnoreCase(JAN) == 0) {
422            month = Calendar.JANUARY;
423        } else if (sipMonth.compareToIgnoreCase(FEB) == 0) {
424            month = Calendar.FEBRUARY;
425        } else if (sipMonth.compareToIgnoreCase(MAR) == 0) {
426            month = Calendar.MARCH;
427        } else if (sipMonth.compareToIgnoreCase(APR) == 0) {
428            month = Calendar.APRIL;
429        } else if (sipMonth.compareToIgnoreCase(MAY) == 0) {
430            month = Calendar.MAY;
431        } else if (sipMonth.compareToIgnoreCase(JUN) == 0) {
432            month = Calendar.JUNE;
433        } else if (sipMonth.compareToIgnoreCase(JUL) == 0) {
434            month = Calendar.JULY;
435        } else if (sipMonth.compareToIgnoreCase(AUG) == 0) {
436            month = Calendar.AUGUST;
437        } else if (sipMonth.compareToIgnoreCase(SEP) == 0) {
438            month = Calendar.SEPTEMBER;
439        } else if (sipMonth.compareToIgnoreCase(OCT) == 0) {
440            month = Calendar.OCTOBER;
441        } else if (sipMonth.compareToIgnoreCase(NOV) == 0) {
442            month = Calendar.NOVEMBER;
443        } else if (sipMonth.compareToIgnoreCase(DEC) == 0) {
444            month = Calendar.DECEMBER;
445        } else {
446            throw new IllegalArgumentException("Illegal Month :" + m);
447        }
448    }
449
450    /**
451     * Set the year member
452     * @param y int to set
453     * @throws IllegalArgumentException if y is not a valid year.
454     */
455    public void setYear(int y) throws IllegalArgumentException {
456        if (y < 0)
457            throw new IllegalArgumentException("Illegal year : " + y);
458        javaCal = null;
459        year = y;
460    }
461
462    /**
463    * Get the year member.
464    */
465    public int getYear() {
466        return year;
467    }
468
469    /**
470     * Set the hour member
471     * @param h int to set
472     * @throws IllegalArgumentException if h is not a valid hour.
473     */
474    public void setHour(int h) throws IllegalArgumentException {
475        if (h < 0 || h > 24)
476            throw new IllegalArgumentException("Illegal hour : " + h);
477        javaCal = null;
478        hour = h;
479    }
480
481    /**
482     * Set the minute member
483     * @param m int to set
484     * @throws IllegalArgumentException if m is not a valid minute
485     */
486    public void setMinute(int m) throws IllegalArgumentException {
487        if (m < 0 || m >= 60)
488            throw new IllegalArgumentException(
489                "Illegal minute : " + (Integer.toString(m)));
490        javaCal = null;
491        minute = m;
492    }
493
494    /**
495     * Set the second member
496     * @param s int to set
497     * @throws IllegalArgumentException if s is not a valid second
498     */
499    public void setSecond(int s) throws IllegalArgumentException {
500        if (s < 0 || s >= 60)
501            throw new IllegalArgumentException(
502                "Illegal second : " + Integer.toString(s));
503        javaCal = null;
504        second = s;
505    }
506
507    /** Get the time offset from the current time.
508     *
509     *@return offset from the current time.
510     */
511    public int getDeltaSeconds() {
512        // long ctime = this.getJavaCal().getTimeInMillis();
513        long ctime = this.getJavaCal().getTime().getTime();
514        return (int) (ctime - System.currentTimeMillis()) / 1000;
515    }
516
517    public Object clone() {
518        SIPDate retval;
519        try {
520            retval = (SIPDate) super.clone();
521        } catch (CloneNotSupportedException e) {
522            throw new RuntimeException("Internal error");
523        }
524        if (javaCal != null)
525            retval.javaCal = (java.util.Calendar) javaCal.clone();
526        return retval;
527    }
528}
529/*
530 * $Log: SIPDate.java,v $
531 * Revision 1.9  2009/10/18 13:46:33  deruelle_jean
532 * FindBugs Fixes (Category Performance Warnings)
533 *
534 * Issue number:
535 * Obtained from:
536 * Submitted by: Jean Deruelle
537 * Reviewed by:
538 *
539 * Revision 1.8  2009/07/17 18:57:37  emcho
540 * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.
541 *
542 * Revision 1.7  2006/07/13 09:01:16  mranga
543 * Issue number:
544 * Obtained from:
545 * Submitted by:  jeroen van bemmel
546 * Reviewed by:   mranga
547 * Moved some changes from jain-sip-1.2 to java.net
548 *
549 * CVS: ----------------------------------------------------------------------
550 * CVS: Issue number:
551 * CVS:   If this change addresses one or more issues,
552 * CVS:   then enter the issue number(s) here.
553 * CVS: Obtained from:
554 * CVS:   If this change has been taken from another system,
555 * CVS:   then name the system in this line, otherwise delete it.
556 * CVS: Submitted by:
557 * CVS:   If this code has been contributed to the project by someone else; i.e.,
558 * CVS:   they sent us a patch or a set of diffs, then include their name/email
559 * CVS:   address here. If this is your work then delete this line.
560 * CVS: Reviewed by:
561 * CVS:   If we are doing pre-commit code reviews and someone else has
562 * CVS:   reviewed your changes, include their name(s) here.
563 * CVS:   If you have not had it reviewed then delete this line.
564 *
565 * Revision 1.3  2006/06/19 06:47:26  mranga
566 * javadoc fixups
567 *
568 * Revision 1.2  2006/06/16 15:26:28  mranga
569 * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak
570 *
571 * Revision 1.1.1.1  2005/10/04 17:12:35  mranga
572 *
573 * Import
574 *
575 *
576 * Revision 1.5  2005/04/16 20:35:10  dmuresan
577 * SIPDate made cloneable.
578 *
579 * Revision 1.4  2004/07/28 14:41:53  mranga
580 * Submitted by:  mranga
581 *
582 * fixed equality check for SIPDate.
583 *
584 * Revision 1.3  2004/04/05 21:46:08  mranga
585 * Submitted by:  Bruno Konik
586 * Reviewed by:   mranga
587 *
588 * Revision 1.2  2004/01/22 13:26:29  sverker
589 * Issue number:
590 * Obtained from:
591 * Submitted by:  sverker
592 * Reviewed by:   mranga
593 *
594 * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.
595 *
596 * CVS: ----------------------------------------------------------------------
597 * CVS: Issue number:
598 * CVS:   If this change addresses one or more issues,
599 * CVS:   then enter the issue number(s) here.
600 * CVS: Obtained from:
601 * CVS:   If this change has been taken from another system,
602 * CVS:   then name the system in this line, otherwise delete it.
603 * CVS: Submitted by:
604 * CVS:   If this code has been contributed to the project by someone else; i.e.,
605 * CVS:   they sent us a patch or a set of diffs, then include their name/email
606 * CVS:   address here. If this is your work then delete this line.
607 * CVS: Reviewed by:
608 * CVS:   If we are doing pre-commit code reviews and someone else has
609 * CVS:   reviewed your changes, include their name(s) here.
610 * CVS:   If you have not had it reviewed then delete this line.
611 *
612 */
613