PROGRAMMING

 PC Hardware  |  PC Software  |  Networking  |  Web Designs  |  News Letter   |  Home

 

 JAVA 3

 

7. I/O

  1. (Sect. 7) How do I read a file containing ASCII numbers?

* There are several ways to do this. Here is one way. Let's assume your file is called "C:\work\mydata.txt" and it contains lines like:

    135   7512   3659814  328   1 54829
    68522 19982810  38 

i.e. lines contain several ASCII strings that are numbers separated by spaces.
The code fragment is as follows:

//  Open the file with    
RandomAccessFile f = new RandomAccessFile("c:\\work\\datafile.txt", "r");
 
// read an entire line from it
String s= f.readLine();
 
// get some methods to break up a line into tokens
StringTokenizer st = new StringTokenizer(s);
 

// extract the next int from the line
i = Integer.parseInt(st.nextToken());

We use a RandomAccessFile because that supports the readLine() method directly. An alternative would be to instantiate a FileReader, and wrap a BufferedReader around it. Putting it all together, including the exception handling in the event the file is missing, the code looks like:

import java.io.*;
import java.util.*;
public class c  {
    public static void main(String args[]) {
      try {
        RandomAccessFile f = new RandomAccessFile
                                        ("datafile.txt", "r");
        String s;
        while ( (s=f.readLine()) != null )  {
            System.out.println("read: "+s);
 

            StringTokenizer st = new StringTokenizer(s);
            int i=0;
            while (st.hasMoreTokens()) {
               i = Integer.parseInt(st.nextToken());
               // i now holds the next int on the line
               // could also use Double.parseDouble(), etc.
 

               System.out.print(" "+ i);
            }
            System.out.println();
        }
 

      } catch (Exception e) {System.out.println("Excpn: "+e); }
      // file I/O, from book "Just Java" by Peter van der Linden
    }
}

See also the next question on how to read data interactively.

  1. (Sect. 7) How do I read a String/int/boolean/etc from the keyboard?

*The easiest way is to pick up the source for the 100% pure Java class EasyIn from http://www.afu.com/ (same place as this FAQ). Compile it with your code and use it like this:

EasyIn easy = new EasyIn();
 

int i = easy.readInt(); // gets an int from System.in
boolean b = easy.readBoolean(); // gets a boolean from System.in
double d = easy.readDouble(); // gets a double from System.in
    

... etc.

EasyIn is free, comes with source, and you can do what you like with it, including improve it, and send me back the results.

If, instead, you want to "roll your own" code (why?!), in JDK 1.0.2

java.io.DataInputStream in = new java.io.DataInputStream(System.in);
String s = in.readLine();
    

One way in JDK 1.1:

java.io.BufferedReader in =
 new java.io.BufferedReader( new InputStreamReader(System.in));
 

String s = in.readLine();
    

Once you have the token in a String, it is easy to parse it into one of the other types, as shown earlier in the FAQ. Yes, it is bone-headed, as it makes the simplest case of keyboard I/O unnecessarily complicated. A bug was filed with Javasoft to record this problem, and it may be addressed as soon as JDK 1.4

  1. (Sect. 7) Why do I have trouble with System.out.println()?

*Check the spelling. The last two characters are the letters "ell enn" not "one enn".

The name of the method stands for "print line", since it prints a String and goes to the next line, rather than staying on the same line as System.out.print() does. Yes, the name is yet another naming inconsistency, since the input equivalent is readLine(), not readln().

  1. (Sect. 7) How do I write to the serial port on my PC using Java Technology?

*There is a platform-independent serial port API introduced in JDK 1.2. You can download the documentation by registering with the Java Developer Connection (it's free, http://java.sun.com/) and searching for "serial port" or "Communications API".

For systems prior to JDK 1.2, read on. At least two companies have written a library to drive the port. See

While not helpful to typical home users, there is an alternative portable COM port solution for Java 1.1 and even 1.0. Buy your COM ports in the form of "terminal servers". Using a COM port is now as easy as connecting to it with a Socket. Port parameters can be changed programatically using SNMP for most terminal servers (but this is never necessary when a modern modem or other fixed-rate equipment is attached). Any networked box can serve as a terminal server - even Win95 - with a simple native server application for that box, but buying an actual firmware based hardware box is much easier.

Furthermore, your Win95 native applications can now share the COM ports (and any attached modems) via a Win95 product called "Dial-out IP" at http://www.tactical-sw.com/.

If the port exists as a pathname in the filesystem, you can open it as a file and read/write. You can also print text this way by writing to "prn" or "lpt1" on a pc, and "/dev/something" on Unix. Writing a formfeed at the end of the file is essential on Windows 95. Here is some sample code:

// class that opens the printer as a file
// and writes "Hello World" to it
 

import java.io.*;
public class lpt {
    public static void main (String[] argv) {
        try {
            FileOutputStream os = new FileOutputStream("LPT1");
            //wrap stream in "friendly" PrintStream
            PrintStream ps = new PrintStream(os);
 

            //print text here
            ps.println("Hello world!");
 

            //form feed -- this is important
            //Without the form feed, the text will simply sit
            // in print buffer until something else gets printed.
            ps.print("\f");
            //flush buffer and close
            ps.close();
        } catch (Exception e) {
            System.out.println("Exception occurred: " + e);
        }
    }
}
    
  1. (Sect. 7) How do I append to a file?

*There are two ways. JDK 1.1 introduced new constructors for two of the output classes that allowed you to set a boolean flag:

public FileWriter(String fileName, boolean append) throws IOException
public FileOutputStream(String name, boolean append) throws IOException
    

Another way is to do this:

RandomAccessFile fd = new RandomAccessFile(file,"rw");
fd.seek(fd.length());
    

Then write using fd. Note that the latter method does not take advantage of the "append" mode present in many operating systems (such as all Unixes). Such a difference may make a difference with multiple processes or threads appending to the same output file. This can happen frequently, even if not intended by the programmer, e.g. with logfiles in multitasking environments.

  1. (Sect. 7) Is it possible to lock a file?

*JDK 1.2 introduces the ability to code up some support for a cooperative file access protocol using the File class. Some people hold that the only acceptable form of file locking is mandatory (not cooperative) locking. These people will be disappointed by the approaches listed below, and will say (accurately) Java does not have support for mandatory file locking.

Other people are satisfied with cooperative locking protocols, and will say (accurately) that you can lock a file indirectly in Java using the File class. This is a hack though. The JDK does not feature a true API to lock a file, or regions within a file, but it is under consideration for the future (bug 4024206 if you want to vote on it). Code that needs to do locking today must take one of four kludge approaches:

1.      Use the atomic operation File.createNewFile(), and mark it as deleteOnExit(). [These calls were introduced in JDK 1.2] The file name doesn't really matter - you aren't going to write to it just use it as a convenient sync object. So you create a second, semaphore-type file with a name that can be based on that of the file you're trying to "lock", perhaps with an extension like "_LOCK" or something. Probably in the same directory as the file to be locked. Have all processes (Java and non-Java) follow the same protocol: if the create operation succeeded, you have the lock. To give up the lock, you either delete the file or exit the JVM.

Note that this may fail if the file is remotely mounted using the old version 2 of NFS (There's a window of opportunity between the LOOKUP to see if it's already there, and the CREATE if it's not). However, NFS version 3 does guarantee exclusive create of remotely mounted files, and is not subject to this race condition failure.

Note: there's a chance that the filename + extension will end up matching an already-existing filename, but that can be minimized if you check for this on starting your program, and make the extension sufficiently esoteric. Alternately the semaphore files could be in another directory such as the default temp directory, but then the risk is that two files in different directories with the same name will have the same semaphore file.

2.      Implement an advisory locking scheme using features that Java does have (such as synchronized methods or atomic file creation). Synchronize on any single mutually agreeable object within the one JVM. E.g. perhaps sync on the String returned by File.getCanonicalPath().intern() for any easy way to map arbitrary file to file lock object. This allows you to lock files against use by other Java code running in the same JVM.

3.      Make calls to native code to issue the locking ioctls. This approach is not portable, but gives you a shot at having your locks respected by legacy code in non-Java programs using standard locking ioctls.

4.      Push the work to a central server. Since socket connection requests arrive in a single queue on the server, this can be used to serialize lock requests. There might be some merit in copying the NFS lockd protocol for a general approach. Rolling your own simple version for a specific application is pretty easy. A database would be better off locking records or fields, not byte offsets. In theory, the server socket approach would make it easier to perform automatic cleanup of a lock on abrupt VM process failure, e.g. by asking "are you still alive?" to the lock holder occasionally.

  1. (Sect. 7) How do I make the keyboard beep?

*In JDK 1.1, java.awt.Toolkit has the method beep(). The pre-1.1 alternative of

System.out.print("\07");
System.out.flush();

(the ASCII BEL character) doesn't work on Macs, but does on some other platforms. The language doesn't support the C abstraction of '\a' for an alert character.

  1. (Sect. 7) How do you do file I/O from an applet?

*For security reasons, untrusted applets accessed across the network are restricted from doing certain operations, including local I/O. This prevents rogue applets from sending out your private data, or deleting it. A trusted (signed) applet can perform these operations (JDK 1.1 on).

The simplest approach for server-side I/O is to use the Linlyn class available from http://www.afu.com/. This is free software under the GNU license, and uses FTP to move files between an applet and the server. It is suitable for low-volume non-critical use like keeping a high-score file. The Linlyn class by design has the simplest possible application programmer interface.

    • The following suggestion is for server-side input.

You can read a file on the server if you can create a URL referencing the file. Then open a stream, then use any of the stream-based methods to read.

This allows reading but not writing. It requires an http daemon running on the server, which will usually be the case.

try{
   URL url = new URL("http://somewhere.com/test.txt");
 // or URL url = new URL( getDocumentBase(), filename);
   BufferedReader in = new BufferedReader(    
                         new InputStreamReader( 
                            url.openStream() ) );
   String s = in.readLine(); //read till you get a null line.
   } catch(MalformedURLException e){
           System.out.println("URLException:"+e);
   } catch(IOException e){
           System.out.println("IOException:"+e);
   }
}
        

You can theoretically write a file on the server in a similar way. Try using the PrintWriter. It works the same way as posting data to a form on a web page. You may have to do a dummy read to complete the post.

    URLConnection connection = url.openConnection();
    connection.setDoOutput(true);
    PrintWriter out = new PrintWriter(connection.getOutputStream());
    out.println("your line of text ... or stream of data" );
    out.close();

In practice, setDoOutput() only works if your server is set up to allow that. Most aren't.

    • The following suggestions are for server-side output.

It absolutely requires the cooperation of the server to allow an applet to write a file to the server. You cannot achieve this by applet code alone. This cooperation may take any of several forms:

      • FTP server
      • File server (webnfs or custom written)
      • Listening on a socket for data from applets
      • CGI script
      • Java RMI (remote method invocation)
      • JDBC process

In particular:

      • FTP code. Use the Linlyn class mentioned above.
      • WebNFS. This is an evolution of the NFS (Network File System) to make file resources visible in browsers. More information at http://www.sun.com/webnfs/
      • Open a socket back to the server and read/write the data. Have a process on the server that listens for socket connections from applets and does the requisite I/O. This does I/O on the server.
      • Or use a CGI script or servlet on the server to write when browsed.
    • The following suggestions are for client-side I/O. Use a trusted applet (see section on security). This will permit local I/O without any of the restraints mentioned above. In this regard, the appletviewer and many other browsers regard applets loaded from a local filesystem (rather than across the net) as being more trustworthy, and perhaps even allowed to do I/O.
    • The simplest form of output is probably for the applet to connect to the mailserver port on the server, and prompt the user to enter his email address. Then email him the data to save locally if he wishes. If a small amount of data he can later enter it by cut-and-paste into the applet when he next invokes it.
    • Or use a browser that has a security policy that is configured to allow file I/O (such as Sun's appletviewer).
    • Read this article http://www.javareport.com/html/features/archive/9802/somers.shtml for an introduction to the basics.
  1. (Sect. 7) What are Resources files and how do they work?

*In Java 1.1 and above, a resource file is a file that your code should be able to access no matter where it was loaded from: the local file system, via http, or some other means. Note that this is a different concept than system resources. See question (TBD) for more information about system resources. (Volunteer sought to write answer on system resource files).

There are two ways to specify resources.

    • using an absolute path name, such as "/myPackage/resourcedir/myResource.txt"
      With an absolute path name, the resource file is actually relative to the classpath.
    • using a relative path such as "dir/myResource.txt".
      If you specify a relative path, then the file is found relative to where the class loader found the package of the Class that is loading the resource. The consequence of this is that relative resource files can only be in the same directory as your class file or in a directory below.

If you want to access resources from an unsigned applet, use relative resources.

There are a couple of methods to get at resources, including methods in the java.lang.Class and java.lang.Classloader. It uses the class loader because that code knew where to find the class on the filesystem. If the resource file is nearby, it can be found the same way. One simple method to get a stream for a resource for a particular class, say Mypackage.MyClass, is as follows:

String relativePath = "resourceDir/somefile.txt";
String absolutePath = "/somePackage/somefile.txt";
InputStream in=Mypackage.MyClass.class.getResourceAsStream(relativePath);

If the class cannot be loaded, "in" would be assigned a null value. Otherwise, you can use the inputStream just as any other.

A brief note about the syntax used above. In java 1.1 and above, a java.lang.Class object for a particular class can be acquired by appending .class to the class's name. Though it looks like every object has a static member variable, this is not actually the case.

When using resources with Netscape, be aware of the Netscape restrictions that:

    • Netscape does not implement the getResource() methods in java.lang.Class and java.lang.ClassLoader, but only getResourceAsStream() methods.
    • All resources must be in a Jar/archive file
    • Resource files must have a Netscape-approved extension, or you must call certain functions before hand. See the following for details: http://developer.netscape.com/docs/technote/java/getresource/getresource.html

Internet Explorer does not seem to have these restrictions.

One final "gotcha" is that jpgStream.available() (wrongly) returns 1 when .gif files in the .jar file are compressed! Some people now create a .jar file in two steps, essentially:

  jar cvf x.jar *.class
  jar uf0 x.jar *.gif

This ensures .gifs are not compressed, and hence that available() doesn't lie to you. David Alex Lamb stumbled onto this after wondering why his .gif files looked bad, then realized that compression of a .gif might throw away detail. The conjecture is that available() returns 1 because it has to block to do uncompression.

Be careful that you retrieve files from jars, in the right way. See http://developer.java.sun.com/developer/bugParade/bugs/4251549.html
This code works for files and files in jars: URLClassLoader cl = (URLClassLoader)this.getClass().getClassLoader(); url = cl.findResource("images/save.gif"); saveButton.setIcon(new ImageIcon(url));

  1. (Sect. 7) How do I execute a command from a program? How do I do I/O redirection when using exec()?

*See the answer to Question 18.6.

  1. (Sect. 7) I used a C program to write a binary file. When I instantiate a DataInputStream on the file, and try to readInt, I do not get the correct numbers. Why is this?

*The Java programming language does everything in network byte order (big-endian order), as do many computers including Motorola, and SPARC. The Intel x86 uses little-endian order in which the 4 bytes of an int are stored least significant first. Rearranging the bytes on the way in will get you the results you need. This is only necessary when the file was written by a non-Java program on a little-endian machine such as a PC.

The following code will byte-swap little-endian integers into network standard order:

public int swap(int i) {
    int byte0 = i & 0xff;
    int byte1 = (i>>8) & 0xff;
    int byte2 = (i>>16) & 0xff;
    int byte3 = (i>>24) & 0xff;
    // swap the byte order
    return (byte0<<24) | (byte1<<16) | (byte2<<8) | byte3;
}
    

Alternatively, the following code assembles bytes from a byte array that is in big-endian order (as used by Java programming language) into an int:

byte[] bytes = ... // whatever
int start_index = ... // wherever
 

int value = 0;
for ( int i = start_index; i < start_index+4; ++i ) {
    value = ( value << 8 ) | ( bytes[i] & 0xFF ); 
}
    

If the bytes are in little-endian order, just change the "for"

for ( int i = start_index+3; i >= start_index; --i )
    

And this code will assemble a double that has been written in reverse byte order:

  byte[] gnol = new byte[8];
  stream.read(gnol);
 

  long l = (
             ( (gnol[7] & 0xff) << 56) |
             ( (gnol[6] & 0xff) << 48) |
             ( (gnol[5] & 0xff) << 40) |
             ( (gnol[4] & 0xff) << 32) |
             ( (gnol[3] & 0xff) << 24) |
             ( (gnol[2] & 0xff) << 16) |
             ( (gnol[1] & 0xff) <<  8) |
               (gnol[0] & 0xff)
           );
 

  double d = Double.longBitsToDouble(l);
    
  1. (Sect. 7) How do I make I/O faster? My file copy program is slow.

*This is the purpose of BufferedInputStream. It is a flaw in Java that buffered I/O is not the default, with a flag or different constructor to turn it off. I/O is the second worst designed package in the API, after the Date class. ,

  1. (Sect. 7) How do I do formatted I/O of floating point numbers?

*Use the class java.text.NumberFormat.

Or use http://www.newbie.net/sharky/lava/. Or use Cay Horstmann's http://www.horstmann.com/corejava/Format.java
Although many utilities claim to handle all varieties of C's printf, as far as has been found, this is the only one to correctly handle the equivalent of %e in printf.

See also the standard packages java.text.DecimalFormat and java.text.NumberFormat

  1. (Sect. 7) How do I read numbers in exponential format?

*The program below (written by Steve Chapel) uses StreamTokenizer to read data from the standard input and recognizes doubles in exponential format (e.g. -1.23e-45). Note that bug id #4079180 is an RFE for adding this feature into StreamTokenizer.

import java.io.*;
public class ReadExponential {
  public static void main(String args[]) throws IOException {
    Reader in = new InputStreamReader(System.in);
    StreamTokenizer st = new StreamTokenizer(in);
    while (st.nextToken() != StreamTokenizer.TT_EOF) {
      switch (st.ttype) {
      case StreamTokenizer.TT_NUMBER:
        double num = st.nval;
        int exp = 0;
        st.ordinaryChars('\0', ' ');
        st.nextToken();
        st.whitespaceChars('\0', ' ');
        if (st.ttype == StreamTokenizer.TT_WORD &&
            Character.toUpperCase(st.sval.charAt(0)) == 'E') {
          try {
            exp = Integer.parseInt(st.sval.substring(1));
          } catch (NumberFormatException e) {
            st.pushBack();
          }
        } else if (!('\0' <= st.ttype && st.ttype <= ' ')) {
          st.pushBack();
        }
        System.out.println("Num " + num * Math.pow(10, exp));
        break;
      case StreamTokenizer.TT_WORD:
        System.out.println("Word " + st.sval);
        break;
      case '"':
      case '\'':
        System.out.println("String " + st.sval);
        break;
      default:
        System.out.println("Char '" + (char) st.ttype + "'");
        break;
      } // end switch
    } // end while
  } // end main
} // end class
 

    
  1. (Sect. 7) I'm trying to read in a character from a text file using the DataInputStream's readChar() method. However, when I print it out, I get ?'s.

*Remember that the Java programming language characters are 16-bit Unicode characters, while many hosts systems store characters as 8-bit ASCII characters. Therefore, to read individual characters from a text file, you need to ensure the proper conversion. The proper way to do this is to use an InputStreamReader, which converts from 8 to 16 bit streams:

InputStream fis = new FileInputStream("myfile.txt");
InputStreamReader isr = new InputStreamReader(fis);
char c3 = (char) isr.read();

The less-favored way (because it is not so portable, as the encodings translation is not done) is just to read a byte and cast it into a character:

InputStream fis = new FileInputStream("myfile.txt");
DataInputStream dis = new DataInputStream(fis);
char c1 = (char) dis.readByte();
    
  1. (Sect. 7) How do I delete a directory?

*JDK 1.0 did not support directory removal. JDK 1.1 supports directory removal with the method:

public boolean delete() in class java.io.File

Make sure you don't have any open streams in the directory you're trying to remove. Do a close() on all streams, even if the underlying file is gone.

  1. (Sect. 7) How do I tell how much disk space is free?

*There currently aren't any good APIs for system introspection. There is no Java technology-enabled way to control processes, or look at system resources. You can use Runtime.getRuntime().exec() to do "df" on unix or "dir" on MS-DOS right now. Bug id #4057701 is an RFE for adding this feature.

Alternatively, check out JConfig: http://www.tolstoy.com/samizdat/jconfig.html
JConfig is a cross-platform library that fills in many of the gaps in the core API, and makes it possible to work with files, processes, file types, video monitors, etc. in a much more Microsoft Windows- and Mac-friendly manner.

  1. (Sect. 7) How do I get a directory listing of the root directory C:\ on a PC?

*The obvious approach of calling File.list("C:\"); does not work. There are two reasons why this fails. First, slash is an escape character, so if you want a literal slash, you have to repeat it. Second, you need to give the name of the directory, i.e. dot. Putting this together, either of the following calls will work

File.list("C:\\.");
    

or

File.list("C:/.");
    

Note: a file separator of "/" works just as well as "\" in most Microsoft Windows programs and library calls. It is an artifact of DOS's origin's as a ripped-off port of CP/M.

CP/M didn't have directories, so it didn't use pathname separators. The forward slash "/" was already used for giving options to CP/M commands, so "\" was pressed into service as the DOS pathname separator, but the DOS shell was taught to understood "/" for compatibility with other OS's. See also JConfig in Q6.15.

  1. (Sect. 7) What is the difference between the various ZIP formats: ZIP, GZIP, and PKZIP?

*Zip is an archive file format, popularized on PCs, that contains multiple compressed files.
GZIP comes from Gnu. It is essentially a one file subset of the Zip format. You can't put a whole directory into a GZIP archive, just a single file. It's intended for compressing a tarball of many files.
PKZIP is a set of commercially available programs that create Zip files. All three use the deflate compression format, which is based on the LZ77 algorithm. This compression is also used by the ZLIB library and hence the PNG graphics file format (which uses ZLIB). PNG - Portable Network Graphics - provides a patent-free replacement for GIF and TIFF.

An alternative compression technology, LZW compression, is encumbered by Unisys's patent. LZW is used in GIF files and by the Unix compress command. Luckily, as well as being free from patent restrictions, LZ77 also gives better compression than LZW. LZW is the initial letters of the last names of the three computer scientists who developed the algorithm (Lempel, Ziv, Welch).

The basic classes (all in java.util.zip) that read LZ77 Zip format are Deflater and Inflater. These are used by the stream classes DeflaterOutputStream and InflaterInputStream. The java.util.zip classes GZIPInputStream and ZipInputStream inherit from InflaterInputStream.

PKZIP is a commercial program for DOS, Windows, and OS/2, sold by PKWARE Their FAQ, at http://www.pkware.com/zipgfaq.html, specifically says

"Because PKWARE has dedicated the .ZIP file format to the public domain, it is possible for other people to write programs which can read .ZIP files. NOTE THAT THE PKZIP, PKUNZIP, PKSFX PROGRAMS AND THEIR ASSOCIATED SOURCE CODE AND SUPPORT PROGRAMS ARE THE EXCLUSIVE PROPERTY OF PKWARE INC. AND ARE NOT PUBLIC DOMAIN SOFTWARE PROGRAMS.

The "other people" PKZIP's FAQ refers to is the InfoZIP project, a group of public-minded programmers spread over the world producing free software that works on most ANSI C compilers and platforms. See

http://www.cdrom.com/pub/infozip/.

Jar files are in ZIP format, but are not as complete as a full filesystem archive format since file permissions are not saved. WinZip version 6.2 or later is needed for processing the full PKZIP format. WinZip 7 and 8 are available from http://www.winzip.com.

  1. (Sect. 7) How can I use characters other than ASCII?

*Search for the article titled "Adding Fonts to the Java Runtime" or visit: http://java.sun.com/products/jdk/1.2/docs/guide/internat/fontprop.html

The article explains how to add fonts to Sun's JDK using the font.properties file. [If anyone has summarised the information, please send it in].

  1. (Sect. 7) I did a read from a Buffered stream, and I got fewer bytes than I specified.

*This is the way that BufferedInputStream worked prior to JDK 1.2. The behavior was so unintuitive that it really represented a bug. Javasoft has at last in JDK 1.2 resolved the bug by fixing the behavior to what everyone expects. So this note is really only of historic interest.

When you instantiate a buffered input stream, you can specify the size of buffer it should use. Let's call this the internal buffer. When you call read() you can say how many bytes to read. Let's call this the request. If the request is smaller than the internal buffer and not a multiple of the internal buffer, then the last read returns only the odd bytes left in the internal buffer! The more reasonable and intuitive behavior is for the internal buffer to be refilled, so that the whole request can be granted.

For example, if you create a BufferedInputStream with an internal buffer of 1000 bytes, and try to read 512 byte chunks, your first read will return 512 bytes, but your second read will only return (1000-512), or 488, bytes. (Assuming that the file has at least that many bytes in it). The following code illustrates the former problem.

// troubleshooting by Tov Are Jacobsen  
import java.io.*;
class filebug {
    public static void main(String args[]) 
                  throws FileNotFoundException, IOException  {
    BufferedInputStream bis = 
       new BufferedInputStream( 
       new FileInputStream("test.txt"), 1000 );
    byte[] buf = new byte[2000];
    int numread;
    System.out.println( "Available: "+bis.available() );
    while (true) {
        numread = bis.read(buf,0,512);
        if (numread<0) break;
        System.out.println( "got "+numread
                           +", avail:"+ bis.available());
    }
  }
}
    

Of course, a valid reason for getting less than you asked for is that you asked for more data than is actually available in the Stream, e.g. you requested 512 bytes from a file that only contains 40 bytes. In general, there are no guarantees about how much data is returned for a given buffered input stream read request. To avoid this problem, push a DataInputStream on top of your buffered stream. Then you can call readFully(), which will do what you want.

A similar "got less than I asked for" occurs when reading a socket. Network protocols frequently packetize data and send it across in bursts. Nothing is lost of course, and you are always told how many bytes you actually got. You will get the remaining bytes on a subsequent read. This happens regardless of the language used. Be sure to check the "amount of data returned" when using the read(byte[], int, int) method of BufferedInputStream, or when reading from a socket.

Another problem with java.io.InputStream.read(byte[], int, int) is that it catches and ignores IOExceptions. Instead, these exceptions should be passed on to the caller. Ace programmer Jef Poskanzer, jef@acme.com, has a version to do this at http://www.acme.com/java/software/Acme.Utils.html. See Jef's read() and readFully() routines.

  1. (Sect. 7) How do I redirect the System.err stream to a file?

*You cannot assign a new FileOutputStream to System.err, as it is final. Instead use the System.setErr() library call, like this:

FileOutputStream err = new FileOutputStream("stderr.log");
PrintStream errPrintStream = new PrintStream(err);
System.setErr(errPrintStream);
    

This was introduced with JDK 1.1. There is also a corresponding setIn() for redirecting standard in, and a setOut() for standard out.

Note that you will get a compiler warning about a deprecated construct when you do this. PrintStreams are deprecated in favor of PrintWriters, which handle Unicode properly. The PrintStream is marked as deprecated by marking all its constructors as deprecated. There is no way to create the PrintStream needed to redirect System.err or System.out without triggering the deprecated warning.

  1. (Sect. 7) What are the values for the Unicode encoding schemes?

*If you review the String constructor with this signature

    String(byte[] bytes, String encoding)

you can see that one argument is a value for the encoding scheme that the conversion of 8-bit bytes to 16-bit Unicode chars is to use.

There are three: "Unicode", "UnicodeBig" and "UnicodeLittle". The first one expects the first two bytes of your data to be a Byte Order Mark, FEFF or FFFE, which specifies whether the data is in little-endian or big-endian order. If there isn't a BOM but you already know the endianness, you can use "UnicodeBig" or "UnicodeLittle" directly.

There is also a Sun document at http://java.sun.com/products/jdk/1.1/docs/guide/intl/encoding.doc.html with some related information (not much).

There is another Sun document at http://java.sun.com/products/jdk/1.1/intl/html/intlspec.doc7.html which shows the table of encodings. There is a new system property called "file.encoding" which translates between codes known to the Java programming language like "Cp1252", and locale encoding names like "Windows Western Europe / Latin-1"

  1. (Sect. 7) Is there a way to read a char from the keyboard without having to type carriage-return?

*You can do this in a GUI (e.g. in a text component). There is no pure Java technology way to do character-by-character I/O without using a GUI. Bug id #4075058 has been filed to request this feature.


8. Core Libraries

  1. (Sect. 8) I can't seem to change the value of an Integer object once created.

*Correct. Integer (Float, Double, etc) are intended as an object wrapper for a specific value of a number, not as a general-purpose way of shipping a primitive variable around as an Object. If you need that it's easy enough to create: class General { public int i; }

  1. (Sect. 8) How do I print from a program?

*Use the Toolkit.getPrintJob() method

Component c = this.getParent();
while (c!=null && !(c instanceof Frame))
    c=c.getParent();
// With a JComponent use   c=getTopLevelAncestor();
 

PrintJob pj = getToolkit().getPrintJob((Frame) c, "test", null);
Graphics pg = pj.getGraphics();
printAll(pg);
pg.dispose();
pj.end();
    

This feature was introduced with JDK 1.1. A common place to put this is in the code that handles a button press. Printing from an untrusted applet is subject to a check from the SecurityManager.

The JDK 1.1 printing API is more a screen hardcopy facility than a full blown publishing and illustration hardcopy API. JDK 1.2 offers a more full-featured printing API.

If you simply want to print text, then write it to a file and print the file. Or open a filename that corresponds to the printer. On Microsoft Windows, that is "LPT1" and the code looks like:

try {
    FileOutputStream fos = new FileOutputStream("LPT1");
    PrintStream ps = new PrintStream(fos);
            ps.print("Your string goes here");
            ps.print("\f");
            ps.close();
} catch (Exception e) {
    System.out.println("Exception occurred: " + e);
}
    

The final formfeed is needed by windows to start the printjob.

  1. (Sect. 8) What are the properties that can be used in a PrintJob?

*The properties are

    • awt.print.destination - can be "printer" or "file"
    • awt.print.printer - printer name
    • awt.print.fileName - name of the file to print
    • awt.print.numCopies - obvious
    • awt.print.options - options to pass to the print command
    • awt.print.orientation - can be "portrait" or "landscape"
    • awt.print.paperSize - can be "letter","legal","executive" or "a4"

The defaults are destination=printer, orientation=portrait, paperSize=letter, and numCopies=1.

You can search for info like this by joining the Java Developer Connection (it's free) at http://java.sun.com/jdc/.

and doing a search for "PrintJob".

  1. (Sect. 8) Is there any package to handle HTML?

*Yes. You can render HTML onto a JEditorPane.

  1. (Sect. 8) Why don't Dialogs work the way I want them to?

*Modal dialogs (dialog windows that stay up until you click on them) are buggy in many browsers and in the 1.0.2 JDK. One bug is that the dialog is not necessarily put on top when it is displayed. Most of the modal dialog bugs are fixed in JDK 1.1.

  1. (Sect. 8) Where can I find information about the sun.* classes in the JDK?

*You're not supposed to. Those classes are only to support functions in the java.* hierarchy. They are not part of the API, and won't be present in systems from non-Sun vendors. Some people have reverse-engineered the code and published an API for these classes but you use it at your own risk, and it may change without warning.

Worst of all, those programs will not have the portability of true Java technology-based software but will only run on Sun JDKs. For the same reason you shouldn't use classes outside the java.* packages when using JDKs from other vendors.

If you still insist on going ahead, check these URLs:
http://java.sun.com/products/api-overview/index.html
http://www.parmly.luc.edu/javaudio/
http://www.users.interport.net/~mash/javamidi.html

  1. (Sect. 8) How do you read environment variables from within a program?

*Environment variables are not used as they are not platform-portable. The Mac doesn't have environment variables, for example. A Windows 95 application not started from a DOS window does not have environment variables. Use properties instead. It was a design error in JDK 1.0 that programmers had to set the CLASSPATH environment variable. This should have been set in a property file

Create your own properties file (see java.util.Properties) or specify them with the -D option when you invoke the interpreter or JRE. Additionally, on some systems you can set a property from the command invocation line like this:

java -Dfoo=$foo MyClass (Unix)

or

java -Dfoo=%foo% MyClass (Win95/NT)

This sets the "foo" property to the value of the environment variable foo, and makes it available in the System properties. Make sure you do not leave any spaces after the -D or around the = sign. Inside the program you get the value with:

String env = System.getProperty("foo");

More simply, just put the environment variable on the command line and read it as arg[0].

java MyClass %FOO% ; Win32
    java MyClass $FOO ; Unix
    

Finally, you could execute a Runtime process to get the environment variables if you are on a platform that has them.

import java.io.*;
import java.util.Properties;
 

public class Main {
    public static void main(String[] argv) {
        Properties envVars = new Properties();
 

        try {
          envVars.load(   // use "set" on Windows
                Runtime.getRuntime().exec("/bin/env").getInputStream()); 
        } catch (Throwable t) {t.printStackTrace();}
 

        System.out.println("\n\n" + argv[0] 
                         + " = <" + envVars.get(argv[0]) + ">");
    }
}

This is not a Pure Java approach as it builds platform-specific knowledge into the program. See Question 10.6 for more details. On Unix, the command that prints environment variables is "/usr/bin/env". On Windows95, it is "set"

  1. (Sect. 8) How do I get a program talking to a Microsoft Access database?

*Use the JDBC-ODBC bridge. It is not especially challenging to set up, but it does require painstaking attention to detail.

Note that the Microsoft version of the Java kit does not support JDBC-ODBC access because Microsoft uses a non-standard native code interface.
The JDBC FAQ can be found at http://java.sun.com/products/jdbc/jdbc-frequent.html

  1. (Sect. 8) I can't seem to change the current working directory.

*Correct. This missing functionality was an oversight that is corrected in the JDK 1.3 release. In jdk1.3, you can use this method: exec(String command, String[] envp, File dir) of the Runtime class. It cd's to the dir before running the command, and it adds the environment variables to that environment.

There are several workarounds for jdk 1.2 and earlier.

    • Run your app from a .bat or .sh file and do the "cd" in that (before you run your java app), assuming that all the external processes you need to exec can be run from the same directory.
    • Do: exec("cd /home/wherever; externalApp.exe") on unix, (there doesn't seem to be an equivalent on NT).
    • Instead of running the .exe directly, run (or write on the fly) a .bat or .sh file that does the cd and then runs the .exe for you (this could well create trouble with getting back the correct return status)
  1. (Sect. 8) How do I create a Vector of ints?

*ints are primitive types and hence can't be stored by the Vector class, which stores objects. You'll need to wrap the ints. Try this:

int i =7;
Vector holdsInts = new Vector(5,1);
 

holdsInts.addElement(new Integer(i));
int j = ((Integer)holdsInts.elementAt(0)).intValue();
    
  1. (Sect. 8) I have several worker threads. I want my main thread to wait for any of them to complete, and take action as soon as any of them completes. I don't know which will complete soonest, so I can't just call Thread.join on that one. How do I do it?

*You need to use the wait/notify mechanism to allow any of the worker threads to wake up your main thread when the worker has completed.

  1. (Sect. 8) How do I get random numbers?

*If you just need a quick random double between 0.0 and just less than 1.0

double myrandom = Math.random(); // [0,1)
    

The notation "[0,1)" is common math notation for "zero to .9999999 etc". However, due to the inherent inaccuracies of floating point arithmetic, multiplying N by 0.999999 etc can result in an answer of N, not N * .999999. So watch out when N is big.

JDK 1.2 adds another version of nextInt that accepts a parameter for returning random numbers within a particular range.

Where things get trickier is when you use JDK 1.1 and want an int in a certain range, say 1 to 6 to simulate the throw of a die or 1 to 52 to represent a playing card. Class Random has a nextInt method that will return any integer:

import java.util.Random;
Random r = new Random();
int i = r.nextInt();
    

However, that has an (almost) 50% chance of being negative, and it doesn't come from the right range. So you just take the abs() value and then mod it into the right range:

int dice_throw = 1 + Math.abs(i) % 6;
    

Except, the abs() method fails gracelessly in the presence of the Integer.MIN_VALUE (it returns the same, negative, result!). So it is better to AND to get the non-negative value: In general, to get a random int between high and low limits (inclusive):

java.util.Random r = new java.util.Random();
int j = (r.nextInt() & Integer.MAX_VALUE) % (high-low+1) + low;
    

The sentence above states "(almost) 50% chance" because there is one more value in the negative integers than in the positive integers in two's complement arithmetic as used by Java. For most purposes, the bias introduced will be insignificant, but we "and" the nextInt() to convert it to zero. Sure, it's unlikely to occur, but you don't want the reactor going critical just because you missed this case while testing.

A worse problem is that with the algorithm used, the low order bits are significantly less random than the higher order bits. And the low order bits are precisely the ones you get when you do a (mod 2^n) operation. You may consider using java.security.SecureRandom which provides much better randomness by using a Cryptographic hash, although it is much more expensive to compute.

  1. (Sect. 8) What does "deprecated" mean? I got this in a compiler error message.

*The compiler will flag a now-obsolete API as "deprecated". The word means "officially disapproved of". Compile again with the "-deprecation" option to see what is deprecated. In almost all cases, the old API has been replaced by a new one. Update your code to use the new one.

An example of using a deprecated API is calling component.size(). That has been replaced by component.getSize().

  1. (Sect. 8) Where/why should I use the Iterator interface?

*It's a very convenient way to step through some of the Collections data structures, such as HashSets, and Maps. It is thread safe. If you're looking at an element in one thread while another thread is trying to delete it, it won't half vanish. Note: enumerations have now been replaced by Iterators, introduced with the Collections of JDK 1.2. Use Iterators instead of Enumerators.

Here's how you might look at every element in a HashSet

import java.util.*;
...
HashSet h = ...
... /* fill the HashSet with some elements */
Iterator i = h.iterator();
while (i.hasNext() ) {
    ... do something with next element, i.next() ...
}
    

You should look for opportunities in your own data structures to implement Iterator where the structure has a sequence of elements.

  1. (Sect. 8) Which version of WinZip is compatible with java.util.zip?

*You need WinZip version 6.2 or later. Version 6.1 or earlier is not good enough. WinZip can be downloaded from http://www.winzip.com/download.cgi. The pkzip software works fine. Infozip is better than WinZip because it lacks the winzip "feature" of failing to recreate directories unless given a special option. Use Infozip.

  1. (Sect. 8) How can I access other fonts on my system?

*You do it by editing the fontnames in the font.properties file in the lib directory of your JDK release. Watch out for program portability when you do this.

For more details, check the website http://www.alumni.caltech.edu/~dank/javafont.htm and the JavaSoft site at http://java.sun.com/products/jdk/1.1/docs/guide/intl/fontprop.html They have lots of information on this.

  1. (Sect. 8) How can I trap Control-C?

*There are two ways to use control c.

    • On Unix, a Control-C is used to interrupt a running program. The control-C is typed in the xterm window in which you started the program. The Control-C is recognized by the OS, which converts it to a SIGINT and sends it to the program. By default, (i.e. unless you registered a different signal handler) the program will terminate.
    • In a GUI under Microsoft Windows, a Control-C is used as an "accelerator key" to access an entry on a menu. There are several such accelerators which can be typed by various control-keys.

In a GUI a KeyPressedListener will see a control-C as java.awt.event.KeyEvent[KEY_PRESSED,keyCode=67,modifiers=Ctrl] Here is the code:

import java.awt.*;
import java.awt.event.*;
public class KeyTestAWT extends Frame 
                     implements KeyListener {
   public KeyTestAWT() {
      TextArea ta = new TextArea();
      ta.addKeyListener(this);
      add( ta );
      pack();
      setVisible(true);
   }
 

   public void keyPressed( KeyEvent ev ) { 
      if( ev.getKeyCode() == KeyEvent.VK_C && ev.isControlDown() )
         System.out.println("Ctrl-C detected!");
   }
   public void keyReleased(KeyEvent ev ) { }
   public void keyTyped(   KeyEvent ev ) { }
 

   public static void main(String[] args) {
      new KeyTestAWT();
   }
}

But platform differences may crop up. Some OS's use a KeyMap that binds all the accelerator keys including Ctrl-C, so they appear "not to work."

On Win32 in a command line app you can't read a control-C in Java because it is sent to the process as a signal (as with Unix).
Instead of interposing a signal handler thru JNI, you could also launch java from perl or a shell script which is capable of trapping the signal. Alternatively, use javaw to launch the JVM so that it has no keyboard which can ctrl-C it.

From JDK 1.3 on, on all platforms, you can use the new method Runtime.addShutdownHook() to run clean up code at program termination time. The new method can be used to service a Ctrl-C, sent on Unix or in a non-GUI Windows application.

  1. (Sect. 8) How do you parse commandline arguments to a Java program?

*Perhaps surprisingly, commandline arguments are not encouraged, as they cause a program not to meet 100% pure Java certification standards. The reason is that some systems like MacOS don't normally have a command line or command-line arguments. Consider using properties instead so that your programs fit more naturally into the environment.

If you must use command-line arguments, have them comply with the POSIX conventions, i.e. they should

    • use a "-" instead of a "/"
    • be case sensitive, and
    • be concatenatable (-pst == -p-s-t).

See http://java.sun.com/docs/books/tutorial/essential/attributes/_posix.html

If such arguments are used, it should NOT be up to the invocating application (ie java.exe) to properly parse them. According to the getopts routine from gnu, getopts is required to know exactly what the usable parameters are before it can properly parse them and create argc/argv.

Because of that, it becomes unduly hard for calling programs such as java.exe to properly parse class arguments by themselves. Instead, they should create an argc/argv pair (actually a java specific array dependant on the way in which the method is called) where the number of elements equals the number of text words in the options. Text word means a group of ascii characters outside of quotation marks, not separated by white space. Once these text words are passed to the class, it is up to the class to actually parse them correctly.

The text words passed to the class can be parsed however the class author wishes. It is up to the author to correctly parse the options. There are several implementations of getopts which perform such parsing, in C, Perl, and the Java programming language. You will find one at http://www.urbanophile.com/arenn/hacking/download.html#getopt

  1. (Sect. 8) How many threads can I create?

*By default, on a Win32 machine, each ("native") thread gets one MB (1024*1024 bytes) of stack space reserved for it. The memory is not actually allocated. If it were, you'd run out of memory with dozens of threads instead of hundreds. The space needs to be reserved as a contiguous block of memory so the stack can grow as needed.

Under Win32, the max amount of memory is 2GB, which corresponds to 2,000 threads each reserving 1MB of memory. That's an upper bound; in practice you'd run out of other OS resources before running out of memory. Each thread has some system resources that will be used to manage the thread -- register storage area, thread-local storage, state information, exception condition info, etc.

You should design your programs so that you use threads only where necessary. It's almost always a mistake to have one thread per object. Successful programs are much more likely to have 5 threads (or fewer) than 500.

  1. (Sect. 8) What resolution timing can I get with Java?

*Standard Java just uses the system time of day clock. The resolution of this varies. On NT machines it is either 10ms or ~15ms. Under Microsoft Windows, it is 55 ms.

When you use the Java Media Framework standard extension, you can access (it is believed) a timer with a 1 msec resolution. See javax.media.TimeBase.

If you write JNI code, you can access whatever underlying timers the native OS provides. For example, Pentium processors have a clock count register that is incremented every clock cycle.


9. Dates and Times

Credit to Paul Hill who completely rewrote this section, and to the programmers at IBM who implemented much of the Java Date code, and reviewed this section of the FAQ for accuracy.

java.util.Date

  1. (Sect. 9) Is the Java programming language "Year 2000"-compliant?

*See http://www.sun.com/y2000/jumppage-temp/jdk.html

JDK 1.1.8_09a is Y2K compliant, as well as 1.1.7_08a. The two Java2 SDKs that have been certified are 1.2.1_03a & 1.2.1_04.

The Date class, as you can see from the discussion, contains more than enough resolution to represent dates in this century and the next and the last. The SimpleDateFormat when parsing a 2 digit year could cause problems; see discussion below.

  1. (Sect. 9) What happen to java.util.Date between JDK 1.0 and JDK 1.1?

*In JDK 1.1 the java.util.Date class was split to provide better support for timezones, and internationalization. 

The classes specifically related to dates are summarized below:

1.      The class Date represents a specific instant in time, with millisecond precision.

2.      The class TimeZone is an abstract class that represents a time zone offset, and also figures out daylight savings time adjustment.

3.      The class SimpleTimeZone is the only concrete subclass of TimeZone in the JDK.  It is what defines an ordinary timezone with a simple daylight savings and daylight savings time period.

4.      The class Calendar is an abstract class for converting between a Date object and a set of integer fields such as year, month, day, and hour.

5.      The class GregorianCalendar is the only concrete subclass of Calendar in the JDK. It does the Date-to-fields conversions for the calendar system in common use.

6.      The class DateFormat is an abstract class that lets you convert a Date to a printable string with fields in the way you want (e.g. dd/mm/yy or dd.MMM.yyyy).

7.      The class SimpleDateFormat is the only concrete subclass of DateFormat in the JDK. It takes a format string and either parses a string to produce a date or takes  a date and produces a string.

At least one critic has used the term "baroque" when describing the complexities of the Java date related classes, but other critics would spell that "broke". The good news is that as of JDK 1.2 all of the common problems have been corrected and many of the bugs were corrected in 1.1.4 and 1.1.6. Even in 1.1.1, you can avoid most of the most annoying bugs by always keeping in mind which timezone each class is using.

  1. (Sect. 9) Exactly what is a java.util.Date?

*A java.util.Date stores a moment in time as a long integer representing the number of milliseconds since 00:00:00 Jan 1, 1970 UTC (Coordinated Universal Time). This zero moment is known as the "Epoch". This is the same Epoch as is used on Unix systems. Dates earlier than the Epoch are represented as negative numbers, counting away from 1/1/1970.

The scheme is sufficient to represent dates from 292,269,053 B.C. to 292,272,993 A.D. (64 bits covers -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807 milliseconds. But note that prior to JDK 1.2, a GregorianCalendar will not accept values earlier than 4713 B.C.

A java.util.Date is the light-weight object intended to just hold a millisecond value. It is used to hold, communicate and store a moment in time. Other tasks like creating a formated string, or calculating dates are best done using other classes.
 

  1. (Sect. 9) Does a java.util.Date really represent the true UTC?

*No, but it is close enough for most human time-keeping purposes. On most computers, it only represents the time since the epoch as converted from the value on the underlying hardware. If you have hardware that is synchronized with an atomic clock your time is UTC; most hardware assumes a day is 24 hours long, but there have been more than 20 leap seconds added to UTC, since the first one was added in 1972.
 

  1. (Sect. 9) How do I create a Date object that represents the current time?

*The default value of a date object is the current time, so the following code creates a date object that contains the current time.

Date now = new Date();
  1. (Sect. 9) I want to create a string that represents a date in a format other than what is returned by java.util.Date.toString() do I have to use a Calendar?

*No. Instead of creating a Calendar and pulling out all of the appropriate fields and making a string, you could use SimpleDateFormat.format() to create a string.
 

  1. (Sect. 9) Why are all the methods in java.util.Date deprecated?

*Mostly because the original java.util.Date was not completely aware of the timezone and "not amenable to internationalization". To make it timezone aware and internationalizable would have required adding some of the functionality which can now be seen in java.util.Calendar and some of the functionality in java.util.DateFormat. If you find the combination all of the date related classes complex, just be glad they were separated into different classes.
 

  1. (Sect. 9) I really don't need a internationalizable, timezone aware, extra flexible formating set of date classes. Is there anything else I can use that stores only a date, and allows me to do some date calculations?

*You could consider using the BigDate class written by Roedy Green, and available in his very informative glossary (search for BigDate). If you want to store the result in a database as a Date or TimeStamp, you should read the section below on java.sql.Date.
 

  1. (Sect. 9) Since the Date( String ) constructor is deprecated what do I use instead?

*The best choice is to use SimpleDateFormat.parse() to create a java.util.Date object.

The Date constructor that accepts a string calls Date.parse( String ). The Date.parse() function had its own rules for converting 2 digit years (it used a 1980 pivot date) and other limitiations which makes it of limited value. Other "features" of Date.parse() that are not supported in SimpleDate have not been missed by many developers.
 

  1. (Sect. 9) Since Date(int year, int month, int date) and related constructors are deprecated what do I use instead?

*The constructor GregorianCalendar(int year, int month, int date) is the newer replacement. Other choices are the Calendar.set( year, month, day ) method. Note that the year in the GregorianCalendar starts at 1 A.D., not at 1901 like the old Date constructor.
 

java.util.TimeZone

  1. (Sect. 9) How can I see if my JVM is using the right timezone?

*The following codes displays the ID of the current default timezone.

  System.out.println( TimeZone.getDefault().getID() );
  1. (Sect. 9) The value of TimeZone.getDefault is not what I expected. What is the problem?

*The value of the default timezone is based on the value of the system property "user.timezone". The JVM  is supposed to set this value. In releases such as JDK 1.1 the value of user.timezone was often not set to anything, so TimeZone.getDefault() used its own built in "fallback" value (the default when there is no default value). In later JDK 1.1 releases and in JDK 1.2 the setting of the value of user.timezone is much better and the "fallback" value is now GMT (Greenwich Mean Time). Up until JDK 1.1.3, the fallback value was "PST" (North American Pacific Timezone).
 

  1. (Sect. 9) Do all the standard objects use the same default timezone?

*Not until JDK 1.2. In JDK 1.1, Date.toString() and Calendar used the value of TimeZone.getDefault() which could often be undefined (see the previous question). In JDK 1.1, The Calendar in a SimpleDateFormat was set to the 1st timezone resource for the locale (for the US this is PST).

System.out.println( "TZ default = " + TimeZone.getDefault().getID() );
sdf = DateFormat.getDateTimeInstance( DateFormat.LONG, DateFormat.LONG );
System.out.println( "Date format TZ = " + sdf.getTimeZone().getID() );
Calendar cal = Calendar.getInstance();
System.out.println( "Calendar TZ = " + cal.getTimeZone().getID() );

When run on a system running JDK 1.1.6, NOT in the North American Pacific Time nor in the GMT timezone results in:

Timezone default = GMT
Date format TZ = PST
Calendar TZ = GMT

This example shows two bugs, the value of user.timezone is undefined, so its defaulting to GMT (see discussion of TimeZone.getDefault()) and it shows that the DateFormat depends on the 1st locale entry which in this case is PST.

If you don't want the DateFormat to use the Locale timezone, see the code provided below.

  1. (Sect. 9) If I explicitly set the default timezone, don't I need code to choose between (a) the daylight savings version or (b) the standard version of a timezone?

*No. The ID that you use to select a timezone with TimeZone.getTimeZone refers to a predefined timezone that contains daylight savings information (when applicable). For example, the following code selects the timezone used in New York, USA.

// Get the North American Eastern Time definition.
TimeZone theTz = TimeZone.getTimeZone( "EST" );
// get a really detailed date format and set it to the right timezone
DateFormat df = DateFormat.getDateTimeInstance( DateFormat.LONG,
DateFormat.LONG );
df.setTimeZone( theTz );
// create a date in the locale's calendar, set its timezone and hour.
Calendar day = Calendar.getInstance();
day.setTimeZone( theTz );
day.set( 1998, Calendar.FEBRUARY, 1 );
day.set( Calendar.HOUR, 12 );
 

// print that date/time and 
// that date/time 150 full days of milliseconds later.
System.out.println( df.format( day.getTime() ) );
System.out.println( df.format(
new Date( day.getTime().getTime() +    // get the millis
        150L*24*60*60*1000L ) ) );     // add exactly 150 days of millis

Results in:

February 1, 1998 12:00:00 PM EST
July 1, 1998 1:00:00 PM EDT

Notice that this example selected something refered to as "EST", but that this TimeZone was aware of the daylight savings time change and either printed as "EST" or "EDT".

The confusion is reduced in JDK 1.2, you can use longer TimeZone IDs each maps to its own set of text resources. For example the following IDs are 5 hour West of GMT and have various DST rules: "America/Nassau", "America/Montreal", "America/Havana", "America/Port-au-Prince", "America/Grand_Turk", "America/New_York" and "EST".

You can look at a list of other timezone names and offsets in the file $JAVAHOME/src/java/util/TimeZone.java

  1. (Sect. 9) How do I create my own Time Zone to apply to dates?

*You can create a TimeZone object with the GMT offset of your choice. The following code creates British Time, a timezone that was not defined in 1.1.

britTime = new SimpleTimeZone(0*ONE_HOUR, "Europe/London" /*GMT/BST*/,
    Calendar.MARCH,  -1, Calendar.SUNDAY /*DOW_IN_DOM*/, 1*ONE_HOUR,
    Calendar.OCTOBER,-1, Calendar.SUNDAY /*DOW_IN_DOM*/, 1*ONE_HOUR,
1*ONE_HOUR),
 

TimeZone.setDefault( britTime );

Or you can then apply that TimeZone to a particular Calendar object like so:

Calendar myCal = Calendar.getInstance();
myCal.setTimeZone( britTime );

If you are running 1.2, You can choose this existing timezone as the default with the code:

TimeZone.setDefault( TimeZone.getTimeZone( "Europe/London" ) );

Note that BST is defined from JDK 1.1 and later, but it is Bangladesh Standard Time. For a longer example of creating and testing the British timezone, Tony Dahlman provides a nice example in his BSumTime.java code.

  1. (Sect. 9) How do I create the BST timezone specifically?

*You can create an arbitrary TimeZone object with the code below. In most or all other timezones, daylight savings time is handled automatically and internally. But GMT is the reference for all other timezones, and so does not have the summertime update applied automatically. The rules for BST can be found at http://www.rog.nmm.ac.uk/leaflets/summer/summer.html

Here is the code to create a British Summer Time timezone that is offset one hour from GMT between two dates:

import java.util.*;
import java.text.*;
// create a BST timezone (code courtesy of Tony Dahlman).
 

public static GregorianCalendar setBritSummTime(String zoneName){
   // Set up the default GMT0BST time zone 
   SimpleTimeZone bst_tz =
      new SimpleTimeZone( 0,   // no offset from GMT
                   zoneName,   // individualized tz id
    // last Sun Mar 1AM
    Calendar.MARCH,-1,Calendar.SUNDAY,1*60*60*1000,  
    // last Sun Oct 2AM
    Calendar.OCTOBER,-1,Calendar.SUNDAY,2*60*60*1000 
                   );
   SimpleTimeZone.setDefault(bst_tz);
 

   // Apply TimeZone to create a Calendar object for UK locale
   return (new GregorianCalendar(bst_tz,Locale.UK) );
}
    

and here is how you would print out values using BST:

// create a template for printing the date
DateFormat df = DateFormat.getTimeInstance(
                   DateFormat.LONG,Locale.UK);
 

// tell the template to use BST tz.
df.setTimeZone(TimeZone.getDefault());
System.out.println("Using British Summer Time "
                  +"the time is: "
                  + df.format( BritishSummerTime.getTime() ) );
 

// Now get and compare with current time in GMT
df.setTimeZone(TimeZone.getTimeZone("GMT") );
System.out.println("\nCurrent time in GMT is: "
                  + df.format(BritishSummerTime.getTime() ) );
    

In the winter, this BST zone is aligned with GMT; in the summer it is one hour later (4 a.m. GMT is 5 a.m. BST).

You can look at a list of timezone names and offsets in the file $JAVAHOME/src/java/util/TimeZone.java

java.util.Calendar and java.util.GregorianCalendar

  1. (Sect. 9)How do I a create a specific date in the Gregorian Calendar?

*If you have a Date use:

myCal.setTime( myDate );

If you have a set of integers representing the year, month and day of month use:

Calendar myCal = Calendar.getInstance();
myCal.set( 1998, Calendar.MARCH, 15 );

Note: Months start with January = 0!
 

  1. (Sect. 9) How do I use a GregorianCalendar to extract a few fields from a Date?

*The following code shows how to get some fields from a Date.

Calendar g = Calendar.getInstance();
g.setTime( aDate );
int year = g.get( Calendar.YEAR );
int mon = g.get( Calendar.MONTH );
int date = g.get( Calendar.DATE );
mon++;             // in class Calendar & GregCal, months run 0-11 ;-(
System.out.println( mon + "/" + date + "/" + year);

If you want to build a string that has a formated date consider using SimpleDateFormat.format().
 

  1. (Sect. 9) Some people use Calendar.getInstance() while others use new GregorianCalendar(). Which one is the correct way to get a Calendar?

*Either way is correct, it depends on what you want to be able to do. You should use Calendar.getInstance(), if you want your code to be ready when the loading of other Calendars are added to the JDK and some other calendar is the default for the locale. A particular locale might have configured a Hebrew or Islamic Calendar as the default calendar and you might want a user to enter a date in his own Calendar, i.e. 1-Jan-2000 (Gregorian) = 23-Tevet-576 (Hebrew) = 24-Ramadan-1420 (Islamic). If you really are trying to place a particular Gregorian date, i.e. 4-July-1776, into a Date object, you might as well create a GregorianCalendar directly.

  1. (Sect. 9) I changed a field using Calendar.set() and then I checked another field. Its value is inconsistent with the value I just set. What is going on?

*In JDK 1.1.0 the Calendar class did not update all of its fields until you called getTime to retrieve the Date that corresponds to the fields in the Calendar. To get the earlier version of the Calendar to "turn the crank" and calculate all fields you can use the trick:

myCal.setTime( myCal.getTime() )     // pull the date out and put it back
in.
  1. (Sect. 9) When I create the date July 4th, 1776 using new GregorianCalendar( 1776, 7, 4 ) the month is off by one. What is the problem?

*You need to be aware that months start with January equal to 0. A better way to create that date would be:

independanceDayUSA = new GregorianCalendar( 1776, Calendar.JULY, 4 );
  1. (Sect. 9)Why aren't there constants for milliseconds per day, week or year?

*The short answer is: these values are not constants. While some date calculations would find these useful, it is important to remember that in areas with daylight savings time rules, there are two days per year that are not 24 hours long, therefore not all weeks are the same length (2 out of 52). Also, because of leap years, not all years are the same length.

If you adding values to a calendar consider using either add or roll; for example:

myCal.add(Calendar.YEAR, 1 );  // get a value 1 year later.
  1. (Sect. 9) By my count the week of the Year is off by one. What is the problem?

*The GregorianCalendar class uses the value set by setMinimalDaysInFirstWeek() to determine if the fractional week at the beginning of the year should be week 1 or week 0. If you don't change it, any fractional week could be week 1, depending on the value defined for the locale.

  1. (Sect. 9) What timezone does a calendar use when I don't explicitly set one?

*The Calendar uses the TimeZone.getDefault() (see discussion under TimeZone).
 

  1. (Sect. 9) Should I stop using Date all together and just use Calendar?

*Probably not. The Calendar class is a much larger than a Date object. Many other interfaces in standard APIs are defined using a Date object. Use Date objects to hold, store or communicate a date-time value. Use a Calendar object to manipulate a date-time value.
 

  1. (Sect. 9) The GregorianCalendar will not accept a date prior to 4713 B.C. Why?

*January 1, 4713 B.C. is the "epoch" date for the Julian Day calendar which was invented in the 16th century by the Joseph Justus Scaliger. "[T]he Julian day calendar, ... does not use individual years at all, but a cycle of 7980 astronomical years that counts a day at a time, with no fractional days, no mean year, and no leap years. He came up with his number by multiplying three chronological cycles: an 18-year solar cycle, a 19-year lunar cycle, and the 15-year indication period used by Romans. All three cycles began together at the same moment at the start of the "Julian cycle. ... [This] Calendar lives on among astronomers."
-- David Ewing Duncan, "Calendar", Avon Books, 1998; p 207

Note that the Julian Day calendar is not the same as the Julian calendar. The Julian Calendar is named for Julius Caesar. The Julian Calendar was used in the Europe from what we now call January 1, 45 B.C. until at least October 4, 1582 and is still used today by the Eastern Orthodox Church to date holidays.

The limitation on dates prior to 4713 BC has been dropped in JDK 1.2.
 

  1. (Sect. 9) The Calendar class is said not to handle certain historical changes. Can you explain some of the limitations?

*The date of change from the Julian to the Gregorian calendar depends on where you lived at the time. The date can vary from 1582 (most Catholic countries, which of course followed the Papal edict) to 1949 (China). The date of the cutover from using the Julian Calendar (leap years ever 4 years) to using the Gregorian Calendar (every 4 years, except every 100 unless divisable by 400) is controlled by the method GregorianCalendar.setGregorianChange(Date).

It is also the case that January 1 was not always the beginning of the year. January 1 was standardized by Julius Caesar in 45 B.C. and Pope Gregory XIII in 1582, but others who used the Julian Calendar between those dates used other dates for New Years Day. (Anyone who has ever been involved in a standardization effort may find it interesting that neither an emperor nor a pope could actually complete the standardization effort).

The Calendar class uses a TimeZone which does not handle historical changes, i.e. the SimpleTimeZone contains only two dates the "spring forward" and "fall back" dates and a date that the DST starts (see SimpleTimeZone.setStartYear() ). If the local definitions have changed then a date/time may not accurately reflect the historical local time.

As noted above, the Date object does not usually include leap seconds, unless your hardware includes leap seconds.

While the Calendar class is more than useful for international business, it may not be what you want for doing UTC timebased calculations or historical dates and times without a more careful analysis of its design limits.

java.text.DateFormat and java.text.SimpleDateFormat

  1. (Sect. 9) How do I convert a date in one format to another?

*The following code illustrates the technique:

import java.text.*;
public class DateTest {
  public static void main( String[] args ) {
    SimpleDateFormat df1 = 
      new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.S");
    SimpleDateFormat df2 = 
      new SimpleDateFormat("dd-MMM-yy");
    String startdatetime = "1998-09-09 06:51:27.0";
 

    try { 
      System.out.println("Date is " + 
        df2.format( df1.parse(startdatetime) )); 
    } catch (ParseException pe) { 
      System.out.println("ParseException " + pe ); 
    }
  }
}

When run, the program outputs "Date is 09-Sep-98"

  1. (Sect. 9) How do I use DateFormat to parse a string containing a date?

*The easiest way to parse a date that is in a known format is to use SimpleDateFormat.parse().

DateFormat df = new SimpleDateFormat( "HH:mm" );
df.setTimeZone( TimeZone.getDefault() ); // if using JDK 1.1 libraries.
df.setLenient( false );                  // to not allow 26:65 etc.
Date lateLunchOnDayZero = df.parse( "12:30" ); 
System.out.println( lateLunchOnDayZero );

The above code would result in (when in the MST timezone).

Thu Jan 01 12:30:00 MST 1970

To parse other date and time fields, refer to the SimpleDateFormat documentation.

  1. (Sect. 9) How do I use a DateFormat to create a text string from a Date?

*The easiest way to create a string from a date is to use a SimpleDateFormat.format(). The following code illustrates how this can be done.

DateFormat df = new SimpleDateFormat( "yyyy.MMM.dd HH:mm:ss.SSS z" );
df.setTimeZone( TimeZone.getDefault() ); // JDK 1.1
System.out.println( df.format( d ) );    // where d is a Date

For other possible fields from the calendar, see the document for SimpleDateFormat.
 

  1. (Sect. 9) What timezone does a SimpleDateFormat use when I don't specify one?

*In JDK 1.1, the SimpleDateFormat uses the first timezone defined for the locale. In JDK 1.2, it uses the default timezone. See the discussion above on how this differs from the Calendar class).

  1. (Sect. 9) I'm not yet using JDK 1.2 and I don't want the DateFormat to use the 1st timezone for the locale. How do I change the timezone in a SimpleDateFormat to use a different timezone?

*The following code sets the timezone of a DateFormat to the current default.

DateFormat df = DateFormat.getDateInstance();
df.setTimeZone(TimeZone.getDefault());

or to set it to a timezone of your choice.

df.setTimeZone(TimeZone.getTimeZone( "MST" ) ) // Mtn Time, Denver USA
  1. (Sect. 9) What century is assumed when I use a two digit year in a SimpleDateFormat string?

*In JDK 1.1, the default start for the century used by SimpleDateFormat for 2 digit years is 80 years before the current date.
This means that in 1998: 1 = 2001, 2 = 2002, ... 17 = 2017, 18 = 2018, 19 = 1919, 20 = 1920, ... 98 = 1998, 99 = 1999,

In JDK 1.2 you can change this "default century start date" with the method set2DigitYearStart( Date) and get its current value
with the method get2DigitYearStart(). One thing to note is that since set2DigitYearStart takes a date not a year, you can have your default century begin at any day or hour.

When running under JDK 1.1, it is probably best to avoid two-digit year fields, when the dates entered could possibly fall outside of the range -- now less 80 years and now plus 20 years. If you want to allow two-digit year fields in JDK 1.2 and beyond, consider setting the 2DigitYearStart property to something appropriate,  For example, set it to today, when all dates to be entered are in the future (i.e. an expiration date), or set it to today less 100 years, when the value is always in the past (i.e. birthdate, death date).
 

  1. (Sect. 9) Does the above mentioned limitation of 2 digit years in JDK 1.1 mean that java.text.SimpleDateFormat is not Y2K compliant?

*No. It means that any code you write that (1) allows the entry of 2 digit years and (2) does not make sure they are in an appropriate century, would not pass a careful Y2K analysis. This code was put here so you could sensibly read old files with non-Y2K compliant dates, not so you could create new ones. Once you are using JDK 1.2 it is better to set the 2DigitYearStart property to something appropriate for any two-digit year field which you are parsing.

java.sql.Date and java.sql.TimeStamp

  1. (Sect. 9) What timezone does a java.sql.date use when converting to an SQL DATE?

*This is another hidden use of the default java.util.TimeZone. If you have carefully set every timezone in every Calendar and DateFormat you are using, but you don't set the default in java.util.TimeZone when a java.util.Date is converted to a java.sql.Date you may not end up with the value you expected in your database.
 

  1. (Sect. 9) When I print a java.sql.Timestamp it doesn't include any milliseconds. What is the problem?

*If you print the java.sql.Timestamp directly you will see this problem. The following code demonstrates this surprising behavior.

// incorrect use of java.sql.Timestamp
DateFormat df = new SimpleDateFormat( "MM/dd/yy hh:mm:ss.SSS a" );
df.setTimeZone( TimeZone.getDefault() );    // needed in JDK 1.1
 

java.sql.Timestamp t = new java.sql.Timestamp( 94, Calendar.JANUARY, 1,
        13, 45, 59, 987654321 );
System.out.println( df.format( t ) ) ; // Wrong! no fractions of a second.

The results of the above code are:

01/01/94 01:45:59.000 PM

The above code is using whatever is in the super class (java.util.Date) and assumes all of those parts are filled in. java.sql.Timestamp could have stored the whole milliseconds in the millisecond part of a java.util.Date, and stored the nanoseconds that are not whole milliseconds in an additional field. They chose to ignore the fractions of a second in the java.util.Date and put all fractional parts in an additional nanosecond field.

The following code shows how to convert a java.sql.timestamp to a java.util.Date.

Date d = new Date(t.getTime() + (t.getNanos() / 1000000 )); 
// 1 Milli = 1x10^6 Nanos
System.out.println( df.format( d ) ) ; // Right! At least we have the millis

The result of the above code is a better approximation of the timestamp value:

01/01/94 01:45:59.987 PM
  1. (Sect. 9) How do I calculate the number of days between two dates?

*There is no API for this (there should be), but you can calculate it by hand like this:

 

    static final long ONE_HOUR = 60 * 60 * 1000L;

 

    Calendar earlierDate = new GregorianCalendar();

    Calendar laterDate = new GregorianCalendar();

    

    earlierDate.set(1997, 1, 5, 0, 0, 0);    // FEB!! 05, 1997

    laterDate.set(1998, 1, 5, 0, 0, 0);      // Feb 05, 1998

 

    // the first getTime() returns a Date, the second takes 

    // that Date object and returns millisecs since 1/1/70. 

    // The API has misleading and horrible naming here, sorry.

    long duration = laterDate.getTime().getTime() -

                              earlierDate.getTime().getTime();

 

    // Add one hour in case the duration includes a 

    // 23 hour Daylight Savings spring forward day.

    long nDays = ( duration + ONE_HOUR ) / (24 * ONE_HOUR);

    System.out.println("difference in days: " + nDays); 

    

Note: this method works only if the two times are both created to be exactly midnight. Otherwise you might end up finding that for example, 11 PM tonight is 0 days away from 6 AM tomorrow, instead of 1 day as many applications expect. This is because 24 hours haven't elapsed between 11pm on one day and 6am on the next.

Or, use int julian = myCalendar.get(Calendar.DAY_OF_YEAR); and subtract, making sure to subtract the years too. Alternatively, use BigDate at http://mindprod.com/.

For the ultimate in generality, you could get ACM's Collected Algorithm 199, recode it in Java (takes about 30 minutes), compute the Julian date for each end point, and subtract the two numbers. Here is the code in Java to get the GMT Julian day number and a "local Julian Day" that leverages the existing algorithms in the GregorianCalendar.

import java.util.*;
import java.text.*;
 

/**
 * This Calendar provides Julian Day and "Calendar Day" methods,
 * The Calendar Day starts at _local_ midnight.
 * 
 * @author Paul A. Hill
 * @version 1.1
 * @since JDK 1.1.7 3/99
 * @see java.util.Calendar
 */
public class FAQCalendar extends GregorianCalendar implements Cloneable {    
    /**
     ** this constant and the ones that follow are actually private
     ** in the GregorianCalendar, so we'll redefine them here.
     **/
    public static final long
        ONE_SECOND  = 1000,
        ONE_MINUTE  = ONE_SECOND * 60,
        ONE_HOUR    = ONE_MINUTE * 60;
    /**
     * this next constant and the others with it have their uses,
     * but watch out for DST days and the weeks that contain them.
     * Note also that 1/1/1970 doesn't start on the first day of the week.
     */
    protected static final long
        ONE_DAY     = ONE_HOUR * 24,
        ONE_WEEK    = ONE_DAY  * 7;
        
    /** The number of days from Jan 1, 4713 BC (Proleptic Julian)
     ** to 1/1/1970 AD (Gregorian).  1/1/1970 is time 0 for a java.util.Date.
     **/
    public static final long JULIAN_DAY_OFFSET = 2440588L;
        
    /**
     * Same as GregorianCalendar(). Creates a calendar with the time set to 
     * the moment it was created.
     * 

Note: for Brevety I have not provided all of the other

     * constructors that you can find in GregorianCalendar.

     *

     * @see java.util.GregorianCalendar#GregorianCalendar

     */

    public FAQCalendar() {

        super();

    }

       

    /**

     * A calendar day as defined here, is like the Julian Day but it starts

     * and ends at _local_ 12 midnight, as defined by the timezone which is

     * attached to this calendar.  This value is useful for comparing

     * any date in the calendar to any other date to determine how many days

     * between them, i.e. tomorrow - today = 1

     *

     * @return the calendar day (see above).

     * @see #getCalendarDay

     */

    public long getCalendarDay() {

        TimeZone tz = getTimeZone();

        // Figure the exact offset for the exact time of day.

        int offset = tz.getOffset( get( ERA ), get( YEAR ),

                get( MONTH ), get( DAY_OF_MONTH ), get( DAY_OF_WEEK ),

                    (int)((long)get( HOUR_OF_DAY ) * ONE_HOUR +

                    get( MINUTE ) * ONE_MINUTE +

                    get( SECOND ) * ONE_SECOND ) );

        return round( ONE_DAY, getTime().getTime() + offset ) + JULIAN_DAY_OFFSET;

    }

   

    /**

     * Sets the date in the calendar to 00:00 (midnight) on the local calendar day.

     * See getCalendarDay for the definition of calendar day as used in this class.

     *

     * @param calendarDay the day to set the calendar to.

     * @see #setCalendarDay

     * @see java.util.TimeZone#getRawOffset

     */

    public void setCalendarDay( long calendarDay ) {

        // Set to the beginning of the Julian day.

        // Then add in the difference to make it 00:00 local time.

        setJulianDay( calendarDay );

        setTimeInMillis( getTime().getTime() - getTimeZone().getRawOffset() );

        // we may have gone slightly too far, because we used the

        // raw offset (diff between Standard time to GMT/UT, instead of the

        // actual value for this day, so during DLS we may be at 1 AM or whatever

        // the local DLS offset is), so we'll just drop back to midnight.

        set( HOUR_OF_DAY, 0 );

    }

   

    /**

    * Finds the number of days after 12/31/4312 BC 24:00 GMT on a proleptic

    * Julian Calendar (i.e. extending the Julian Calendar into pre-history)

    * to the current time.

    *

The Astronomers Julian Day begins at noon.  The Julian Day used here

    * sometimes called the Chronologists or Historians Julian Day

    * starts at midnight.  For more information see

    * http://www.magnet.ch/serendipity/hermetic/cal_stud/jdn.htm#astronomical

    *

Note: This routine does NOT take into consideration

    * leap seconds.

    *

    * @return the day number of the current time from 1/

    * @see #getCalendarDay

    */    

    public long getJulianDay() {

        return round( ONE_DAY, getTime().getTime() ) + JULIAN_DAY_OFFSET;

    }

   

    /**

    * Sets the current date contained in this calendar to exactly

    * 00:00 GMT on the date defined by the Julian Day provided.

    *

    * @param julianDay the Julian Day to set the calendar to

    * @see #setCalendarDay

    */

    

    public void setJulianDay( long julianDay ) {

        setTimeInMillis( ( julianDay - JULIAN_DAY_OFFSET ) * ONE_DAY );       

    }

       

    /**

     * This is a utility routine for rounding (toward negative) to the nearest

     * multiple of the conversion factor.

     *

BUG? Why is this different than the formula given in

     * java.util.GregorianCalendar private millisToJulianDay?

     *

     * @param conversion typically one of the constants defined

     * above ONE_MINUTE, ONE_DAY etc.

     * @param fractions the value to convert expressed in the same units

     * as the conversion factor (i.e milliseconds).

     *

     * @return the value divided by the conversion factor, rounded to the negative.

     * @see java.util.Calendar

     */

    protected static final long round( long conversion, long fractions ) {

        long wholeUnits;

       

        // round toward negative:

        // For secs rounded to minutes -61/60=-1, -60/60=-1, -59/60=0,

        //      but we want -2, -1, -1 not -1,-1,0

        // or month 0..11 => year 1; -12..-1 => 0; -24..-13 => -1

       

        if ( fractions >= 0 ) {

            wholeUnits = fractions / conversion;

        }

        else {

            wholeUnits = ( fractions + 1 )/ conversion - 1;

        }       

        return wholeUnits;

    }   

} // FAQCalendar

 

JAVA Index

For more details contact the webmaster