Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/derby/iapi/types/SQLDate.java


1   /*
2   
3      Derby - Class org.apache.derby.iapi.types.SQLDate
4   
5      Copyright 2001, 2004 The Apache Software Foundation or its licensors, as applicable.
6   
7      Licensed under the Apache License, Version 2.0 (the "License");
8      you may not use this file except in compliance with the License.
9      You may obtain a copy of the License at
10  
11        http://www.apache.org/licenses/LICENSE-2.0
12  
13     Unless required by applicable law or agreed to in writing, software
14     distributed under the License is distributed on an "AS IS" BASIS,
15     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16     See the License for the specific language governing permissions and
17     limitations under the License.
18  
19   */
20  
21  package org.apache.derby.iapi.types;
22  
23  import org.apache.derby.iapi.types.SQLInteger;
24  
25  import org.apache.derby.iapi.reference.SQLState;
26  
27  import org.apache.derby.iapi.services.io.ArrayInputStream;
28  
29  import org.apache.derby.iapi.error.StandardException;
30  
31  import org.apache.derby.iapi.db.DatabaseContext;
32  import org.apache.derby.iapi.types.DataValueDescriptor;
33  import org.apache.derby.iapi.types.TypeId;
34  
35  import org.apache.derby.iapi.types.NumberDataValue;
36  import org.apache.derby.iapi.types.DateTimeDataValue;
37  
38  import org.apache.derby.iapi.services.context.ContextService;
39  
40  import org.apache.derby.iapi.services.io.StoredFormatIds;
41   
42  import org.apache.derby.iapi.services.sanity.SanityManager;
43  
44  import org.apache.derby.iapi.types.DataType;
45  
46  import org.apache.derby.iapi.services.cache.ClassSize;
47  import org.apache.derby.iapi.services.i18n.LocaleFinder;
48  import org.apache.derby.iapi.util.StringUtil;
49  
50  import java.sql.Date;
51  import java.sql.Time;
52  import java.sql.Timestamp;
53  import java.sql.Types;
54  import java.sql.PreparedStatement;
55  
56  import java.util.Calendar;
57  import java.util.GregorianCalendar;
58  
59  import java.io.ObjectOutput;
60  import java.io.ObjectInput;
61  import java.io.IOException;
62  
63  import java.sql.ResultSet;
64  import java.sql.SQLException;
65  
66  import java.text.DateFormat;
67  import java.text.ParseException;
68  
69  /**
70   * This contains an instance of a SQL Date.
71   * <p>
72   * The date is stored as int (year << 16 + month << 8 + day)
73   * Null is represented by an encodedDate value of 0.
74   * Some of the static methods in this class are also used by SQLTime and SQLTimestamp
75   * so check those classes if you change the date encoding
76   *
77   * PERFORMANCE OPTIMIZATION:
78   * The java.sql.Date object is only instantiated when needed
79   * do to the overhead of Date.valueOf(), etc. methods.
80   */
81  
82  public final class SQLDate extends DataType
83              implements DateTimeDataValue
84  {
85  
86    private int  encodedDate;  //year << 16 + month << 8 + day
87  
88    // The cached value.toString()
89    private String  valueString;
90  
91      private static final int BASE_MEMORY_USAGE = ClassSize.estimateBaseFromCatalog( SQLDate.class);
92  
93      public int estimateMemoryUsage()
94      {
95          return BASE_MEMORY_USAGE + ClassSize.estimateMemoryUsage( valueString);
96      } // end of estimateMemoryUsage
97  
98      int getEncodedDate()
99      {
100         return encodedDate;
101     }
102     
103   /*
104   ** DataValueDescriptor interface
105   ** (mostly implemented in DataType)
106   */
107 
108   public String getString()
109   {
110     //format is [yyy]y-mm-dd e.g. 1-01-01, 9999-99-99
111     if (!isNull())
112     {
113       if (valueString == null)
114       {
115         valueString = encodedDateToString(encodedDate);
116       }
117       return valueString;
118     }
119     else
120     {
121       if (SanityManager.DEBUG)
122       {
123         if (valueString != null)
124         {
125           SanityManager.THROWASSERT(
126             "valueString expected to be null, not " +
127             valueString);
128         }
129       }
130       return null;
131     }
132   }
133 
134   /**
135     getTimestamp returns a timestamp with the date value 
136     time is set to 00:00:00.0
137   */
138   public Timestamp getTimestamp( Calendar cal) 
139   {
140     if (isNull())
141     {
142       return null;
143     }
144     else 
145       // date is converted to a timestamp filling the time in with 00:00:00
146             return newTimestamp(cal);
147     }
148 
149     private long getTimeInMillis( Calendar cal)
150     {
151         if( cal == null)
152             cal = new GregorianCalendar();
153         cal.clear();
154         cal.set( getYear( encodedDate), getMonth( encodedDate)-1, getDay( encodedDate));
155         return cal.getTime().getTime();
156     }
157     
158     private Timestamp newTimestamp(java.util.Calendar cal)
159     {
160         return new Timestamp(getTimeInMillis( cal));
161   }
162 
163   /**
164     getObject returns the date value
165 
166    */
167   public Object getObject()
168   {
169     return getDate( (Calendar) null);
170   }
171     
172   public int getLength()
173   {
174     return 4;
175   }
176 
177   /* this is for DataType's error generator */
178   public String getTypeName()
179   {
180     return "DATE";
181   }
182 
183   /*
184    * Storable interface, implies Externalizable, TypedFormat
185    */
186 
187   /**
188     Return my format identifier.
189 
190     @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId
191   */
192   public int getTypeFormatId() {
193     return StoredFormatIds.SQL_DATE_ID;
194   }
195 
196   /** 
197     @exception IOException error writing data
198 
199   */
200   public void writeExternal(ObjectOutput out) throws IOException {
201 
202     if (SanityManager.DEBUG)
203       SanityManager.ASSERT(!isNull(), "writeExternal() is not supposed to be called for null values.");
204 
205     out.writeInt(encodedDate);
206   }
207 
208   /**
209    * @see java.io.Externalizable#readExternal
210    *
211    * @exception IOException  Thrown on error reading the object
212    */
213   public void readExternal(ObjectInput in) throws IOException
214   {
215     encodedDate = in.readInt();
216 
217     // reset cached string values
218     valueString = null;
219   }
220   public void readExternalFromArray(ArrayInputStream in) throws IOException
221   {
222     encodedDate = in.readInt();
223 
224     // reset cached string values
225     valueString = null;
226   }
227 
228   /*
229    * DataValueDescriptor interface
230    */
231 
232   /** @see DataValueDescriptor#getClone */
233   public DataValueDescriptor getClone()
234   {
235     // Call constructor with all of our info
236     return new SQLDate(encodedDate);
237   }
238 
239   /**
240    * @see DataValueDescriptor#getNewNull
241    */
242   public DataValueDescriptor getNewNull()
243   {
244     return new SQLDate();
245   }
246   /**
247    * @see org.apache.derby.iapi.services.io.Storable#restoreToNull
248    *
249    */
250 
251   public void restoreToNull()
252   {
253     // clear encodedDate
254     encodedDate = 0;
255 
256     // clear cached valueString
257     valueString = null;
258   }
259 
260   /*
261    * DataValueDescriptor interface
262    */
263 
264   /** 
265    * @see DataValueDescriptor#setValueFromResultSet 
266    *
267    * @exception SQLException    Thrown on error
268    */
269   public void setValueFromResultSet(ResultSet resultSet, int colNumber,
270                     boolean isNullable)
271     throws SQLException, StandardException
272   {
273         setValue(resultSet.getDate(colNumber), (Calendar) null);
274   }
275 
276   /**
277    * Orderable interface
278    *
279    *
280    * @see org.apache.derby.iapi.types.Orderable
281    *
282    * @exception StandardException thrown on failure
283    */
284   public int compare(DataValueDescriptor other)
285     throws StandardException
286   {
287     /* Use compare method from dominant type, negating result
288      * to reflect flipping of sides.
289      */
290     if (typePrecedence() < other.typePrecedence())
291     {
292       return - (other.compare(this));
293     }
294 
295 
296     boolean thisNull, otherNull;
297 
298     thisNull = this.isNull();
299     otherNull = other.isNull();
300 
301     /*
302      * thisNull otherNull  return
303      *  T    T       0  (this == other)
304      *  F    T       -1   (this < other)
305      *  T    F       1  (this > other)
306      */
307     if (thisNull || otherNull)
308     {
309       if (!thisNull)    // otherNull must be true
310         return -1;
311       if (!otherNull)    // thisNull must be true
312         return 1;
313       return 0;
314     }
315 
316     /*
317       Neither are null compare them 
318      */
319 
320     int comparison;
321     /* get the comparison date values */
322     int otherVal = 0;
323 
324     /* if the argument is another SQLDate
325      * get the encodedDate
326      */
327     if (other instanceof SQLDate)
328     {
329       otherVal = ((SQLDate)other).encodedDate; 
330     }
331     else 
332     {
333       /* O.K. have to do it the hard way and calculate the numeric value
334        * from the value
335        */
336       otherVal = SQLDate.computeEncodedDate(other.getDate(new GregorianCalendar()));
337     }
338     if (encodedDate > otherVal)
339       comparison = 1;
340     else if (encodedDate < otherVal)
341       comparison = -1;
342     else 
343       comparison = 0;
344 
345     return comparison;
346   }
347 
348   /**
349     @exception StandardException thrown on error
350    */
351   public boolean compare(int op,
352                DataValueDescriptor other,
353                boolean orderedNulls,
354                boolean unknownRV)
355     throws StandardException
356   {
357     if (!orderedNulls)    // nulls are unordered
358     {
359       if (this.isNull() || other.isNull())
360         return unknownRV;
361     }
362 
363     /* Do the comparison */
364     return super.compare(op, other, orderedNulls, unknownRV);
365   }
366 
367   /*
368   ** Class interface
369   */
370 
371   /*
372   ** Constructors
373   */
374 
375   /** no-arg constructor required by Formattable */
376   public SQLDate() {
377   }
378 
379   public SQLDate(Date value) throws StandardException
380   {
381     parseDate(value);
382   }
383     
384     private void parseDate( java.util.Date value) throws StandardException
385   {
386     encodedDate = computeEncodedDate(value);
387   }
388 
389   private SQLDate(int encodedDate) {
390     this.encodedDate = encodedDate;
391   }
392 
393     /**
394      * Construct a date from a string. The allowed date formats are:
395      *<ol>
396      *<li>ISO: yyyy-mm-dd
397      *<li>IBM USA standard: mm/dd/yyyy
398      *<li>IBM European standard: dd.mm.yyyy
399      *</ol>
400      * Trailing blanks may be included; leading zeros may be omitted from the month and day portions.
401      *
402      * @param dateStr
403      * @param isJdbcEscape if true then only the JDBC date escape syntax is allowed
404      * @param localeFinder
405      *
406      * @return the internal DataValueDescriptor for the value
407      *
408      * @exception Standard exception if the syntax is invalid or the value is out of range.
409      */
410     public SQLDate( String dateStr, boolean isJdbcEscape, LocaleFinder localeFinder)
411         throws StandardException
412     {
413         parseDate( dateStr, isJdbcEscape, localeFinder, (Calendar) null);
414     }
415 
416     /**
417      * Construct a date from a string. The allowed date formats are:
418      *<ol>
419      *<li>ISO: yyyy-mm-dd
420      *<li>IBM USA standard: mm/dd/yyyy
421      *<li>IBM European standard: dd.mm.yyyy
422      *</ol>
423      * Trailing blanks may be included; leading zeros may be omitted from the month and day portions.
424      *
425      * @param dateStr
426      * @param isJdbcEscape if true then only the JDBC date escape syntax is allowed
427      * @param localeFinder
428      *
429      * @return the internal DataValueDescriptor for the value
430      *
431      * @exception Standard exception if the syntax is invalid or the value is out of range.
432      */
433     public SQLDate( String dateStr, boolean isJdbcEscape, LocaleFinder localeFinder, Calendar cal)
434         throws StandardException
435     {
436         parseDate( dateStr, isJdbcEscape, localeFinder, cal);
437     }
438 
439     static final char ISO_SEPARATOR = '-';
440     private static final char[] ISO_SEPARATOR_ONLY = {ISO_SEPARATOR};
441     private static final char IBM_USA_SEPARATOR = '/';
442     private static final char[] IBM_USA_SEPARATOR_ONLY = {IBM_USA_SEPARATOR};
443     private static final char IBM_EUR_SEPARATOR = '.';
444     private static final char[] IBM_EUR_SEPARATOR_ONLY = {IBM_EUR_SEPARATOR};
445     private static final char[] END_OF_STRING = {(char) 0};
446     
447     private void parseDate( String dateStr, boolean isJdbcEscape, LocaleFinder localeFinder, Calendar cal)
448         throws StandardException
449     {
450         boolean validSyntax = true;
451         DateTimeParser parser = new DateTimeParser( dateStr);
452         int year = 0;
453         int month = 0;
454         int day = 0;
455         StandardException thrownSE = null;
456 
457         try
458         {
459             switch( parser.nextSeparator())
460             {
461             case ISO_SEPARATOR:
462                 encodedDate = SQLTimestamp.parseDateOrTimestamp( parser, false)[0];
463                 valueString = parser.getTrimmedString();
464                 return;
465 
466             case IBM_USA_SEPARATOR:
467                 if( isJdbcEscape)
468                 {
469                     validSyntax = false;
470                     break;
471                 }
472                 month = parser.parseInt( 2, true, IBM_USA_SEPARATOR_ONLY, false);
473                 day = parser.parseInt( 2, true, IBM_USA_SEPARATOR_ONLY, false);
474                 year = parser.parseInt( 4, false, END_OF_STRING, false);
475                 break;
476 
477             case IBM_EUR_SEPARATOR:
478                 if( isJdbcEscape)
479                 {
480                     validSyntax = false;
481                     break;
482                 }
483                 day = parser.parseInt( 2, true, IBM_EUR_SEPARATOR_ONLY, false);
484                 month = parser.parseInt( 2, true, IBM_EUR_SEPARATOR_ONLY, false);
485                 year = parser.parseInt( 4, false, END_OF_STRING, false);
486                 break;
487 
488             default:
489                 validSyntax = false;
490             }
491         }
492         catch( StandardException se)
493         {
494             validSyntax = false;
495             thrownSE = se;
496         }
497         if( validSyntax)
498         {
499             valueString = parser.checkEnd();
500             encodedDate = computeEncodedDate( year, month, day);
501         }
502         else
503         {
504             // See if it is a localized date or timestamp.
505             dateStr = StringUtil.trimTrailing( dateStr);
506             DateFormat dateFormat = null;
507             if( localeFinder == null)
508                 dateFormat = DateFormat.getDateInstance();
509             else if( cal == null)
510                 dateFormat = localeFinder.getDateFormat();
511             else
512                 dateFormat = (DateFormat) localeFinder.getDateFormat().clone();
513             if( cal != null)
514                 dateFormat.setCalendar( cal);
515             try
516             {
517                 encodedDate = computeEncodedDate( dateFormat.parse( dateStr), cal);
518             }
519             catch( ParseException pe)
520             {
521                 // Maybe it is a localized timestamp
522                 try
523                 {
524                     encodedDate = SQLTimestamp.parseLocalTimestamp( dateStr, localeFinder, cal)[0];
525                 }
526                 catch( ParseException pe2)
527                 {
528                     if( thrownSE != null)
529                         throw thrownSE;
530                     throw StandardException.newException( SQLState.LANG_DATE_SYNTAX_EXCEPTION);
531                 }
532             }
533             valueString = dateStr;
534         }
535     } // end of parseDate
536 
537   public void setValue(Object theValue) throws StandardException
538   {
539     if (theValue == null)
540     {
541       setToNull();
542     }
543     else if (theValue instanceof Date)
544     {
545       setValue((Date)theValue, (Calendar) null);
546     }
547     else if (theValue instanceof Timestamp)
548     {
549       setValue((Timestamp)theValue, (Calendar) null);
550     }
551     else
552     {
553       genericSetObject(theValue);
554     }
555 
556   }
557 
558   protected void setFrom(DataValueDescriptor theValue) throws StandardException {
559 
560     // Same format means same type SQLDate
561     if (theValue instanceof SQLDate) {
562       restoreToNull();
563       encodedDate = ((SQLDate) theValue).encodedDate;
564     }
565         else
566         {
567             Calendar cal = new GregorianCalendar();
568       setValue(theValue.getDate( cal), cal);
569         }
570   }
571 
572   /**
573     @see DateTimeDataValue#setValue
574 
575    */
576   public void setValue(Date value, Calendar cal) throws StandardException
577   {
578     restoreToNull();
579     encodedDate = computeEncodedDate((java.util.Date) value, cal);
580   }
581 
582   /**
583     @see DateTimeDataValue#setValue
584 
585    */
586   public void setValue(Timestamp value, Calendar cal) throws StandardException
587   {
588     restoreToNull();
589     encodedDate = computeEncodedDate((java.util.Date) value, cal);
590   }
591 
592 
593   public void setValue(String theValue)
594       throws StandardException
595   {
596     restoreToNull();
597 
598     if (theValue != null)
599     {
600             DatabaseContext databaseContext = (DatabaseContext) ContextService.getContext(DatabaseContext.CONTEXT_ID);
601             parseDate( theValue,
602                        false,
603                        (databaseContext == null) ? null : databaseContext.getDatabase(),
604                        (Calendar) null);
605         }
606   }
607 
608   /*
609   ** SQL Operators
610   */
611 
612   /**
613    * @see DateTimeDataValue#getYear
614    * 
615    * @exception StandardException    Thrown on error
616    */
617   public NumberDataValue getYear(NumberDataValue result)
618               throws StandardException
619   {
620     if (SanityManager.DEBUG)
621     {
622       SanityManager.ASSERT(!isNull(), "getYear called on a null");
623     }
624     return SQLDate.setSource(getYear(encodedDate), result);
625   }
626 
627   /**
628    * @see DateTimeDataValue#getMonth
629    * 
630    * @exception StandardException    Thrown on error
631    */
632   public NumberDataValue getMonth(NumberDataValue result)
633               throws StandardException
634   {
635     if (SanityManager.DEBUG)
636     {
637       SanityManager.ASSERT(!isNull(), "getMonth called on a null");
638     }
639     return SQLDate.setSource(getMonth(encodedDate), result);
640   }
641 
642   /**
643    * @see DateTimeDataValue#getDate
644    * 
645    * @exception StandardException    Thrown on error
646    */
647   public NumberDataValue getDate(NumberDataValue result)
648               throws StandardException
649   {
650     if (SanityManager.DEBUG)
651     {
652       SanityManager.ASSERT(!isNull(), "getDate called on a null");
653     }
654     return SQLDate.setSource(getDay(encodedDate), result);
655   }
656 
657   /**
658    * @see DateTimeDataValue#getHours
659    * 
660    * @exception StandardException    Thrown on error
661    */
662   public NumberDataValue getHours(NumberDataValue result)
663               throws StandardException
664   {
665     if (SanityManager.DEBUG)
666     {
667       SanityManager.ASSERT(!isNull(), "getHours called on null.");
668     }
669     throw StandardException.newException(SQLState.LANG_UNARY_FUNCTION_BAD_TYPE, 
670             "getHours", "Date");
671   }
672 
673   /**
674    * @see DateTimeDataValue#getMinutes
675    * 
676    * @exception StandardException    Thrown on error
677    */
678   public NumberDataValue getMinutes(NumberDataValue result)
679               throws StandardException
680   {
681     if (SanityManager.DEBUG)
682     {
683       SanityManager.ASSERT(!isNull(), "getMinutes called on null.");
684     }
685     throw StandardException.newException(SQLState.LANG_UNARY_FUNCTION_BAD_TYPE, 
686             "getMinutes", "Date");
687   }
688 
689   /**
690    * @see DateTimeDataValue#getSeconds
691    * 
692    * @exception StandardException    Thrown on error
693    */
694   public NumberDataValue getSeconds(NumberDataValue result)
695               throws StandardException
696   {
697     if (SanityManager.DEBUG)
698     {
699       SanityManager.ASSERT(!isNull(), "getSeconds called on null.");
700     }
701     throw StandardException.newException(SQLState.LANG_UNARY_FUNCTION_BAD_TYPE, 
702             "getSeconds", "Date");
703   }
704 
705   /*
706   ** String display of value
707   */
708 
709   public String toString()
710   {
711     if (isNull())
712     {
713       return "NULL";
714     }
715     else
716     {
717       return getDate( (Calendar) null).toString();
718     }
719   }
720 
721   /*
722    * Hash code
723    */
724   public int hashCode()
725   {
726     return encodedDate;
727   }
728 
729   /** @see DataValueDescriptor#typePrecedence */
730   public int  typePrecedence()
731   {
732     return TypeId.DATE_PRECEDENCE;
733   }
734 
735   /**
736    * Check if the value is null.  
737    * encodedDate is 0 if the value is null
738    *
739    * @return Whether or not value is logically null.
740    */
741   public final boolean isNull()
742   {
743     return (encodedDate == 0);
744   }
745 
746   /**
747    * Get the value field.  We instantiate the field
748    * on demand.
749    *
750    * @return  The value field.
751    */
752   public Date getDate( Calendar cal)
753   {
754     if (encodedDate != 0)
755             return new Date( getTimeInMillis( cal));
756 
757     return null;
758   }
759 
760   /**
761    * Get the year from the encodedDate.
762    *
763    * @param encodedDate  the encoded date
764    * @return         year value.
765    */
766   static int getYear(int encodedDate)
767   {
768     return (encodedDate >>> 16);
769   }
770 
771   /**
772    * Get the month from the encodedDate.
773    *
774    * @param encodedDate  the encoded date
775    * @return         month value.
776    */
777   static int getMonth(int encodedDate)
778   {
779     return ((encodedDate >>> 8) & 0x00ff);
780   }
781 
782   /**
783    * Get the day from the encodedDate.
784    *
785    * @param encodedDate  the encoded date
786    * @return         day value.
787    */
788   static int getDay(int encodedDate)
789   {
790     return (encodedDate & 0x00ff);
791   }
792   /**
793    *  computeEncodedDate extracts the year, month and date from
794    *  a Calendar value and encodes them as
795    *    year << 16 + month << 8 + date
796    *  Use this function will help to remember to add 1 to month
797    *  which is 0 based in the Calendar class
798    *  @param value  the Calendar 
799    *  @return     the encodedDate
800      *
801      *  @exception StandardException if the value is out of the DB2 date range
802    */
803   static int computeEncodedDate(Calendar cal) throws StandardException
804   {
805     return computeEncodedDate(cal.get(Calendar.YEAR),
806                                   cal.get(Calendar.MONTH) + 1,
807                                   cal.get(Calendar.DATE));
808   }
809 
810     static int computeEncodedDate( int y, int m, int d) throws StandardException
811     {
812         int maxDay = 31;
813         switch( m)
814         {
815         case 4:
816         case 6:
817         case 9:
818         case 11:
819             maxDay = 30;
820             break;
821                 
822         case 2:
823             // leap years are every 4 years except for century years not divisble by 400.
824             maxDay = ((y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0)) ? 29 : 28;
825             break;
826         }
827         if( y < 1 || y > 9999
828             || m < 1 || m > 12
829             || d < 1 || d > maxDay)
830             throw StandardException.newException( SQLState.LANG_DATE_RANGE_EXCEPTION);
831         return (y << 16) + (m << 8) + d;
832     }
833 
834     /**
835      * Convert a date to the JDBC representation and append it to a string buffer.
836      *
837      * @param year
838      * @param month 1 based (January == 1)
839      * @param day
840      * @param sb The string representation is appended to this StringBuffer
841      */
842     static void dateToString( int year, int month, int day, StringBuffer sb)
843     {
844         String yearStr = Integer.toString( year);
845         for( int i = yearStr.length(); i < 4; i++)
846             sb.append( '0');
847     sb.append(yearStr);
848     sb.append(ISO_SEPARATOR);
849 
850     String monthStr = Integer.toString( month);
851     String dayStr = Integer.toString( day);
852     if (monthStr.length() == 1)
853       sb.append('0');
854     sb.append(monthStr);
855     sb.append(ISO_SEPARATOR);
856     if (dayStr.length() == 1)
857       sb.append('0');
858     sb.append(dayStr);
859     } // end of dateToString
860     
861   /**
862    * Get the String version from the encodedDate.
863    *
864    * @return   string value.
865    */
866   static String encodedDateToString(int encodedDate)
867   {
868     StringBuffer vstr = new StringBuffer();
869         dateToString( getYear(encodedDate), getMonth(encodedDate), getDay(encodedDate), vstr);
870     return vstr.toString();
871   }
872 
873   // International Support
874 
875   /**
876    * International version of getString(). Overrides getNationalString
877    * in DataType for date, time, and timestamp.
878    *
879    * @exception StandardException    Thrown on error
880    */
881   protected String getNationalString(LocaleFinder localeFinder) throws StandardException
882   {
883     if (isNull())
884     {
885       return getString();
886     }
887 
888     return localeFinder.getDateFormat().format(getDate(new GregorianCalendar()));
889   }
890 
891   /**
892     This helper routine tests the nullability of various parameters
893     and sets up the result appropriately.
894 
895     If source is null, a new NumberDataValue is built. 
896 
897     @exception StandardException  Thrown on error
898    */
899   static NumberDataValue setSource(int value,
900                     NumberDataValue source)
901                   throws StandardException {
902     /*
903     ** NOTE: Most extract operations return int, so the generation of
904     ** a SQLInteger is here.  Those extract operations that return
905     ** something other than int must allocate the source NumberDataValue
906     ** themselves, so that we do not allocate a SQLInteger here.
907     */
908     if (source == null)
909       source = new SQLInteger();
910 
911     source.setValue(value);
912 
913     return source;
914   }
915   /**
916      * Compute the encoded date given a date
917    *
918    */
919   private static int computeEncodedDate(java.util.Date value) throws StandardException
920   {
921         return computeEncodedDate( value, null);
922     }
923 
924     static int computeEncodedDate(java.util.Date value, Calendar currentCal) throws StandardException
925     {
926     if (value == null)
927       return 0;      //encoded dates have a 0 value for null
928         if( currentCal == null)
929             currentCal = new GregorianCalendar();
930     currentCal.setTime(value);
931     return SQLDate.computeEncodedDate(currentCal);
932   }
933 
934 
935         /**
936          * Implement the date SQL function: construct a SQL date from a string, number, or timestamp.
937          *
938          * @param operand Must be a date or a string convertible to a date.
939          * @param dvf the DataValueFactory
940          *
941          * @exception StandardException standard error policy
942          */
943     public static DateTimeDataValue computeDateFunction( DataValueDescriptor operand,
944                                                          DataValueFactory dvf) throws StandardException
945     {
946         try
947         {
948             if( operand.isNull())
949                 return new SQLDate();
950             if( operand instanceof SQLDate)
951                 return (SQLDate) operand.getClone();
952 
953             if( operand instanceof SQLTimestamp)
954             {
955                 DateTimeDataValue retVal = new SQLDate();
956                 retVal.setValue( operand);
957                 return retVal;
958             }
959             if( operand instanceof NumberDataValue)
960             {
961                 int daysSinceEpoch = operand.getInt();
962                 if( daysSinceEpoch <= 0 || daysSinceEpoch > 3652059)
963                     throw StandardException.newException( SQLState.LANG_INVALID_FUNCTION_ARGUMENT,
964                                                           operand.getString(), "date");
965                 Calendar cal = new GregorianCalendar( 1970, 0, 1, 12, 0, 0);
966                 cal.add( Calendar.DATE, daysSinceEpoch - 1);
967                 return new SQLDate( computeEncodedDate( cal.get( Calendar.YEAR),
968                                                         cal.get( Calendar.MONTH) + 1,
969                                                         cal.get( Calendar.DATE)));
970             }
971             String str = operand.getString();
972             if( str.length() == 7)
973             {
974                 // yyyyddd where ddd is the day of the year
975                 int year = SQLTimestamp.parseDateTimeInteger( str, 0, 4);
976                 int dayOfYear = SQLTimestamp.parseDateTimeInteger( str, 4, 3);
977                 if( dayOfYear < 1 || dayOfYear > 366)
978                     throw StandardException.newException( SQLState.LANG_INVALID_FUNCTION_ARGUMENT,
979                                                           operand.getString(), "date");
980                 Calendar cal = new GregorianCalendar( year, 0, 1, 2, 0, 0);
981                 cal.add( Calendar.DAY_OF_YEAR, dayOfYear - 1);
982                 int y = cal.get( Calendar.YEAR);
983                 if( y != year)
984                     throw StandardException.newException( SQLState.LANG_INVALID_FUNCTION_ARGUMENT,
985                                                           operand.getString(), "date");
986                 return new SQLDate( computeEncodedDate( year,
987                                                         cal.get( Calendar.MONTH) + 1,
988                                                         cal.get( Calendar.DATE)));
989             }
990             // Else use the standard cast.
991             return dvf.getDateValue( str, false);
992         }
993         catch( StandardException se)
994         {
995             if( SQLState.LANG_DATE_SYNTAX_EXCEPTION.startsWith( se.getSQLState()))
996                 throw StandardException.newException( SQLState.LANG_INVALID_FUNCTION_ARGUMENT,
997                                                       operand.getString(), "date");
998             throw se;
999         }
1000    } // end of computeDateFunction
1001
1002    /** Adding this method to ensure that super class' setInto method doesn't get called
1003      * that leads to the violation of JDBC spec( untyped nulls ) when batching is turned on.
1004      */     
1005    public void setInto(PreparedStatement ps, int position) throws SQLException, StandardException {
1006
1007                  ps.setDate(position, getDate((Calendar) null));
1008     }
1009
1010
1011    /**
1012     * Add a number of intervals to a datetime value. Implements the JDBC escape TIMESTAMPADD function.
1013     *
1014     * @param intervalType One of FRAC_SECOND_INTERVAL, SECOND_INTERVAL, MINUTE_INTERVAL, HOUR_INTERVAL,
1015     *                     DAY_INTERVAL, WEEK_INTERVAL, MONTH_INTERVAL, QUARTER_INTERVAL, or YEAR_INTERVAL
1016     * @param intervalCount The number of intervals to add
1017     * @param currentDate Used to convert time to timestamp
1018     * @param resultHolder If non-null a DateTimeDataValue that can be used to hold the result. If null then
1019     *                     generate a new holder
1020     *
1021     * @return startTime + intervalCount intervals, as a timestamp
1022     *
1023     * @exception StandardException
1024     */
1025    public DateTimeDataValue timestampAdd( int intervalType,
1026                                           NumberDataValue intervalCount,
1027                                           java.sql.Date currentDate,
1028                                           DateTimeDataValue resultHolder)
1029        throws StandardException
1030    {
1031        return toTimestamp().timestampAdd( intervalType, intervalCount, currentDate, resultHolder);
1032    }
1033
1034    private SQLTimestamp toTimestamp() throws StandardException
1035    {
1036        return new SQLTimestamp( getEncodedDate(), 0, 0);
1037    }
1038    
1039    /**
1040     * Finds the difference between two datetime values as a number of intervals. Implements the JDBC
1041     * TIMESTAMPDIFF escape function.
1042     *
1043     * @param intervalType One of FRAC_SECOND_INTERVAL, SECOND_INTERVAL, MINUTE_INTERVAL, HOUR_INTERVAL,
1044     *                     DAY_INTERVAL, WEEK_INTERVAL, MONTH_INTERVAL, QUARTER_INTERVAL, or YEAR_INTERVAL
1045     * @param time1
1046     * @param currentDate Used to convert time to timestamp
1047     * @param resultHolder If non-null a NumberDataValue that can be used to hold the result. If null then
1048     *                     generate a new holder
1049     *
1050     * @return the number of intervals by which this datetime is greater than time1
1051     *
1052     * @exception StandardException
1053     */
1054    public NumberDataValue timestampDiff( int intervalType,
1055                                          DateTimeDataValue time1,
1056                                          java.sql.Date currentDate,
1057                                          NumberDataValue resultHolder)
1058        throws StandardException
1059    {
1060        return toTimestamp().timestampDiff( intervalType, time1, currentDate, resultHolder);
1061    }
1062}