All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.ibm.as400.access.AS400Timestamp Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename:  AS400Timestamp.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 2010-2010 International Business Machines Corporation and
// others.  All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////

package com.ibm.as400.access;

import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

/**
 Provides a converter between a {@link java.sql.Timestamp java.sql.Timestamp} object and 
 an IBM i timestamp value such as "1997-12-31-23.59.59.999999".
 In the IBM i programming reference, this type is referred to as the 
 "Timestamp Data Type", or DDS data type Z.
 

The minimum value for an IBM i timestamp is 0001-01-01-00.00.00.000000, and the maximum value is 9999-12-31-24.00.00.000000.

Note that java.sql.Timestamp values have nanoseconds precision, whereas IBM i timestamp values have only microseconds precision. When converting Timestamp values to IBM i timestamp values, fractional microseconds are rounded to the nearest microsecond.

An IBM i timestamp value simply indicates a year/month/day/hour/minute/second/microsecond, and does not indicate a contextual time zone. Internally, this class interprets all date- and time-related strings as relative to time zone of the AS400 system.

Suggestion: To avoid confusion and unexpected results when crossing time zones:
Whenever creating or interpreting instances of {@link java.sql.Date java.sql.Date}, {@link java.sql.Time java.sql.Time}, or {@link java.sql.Timestamp java.sql.Timestamp}, always assume that the reference time zone for the object is the server time zone, and avoid using any deprecated methods. If it is necessary to convert date/time values between the server time zone and other time zones, use methods of Calendar. Rather than using toString() to display the value of a date/time object, use DateFormat.format() after specifying a server time zone. For example: import java.text.SimpleDateFormat; java.sql.Timestamp timestamp1; // value to be generated by AS400Timestamp SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); // Set the formatter's time zone to the servers time zone formatter.setTimeZone(as400.getTimeZone()); ... System.out.println("Timestamp value: " + formatter.format(timestamp1)); @see AS400Date @see AS400Time **/ public class AS400Timestamp extends AS400AbstractTime { /** * */ private static final long serialVersionUID = 1L; // Constants used when processing *DTS timestamp values. private static final BigInteger ONE_THOUSAND = new BigInteger("1000"); private static final BigInteger ONE_MILLION = new BigInteger("1000000"); // Conversion factor: Microseconds elapsed from [1970-01-01 00:00:00] to [2000-01-01 00:00:00]. We've calculated this value previously. private static final BigInteger DTS_CONVERSION_FACTOR = new BigInteger("946684800000000"); private static final String PARSING_PATTERN = "yyyy-MM-dd-HH.mm.ss"; private java.sql.Timestamp defaultValue_; private transient SimpleDateFormat dateFormatterWithMillis_; /** The standard IBM i timestamp format.

  • Example: 1997-04-25-23.59.59.999999
  • Range of years: 0001-9999
  • Default separator: '-' and '.'
  • Length: 26 bytes
  • Note: The time zone context is not specified. The time zone for a timestamp field is typically assumed to match that of the IBM i system on which the field resides.
**/ public static final int FORMAT_DEFAULT = 0; /** Timestamp format *DTS ("Standard Time Format").
  • Example: The timestamp value 0x8000000000000000 represents 2000-01-01 00:00:00.000000, in the time zone context of the IBM i system.
  • Range of years: 1928-2071
    (Date range: 1928-07-25 00:00:00.000000 to 2071-05-09 00:00:00.000000)
  • Default separator: not applicable (no separator)
  • Length: 8 bytes
  • Note: The time zone context is the time zone of the IBM i system, rather than GMT.
    The base date and time for the TOD clock, or the date and time represented by hex value 0x0000000000000000, is August 23, 1928 12:03:06.314752 (in the time zone of the IBM i system).
**/ static final int FORMAT_DTS = 1; // for internal Toolbox use only // From the spec for the QWCCVTDT API: // "the supported date range [for format *DTS is] from August 25, 1928, 00:00:00.000000 to May 09, 2071, 00:00:00.000000". // From the MI instructions spec: // // The Standard Time Format [*DTS] is defined as a 64-bit (8-byte) unsigned binary value as follows: // // Offset // Dec Hex Field Name Data Type and Length // ___ ___ ____________________ ____________________ // 0 0 Standard Time Format UBin(8) // 0 0 Time Bits 0-51 (52 bits) // 0 0 Uniqueness bits Bits 52-63 (12 bits) // 8 8 --- End --- // // // The time field is a binary number which can be interpreted as a time value in units of 1 microsecond. A binary 1 in bit 51 is equal to 1 microsecond. // // The "uniqueness bits" field may contain any combination of binary 1s and 0s. These bits do not provide additional granularity for a time value; they merely allow unique 64-bit values to be returned, such as when the value of the time-of-day (TOD) clock is materialized. When the uniqueness bits all contain binary 0s, then the 64-bit value returned is not unique. Unless explicitly stated otherwise, MI instructions which materialize the TOD clock return a unique 64-bit value. // Design note: According to the IBM i datatype spec: // "Microseconds (.mmmmmm) are optional for timestamp literals and if not provided will be padded // on the right with zeros. Leading zeros are required for all timestamp data." // For simplicity, we will assume that the "timestamp" fields encountered by the Toolbox, // will always occupy exactly 26 bytes on the system, and will always specify microseconds. /** Constructs an AS400Timestamp object. Assumes the timezone to be GTM. **/ public AS400Timestamp() { super(); setFormat(0, HYPHEN); // this data type has only one format } /** Constructs an AS400Timestamp object. * @param timeZone **/ public AS400Timestamp(TimeZone timeZone) { super(timeZone); setFormat(0, HYPHEN); // this data type has only one format } /** Constructs an AS400Timestamp object when datalength < 26. * @param timeZone * @param dataLength */ public AS400Timestamp(TimeZone timeZone, int dataLength) { super(timeZone); setFormat(0, HYPHEN); setDataLength(dataLength); } // Overrides method of superclass. /** Returns a Java object representing the default value of the data type. @return a java.sql.Timestamp object with a value of January 1, 1970, 00:00:00 GMT **/ public Object getDefaultValue() { // Design note: According to the IBM i datatype spec: // "The default initialization value for a timestamp is midnight of January 1, 0001 (0001-01-01-00.00.00.000000)." // However, for simplicity, we will stay consistent with our other "date" classes on the default value, until/unless we get a requirement to do otherwise. if (defaultValue_ == null) { defaultValue_ = new java.sql.Timestamp(0L); // January 1, 1970, 00:00:00.000000 GMT } return defaultValue_; } // Implements abstract method of superclass. /** Returns {@link AS400DataType#TYPE_TIMESTAMP TYPE_TIMESTAMP}. @return AS400DataType.TYPE_TIMESTAMP. **/ public int getInstanceType() { return AS400DataType.TYPE_TIMESTAMP; } // Implements abstract method of superclass. /** Returns the Java class that corresponds with this data type. @return java.sql.Timestamp.class. **/ public Class getJavaType() { return java.sql.Timestamp.class; } // Used by class 'User'. /** Sets the format of this AS400Timestamp object. The specified format's default separator is used. @param format The format for this object. Valid values are:
  • {@link #FORMAT_DEFAULT FORMAT_DEFAULT}
  • {@link #FORMAT_DTS FORMAT_DTS}
**/ void setFormat(int format) { super.setFormat(format); } // Overrides method of superclass. This allows us to be more specific in the javadoc. /** Converts the specified Java object into IBM i format in the specified byte array. @param javaValue The object corresponding to the data type. It must be an instance of {@link java.sql.Timestamp java.sql.Timestamp}. @param as400Value The array to receive the data type in IBM i format. There must be enough space to hold the IBM i value. @param offset The offset into the byte array for the start of the IBM i value. It must be greater than or equal to zero. @return The number of bytes in the IBM i representation of the data type. **/ public int toBytes(Object javaValue, byte[] as400Value, int offset) { return super.toBytes(javaValue, as400Value, offset); } // Implements abstract method of superclass. /** Converts the specified IBM i data type to a Java object. @param as400Value The array containing the data type in IBM i format. The entire data type must be represented. @param offset The offset into the byte array for the start of the IBM i value. It must be greater than or equal to zero. @return a {@link java.sql.Timestamp java.sql.Timestamp} object corresponding to the data type. The reference time zone for the object is GMT. **/ public Object toObject(byte[] as400Value, int offset) { if (as400Value == null) throw new NullPointerException("as400Value"); java.sql.Timestamp dateObj = null; switch (getFormat()) { case FORMAT_DEFAULT: { String timestampString = getCharConverter().byteArrayToString(as400Value, offset, getLength()); // Parse the string, and create a java.sql.Timestamp object. dateObj = parse(timestampString); break; } // This format is only used internally by Toolbox classes such as 'User'. case FORMAT_DTS: { // Determine the "elapsed microseconds" value represented by the *DTS value. // Note that *DTS values, in theory, specify microseconds elapsed since August 23, 1928 12:03:06.314752. // However, the real reference point is January 1, 2000, 00:00:00.000000, // which is represented by *DTS value 0x8000000000000000. // In the returned *DTS value, only the first 8 bytes are meaningful. // Of those 8 bytes, only bits 0-51 are used to represent "elapsed microseconds". // To prevent sign-extension when we right-shift the bits: // Copy the first 8 bytes into a 9-byte array, preceded by 0x00. byte[] bytes9 = new byte[9]; System.arraycopy(as400Value, offset, bytes9, 1, 8); // right-justify BigInteger bits0to63 = new BigInteger(bytes9); // bits 0-63 // Convert base of date from August 23, 1928 12:03:06.314752 to January 1, 2000, 00:00:00.000000. byte[] dts2000 = { 0, (byte)0x80, 0,0,0,0,0,0,0 }; // 0x8000000000000000 BigInteger basedOn2000 = bits0to63.subtract(new BigInteger(dts2000)); // Eliminate the "uniqueness bits" (bits 52-63). // Right-shift 12 bits, without sign-extension, leaving bits 0-51. BigInteger microsElapsedSince2000 = basedOn2000.shiftRight(12); // Convert the above value to "microseconds elapsed since January 1, 1970, 00:00:00". That gets us closer to a value we can use to create a Java timestamp object. BigInteger microsElapsedSince1970 = microsElapsedSince2000.add(DTS_CONVERSION_FACTOR); // Milliseconds elapsed since January 1, 1970, 00:00:00 long millisSince1970 = microsElapsedSince1970.divide(ONE_THOUSAND).longValue(); // 1 millisec == 1000 microsecs dateObj = new java.sql.Timestamp(millisSince1970); // GMT time zone // Set the "nanoseconds into the second". int microsIntoSecond = microsElapsedSince1970.mod(ONE_MILLION).intValue(); dateObj.setNanos(1000*microsIntoSecond); // 1 microsec == 1000 nanosecs break; } default: // this will never happen throw new InternalErrorException(InternalErrorException.UNKNOWN, "Unrecognized format: " + getFormat(), null); } return dateObj; } /** Converts the specified IBM i data type to a Java object. This method is simply a convenience front-end to the {@link #toObject(byte[]) toObject(byte[])} method. @param as400Value The array containing the data type in IBM i format. The entire data type must be represented. @return a {@link java.sql.Timestamp java.sql.Timestamp} object corresponding to the data type. The reference time zone for the object is GMT. **/ public java.sql.Timestamp toTimestamp(byte[] as400Value) { return (java.sql.Timestamp)toObject(as400Value, 0); } /** Converts the specified IBM i data type to a Java object. This method is simply a convenience front-end to the {@link #toObject(byte[],int) toObject(byte[],int)} method. @param as400Value The array containing the data type in IBM i format. The entire data type must be represented. @param offset The offset into the byte array for the start of the IBM i value. It must be greater than or equal to zero. @return a {@link java.sql.Timestamp java.sql.Timestamp} object corresponding to the data type. The reference time zone for the object is GMT. **/ public java.sql.Timestamp toTimestamp(byte[] as400Value, int offset) { return (java.sql.Timestamp)toObject(as400Value, offset); } /** Creates a new java.util.Date object representing the Timestamp's nominal value, in the context of the specified time zone. That is, the timestamp is re-interpreted as if its reference context were the specified time zone. This assume that the current timestamp is represented in GMT.

For example, if timestamp represents "2000-01-01-00.00.00.000000 GMT", and timezone specifies CST, then this method will return a java.util.Date object representing "2000-01-01-00.00.00.000000 CST".

Note that java.util.Date has milliseconds precision, whereas java.sql.Timestamp has nanoseconds precision. When converting from Timestamp to Date, nanoseconds are rounded to the nearest millisecond. @param timestamp The timestamp object. @param timezone The desired reference time zone to assign to the returned Date object. @return A Date object representing the same nominal timestamp value as represented by timestamp, with time zone context timezone. **/ public java.util.Date toDate(java.sql.Timestamp timestamp, TimeZone timezone) { if (timestamp == null) throw new NullPointerException("timestamp"); if (timezone == null) throw new NullPointerException("timezone"); // We assume that the default/implied contextual timezone of all Timestamp objects is the server timezone // This is certainly the case for all Timestamp objects created by this class. if (timezone.equals(AS400AbstractTime.TIMEZONE_GMT)) return (Date)timestamp; long millisSince1970 = timestamp.getTime(); int nanosIntoSecond = timestamp.getNanos(); // For consistency with the QWCCVTDT API (used by the DateTimeConverter class), round up if fractional milliseconds are 500 microseconds or greater. int nanosIntoMillisecond = nanosIntoSecond % 1000000; // 1 millisec == 1,000,000 nanosecs if (nanosIntoMillisecond >= 500000) { // half a millisecond millisSince1970 += 1; // round up to the next millisecond } else {} // truncate the partial milliseconds Date dateObj; synchronized (this) { getCalendar().setTimeInMillis(millisSince1970); dateObj = getCalendar().getTime(); // this object is based the server time zone } String dateAsString = getDateFormatterWithMillis(AS400AbstractTime.TIMEZONE_GMT).format(dateObj); // Create a new Date object in the desired timezone, representing the same timestamp string expression as above. // Note: In the US, depending on the year, Daylight Saving Time begins between March 8-14, and // ends between November 1-7. Different JVMs may have different understandings of exactly when // Daylight Saving Time starts and ends. This may lead to inconsistent setting of the time zone of the // returned Date object, on dates that fall in those DST transition periods. try { return getDateFormatterWithMillis(timezone).parse(dateAsString); } catch (java.text.ParseException e) { // should never happen Trace.log(Trace.ERROR, e); throw new InternalErrorException(InternalErrorException.UNEXPECTED_EXCEPTION, e); } } // Implements abstract method of superclass. /** Converts the specified Java object into a String representation that is consistent with the format of this data type. @param javaValue The object corresponding to the data type. This must be an instance of {@link java.sql.Timestamp java.sql.Timestamp}, and must be within the range specifiable by this data type. @return A String representation of the specified value, formatted appropriately for this data type. @throws ExtendedIllegalArgumentException if the specified date is outside of the range representable by this data type. **/ public String toString(Object javaValue) { if (javaValue == null) throw new NullPointerException("javaValue"); java.sql.Timestamp timestampObj; try { timestampObj = (java.sql.Timestamp)javaValue; } catch (ClassCastException e) { Trace.log(Trace.ERROR, "javaValue is of type " + javaValue.getClass().getName()); throw e; } // Round up to the next microsecond, if fractional microseconds are 500 nanoseconds or greater. int nanosIntoSecond = timestampObj.getNanos(); int microsIntoSecond = nanosIntoSecond/1000; // 1 microsec == 1000 nanosecs int nanosIntoMicrosecond = nanosIntoSecond % 1000; // remainder if (nanosIntoMicrosecond >= 500) { // half a microsecond if (DEBUG) { System.out.println("AS400Timestamp.toString: Rounding up to next microsecond."); System.out.println("nanosIntoSecond="+nanosIntoSecond+"; microsIntoSecond="+microsIntoSecond+"; nanosIntoMicrosecond="+nanosIntoMicrosecond); } microsIntoSecond += 1; // round up to the next microsecond // See if the round-up moved us up into the next second. if (microsIntoSecond > 999999) { java.sql.Timestamp newObj = new java.sql.Timestamp(timestampObj.getTime() + 1000); // advance to next second up (1 sec == 1000 msecs). timestampObj = newObj; microsIntoSecond = 0; } } // Verify that the 'year' value from the date is within the range of our format. int year, era; synchronized (this) { Calendar cal = getCalendar(timestampObj); year = cal.get(Calendar.YEAR); era = cal.get(Calendar.ERA); } if (year < 1 || year > 9999) { throw new ExtendedIllegalArgumentException("javaValue (year=" + year + ")", ExtendedIllegalArgumentException.RANGE_NOT_VALID); } if (era == 0) { // we can't represent years BCE throw new ExtendedIllegalArgumentException("javaValue (era=0)", ExtendedIllegalArgumentException.RANGE_NOT_VALID); } String micros = to6Digits(microsIntoSecond); // prepend zeros as needed return ( getDateFormatter().format(timestampObj) + "." + micros ); } /** Converts a string representation of a timestamp, to a Java object. @param source A timestamp value expressed as a string in standard IBM i {@link #FORMAT_DEFAULT timestamp} format. @return A {@link java.sql.Timestamp java.sql.Timestamp} object representing the specified timestamp. The reference time zone for the object is GMT. **/ public java.sql.Timestamp parse(String source) { if (source == null) throw new NullPointerException("source"); //@Y8D Start //if (source.length() < 26) { // Trace.log(Trace.ERROR, "Timestamp string is expected to be in format: " + patternFor(getFormat(), getSeparator()) + ".ssssss"); // throw new ExtendedIllegalArgumentException("source ("+source+")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID); //} //@Y8D End //@Y8A Start if (source.length() < 19) { Trace.log(Trace.ERROR, "Timestamp string is expected to be in format: " + patternFor(getFormat(), getSeparator()) + ".ssssss"); throw new ExtendedIllegalArgumentException("source ("+source+")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID); } //@Y8A End try { // Our SimpleDateFormat formatter doesn't handle microseconds. // Strip out the fractional seconds before parsing; then re-append them later. // The default IBM i "timestamp" format is: yyyy-mm-dd-hh.mm.ss.mmmmmm // Exclude the fractional seconds for now. java.util.Date dateObjWithoutMicros = getDateFormatter().parse(source.substring(0,19)); // Now add the fractional seconds back in. //int microsIntoSecond = Integer.parseInt(source.substring(20)); // skip the period @Y8D java.sql.Timestamp timestampObj = new java.sql.Timestamp(dateObjWithoutMicros.getTime()); //@Y8A Start if (source.length() > 19) { while(source.length() < 26) { source += "0"; } int microsIntoSecond = Integer.parseInt(source.substring(20)); timestampObj.setNanos(1000*microsIntoSecond); // 1 microsec == 1000 nanosecs } //@Y8A End //timestampObj.setNanos(1000*microsIntoSecond); // 1 microsec == 1000 nanosecs @Y8D return timestampObj; } catch (Exception e) { // Assume that the exception is because we got bad input. Trace.log(Trace.ERROR, e.getMessage(), source); Trace.log(Trace.ERROR, "Timestamp string is expected to be in format: " + patternFor(getFormat(), getSeparator()) + ".ssssss"); throw new ExtendedIllegalArgumentException("source ("+source+")", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID,e); } } /** Converts the specified ISO representation of a timestamp, to a Java object. This method is provided for use by the PCML infrastructure. in particular, when parsing 'init=' values for 'timestamp' data elements. The timezone used by this method is GMT. @param source A timestamp value expressed as a string in format yyyy-MM-ddTHH:mm:ss.SSSSSSSSS. For example: 2010-01-01T23:59:59.999999999 @return A {@link java.sql.Timestamp java.sql.Timestamp} object representing the specified timestamp. **/ public static java.sql.Timestamp parseXsdString(String source) { return parseXsdString(source, AS400AbstractTime.TIMEZONE_GMT); } /** Converts the specified ISO representation of a timestamp, to a Java object. This method is provided for use by the PCML infrastructure. in particular, when parsing 'init=' values for 'timestamp' data elements. @param source A timestamp value expressed as a string in format yyyy-MM-ddTHH:mm:ss.SSSSSSSSS. For example: 2010-01-01T23:59:59.999999999 @param timeZone time zone to used for the conversion. @return A {@link java.sql.Timestamp java.sql.Timestamp} object representing the specified timestamp. **/ public static java.sql.Timestamp parseXsdString(String source, TimeZone timeZone) { if (source == null) throw new NullPointerException("source"); try { // First, separate-out the fractional seconds (nanoseconds) at the end of the string, // leaving something that can be parsed by SimpleDateFormat. int nanos = 0; String withoutNanos = source.substring(0,19); // up to the '.' (exclusive) if (source.length() > 20) { StringBuffer fractionalSeconds = new StringBuffer(source.substring(20)); // Pad with trailing zeros, to 9 digits, so as to specify "number of nanoseconds". int numZerosToAdd = 9 - fractionalSeconds.length(); for (int i=0; iyyyy-MM-ddTHH:mm:ss.SSSSSSSSS. **/ public static String toXsdString(Object javaValue) { return toXsdString(javaValue, TIMEZONE_GMT); } /** Converts the specified Java object into a String representation that is consistent with the format of this data type. This method is provided for use by the PCML infrastructure. @param javaValue The object corresponding to the data type. This must be an instance of {@link java.sql.Timestamp java.sql.Timestamp}, and must be within the range specifiable by this data type. @param timeZone Time zone used to interpret the value. @return The timestamp expressed as a string in format yyyy-MM-ddTHH:mm:ss.SSSSSSSSS. **/ public static String toXsdString(Object javaValue, TimeZone timeZone) { if (javaValue == null) throw new NullPointerException("javaValue"); java.sql.Timestamp timestampObj; try { timestampObj = (java.sql.Timestamp)javaValue; } catch (ClassCastException e) { Trace.log(Trace.ERROR, "javaValue is of type " + javaValue.getClass().getName()); throw e; } StringBuffer timestampString = new StringBuffer(getTimestampFormatterXSD(timeZone).format(timestampObj)); // Append nanoseconds. timestampString.append('.'); timestampString.append(to9Digits(timestampObj.getNanos())); return timestampString.toString(); } // Implements abstract method of superclass. String patternFor(int format, Character separator) { // SimpleDateFormat has a "milliseconds" pattern, but no "microseconds" or "nanoseconds" pattern. // Therefore, to generate a pattern consumable by SimpleDateFormat, we omit the fractional seconds entirely here. We re-append the fractional seconds elsewhere in the code. return PARSING_PATTERN; } // Implements abstract method of superclass. Character defaultSeparatorFor(int format) { return HYPHEN; } // Utility method used internally. private synchronized SimpleDateFormat getDateFormatterWithMillis(TimeZone timezone) { if (dateFormatterWithMillis_ == null) { dateFormatterWithMillis_ = new SimpleDateFormat("yyyy-MM-dd HH.mm.ss.SSS"); dateFormatterWithMillis_.setTimeZone(timezone); } else if (!dateFormatterWithMillis_.getTimeZone().equals(timezone)) { dateFormatterWithMillis_.setTimeZone(timezone); } return dateFormatterWithMillis_; } // Implements abstract method of superclass. boolean isValidFormat(int format) { return validateFormat(format); } // Validates the specified format value. static boolean validateFormat(int format) { if (format < FORMAT_DEFAULT || format > FORMAT_DTS) return false; else return true; } /** Returns the number of bytes occupied on the IBM i system by a field of this type. **/ static int getByteLength(int format) { switch (format) { case FORMAT_DTS: return 8; // field length is 8 bytes default: // FORMAT_DEFAULT return 26; // field length is 26 bytes } } // Implements abstract method of superclass. int lengthFor(int format) { return getByteLength(format); } // Utility method. // Creates a 6-digit decimal string to represent an integer, prepending 0's as needed. The value must be in the range 0 - 999999. static final String to6Digits(int value) { if (value < 0 || value > 999999) { throw new InternalErrorException(InternalErrorException.UNKNOWN, "to6Digits("+value+")",null); } StringBuffer buf = new StringBuffer(Integer.toString(value)); int zerosToPrepend = 6 - buf.length(); for (int i=0; i 999999999) { throw new InternalErrorException(InternalErrorException.UNKNOWN, "to9Digits("+value+")",null); } StringBuffer buf = new StringBuffer(Integer.toString(value)); int zerosToPrepend = 9 - buf.length(); for (int i=0; i





© 2015 - 2024 Weber Informatics LLC | Privacy Policy