• No results found

Date and Time in Java

In document Java (Page 115-121)

This section illustrates more uses of OOP, in the context of dates and time.

Timing

Timing a process is simple. The System class has a static method called currentTimeMillis(), which returns the current system time in milliseconds. This can be used by storing the current time in a variable, running the process, finding the new time, and finding the difference.

For example, this outputs in seconds how long it takes to count to one billion:

long start = System.currentTimeMillis();

for (long i=0; i<1000000000; i++);

long end=System.currentTimeMillis();

System.out.println((end-start)/1000.0);

The for loop has no body - we just count. The return type of currentTimeMillis is a long, since an int does not have sufficient range.

If you run this several times, you get different answers. This is because the computer multitasks, and is doing other activity as well as running this program.

Exercise

Use this method to time how long it takes to bubble sort an array of random integers. Do this for various array sizes from 1000 to 1000000. Does this agree with the theory?

The Date class

The fundamental way that Java treats points in time is as a long integer, being the number of

milliseconds since January 1, 1970, 00:00:00 GMT. The number can be negative, so we can represent times before 1970. A Date object, an instance of the Date class, represents a point in time. Inside a Date object there is a long integer, which fixes the time. We say Date wraps a long integer.

Here is a simple start:

Date now = new Date();

System.out.println(now);

which will output something like:

Mon Oct 17 16:45:00 BST 2011

There are two Date classes. The one in java.sql is about dates in databases. This Date is in java.util.

The no-args constructor Date(); returns a Date object set to the current time and date. The println invokes the toString() method of Date, which by default will format it as shown.

Deprecated methods

So many of the methods in Date were better handled by Calendar. Those methods in Date were said to be deprecated. That means they are still available - otherwise old Java code might stop working.

But it signals that there is a better way of doing it, and that in future deprecated methods may disappear. You should not write Java using a deprecated method.

As an example, Date has another constructor which takes a year (after 1900), month (January=0) and day as arguments:

Date inThePast = new Date(10,2,4);

System.out.println(inThePast);

which outputs

Fri Mar 04 00:00:00 GMT 1910 but this constructor is deprecated.

The imporant thing about Date is that it wraps a long integer which marks a moment in time. We will see how this is useful later.

Exercise

Date has a method getTime() which returns the underlying time point. Use this to find out how many milliseconds after midnight on 1 January 1970 you were born (use the deprecated constructor).

Date Formats

If you just output a Date, you get the default formatting as shown above. If you want to specify the format yourself, you can use an instance of SimpleDateFormat, which is a subclass of the

DateFormat class.

The format is specified by a format string - see the API for all the details. For example:

Date now = new Date();

String s = "'sometime in' MMMM 'in the year' yyyy");

SimpleDateFormat vagueFormat = new SimpleDateFormat(s);

System.out.println(vagueFormat.format(now));

s=("yyyy.MM.dd G 'at' HH:mm:ss z";

SimpleDateFormat exactFormat = new SimpleDateFormat(s);

System.out.println(exactFormat.format(now));

which outputs:

sometime in October in the year 2011 2011.10.18 AD at 11:41:11 BST

SimpleDateFormat also deals with different time zones. This needs a little thought. It is the same moment in time no matter where you are. But it is expressed in different ways in different time zones. Date represents the number of milliseconds since Jan.1,1970 which is the same wherever you are (in UTC). But you can set a SimpleDateFormat to different time zones and see that moment in different places:

Date now = new Date();

String s = "yyyy.MM.dd G 'at' HH:mm:ss z";

SimpleDateFormat exactFormat = new SimpleDateFormat(s);

System.out.println("In London, " + exactFormat.format(now));

TimeZone est = TimeZone.getTimeZone("EST");

exactFormat.setTimeZone(est);

System.out.println("In New York, " + exactFormat.format(now));

TimeZone japan = TimeZone.getTimeZone("Japan");

exactFormat.setTimeZone(japan);

System.out.println("In Tokyo, " + exactFormat.format(now));

which outputs:

In London, 2011.10.18 AD at 11:57:53 BST In New York, 2011.10.18 AD at 05:57:53 EST In Tokyo, 2011.10.18 AD at 19:57:53 JST

Exercise

Output what time it is in Honolulu (unless you are in Honolulu, in which case, what time it is in London).

The GregorianCalendar class

The whole problem with Date is that there are several different calendars in use across the world.

That situation is modelled in OOP by having a class hierarchy, with a base class that establishes the common features which all calendars would have, and sub-classes which model actual calendars.

This is how it works. Calendar is the base class, and offers common features but it is abstract, so you cannot instantiate it. The standard subclass is GregorianCalendar, which models the most common calendar in use across the world today. The no-args constructor creates an object modelling the current time in the current locale. getTime() retrieves the underlying moment, as a Date:

GregorianCalendar gc = new GregorianCalendar();

System.out.println(gc.getTime());

A GregorianCalendar object again represents a moment in time, but unlike Date (which in effect it wraps) it also has fields for day, month, year and so on. When these are changed, it recalculates the underlying time instant (when it needs to).

There are three kinds of methods on these fields - set, add and roll. Set is simplest - it sets the given field to the given value:

GregorianCalendar gc = new GregorianCalendar();

Tue Oct 18 15:15:16 BST 2011 Tue Jan 18 15:15:16 GMT 2011

GregorianCalendar gc = new GregorianCalendar();

GregorianCalendar gc = new GregorianCalendar();

// Tue Oct 18 15:24:31 BST 2011

Check the Calendar API for changing the lenient mode. Use it to validate a date.

Date Calculations

Suppose we want to work out something like the point in time three fifths of the way between 1 Jan 1900 and 12 August 1973. Why? Maybe because you are drawing a graph with time as the x axis.

One way to do it is

1. Make Calendar objects of those two dates.

2. Extract the Date, then the underlying long integer, from those two

3. Do arithmetic on the longs

4. Convert the result back into a Date, then a Calendar:

GregorianCalendar gc1 = new GregorianCalendar(1900,0,0 );

GregorianCalendar gc2 = new GregorianCalendar(1973,7,11 );

Date date1 = gc1.getTime();

GregorianCalendar gc3= new GregorianCalendar();

gc3.setTime(d);

System.out.println(gc3.getTime());

// Wed Mar 01 14:48:00 BST 1944

Exercise

Find out when you were half your current age.

Interfaces

The idea of an interface is abstract and subtle - you might want to read this now, and again later.

A class can implement an interface. This means that the class can do the things the interface says it can. Interface is a Java keyword.

An interface is a set of method signatures (headers, declarations) without method bodies. The class 'implements' an interface by providing a body for each of the methods.

What is the point of that? We often give an object the role of performing some task involving a set of actions. This enables the compiler to check whether the object belongs to a class which can actually do those actions.

As an example, we might want something which will respond to mouse actions on a GUI component like a window. The MouseListener interface has methods for the mouse entering the component, leaving, a mouse button depression, release and click. We might program a class called

MyMouseListener which implements that interface - in other words, actually defines those five methods. Then we code the window that an instance of MyMouseListener will deal with mouse actions. The compiler can check that MyMouseListener actually does implement MouseListener.

We can also think of an interface as a contract. This is like a contract of employemnt - it says the employee will do certain things. It does not say how they will be done, it simply lists the tasks. It is up to the employee to actually do it. The MouseListener is a contract of five tasks. Any class which gets this job must fulfill that contract.

Example - the Comparable Interface

Suppose we have a class of objects consisting of a pair of integers, x and y, and we want to sort an array of such objects. We will name the class Pair. The class Arrays (in the java.util package) has a method called sort which will do that for us. But it can only sort objects which implement the Comparable interface. This is because it is often not obvious what it means for one object to be 'more than' another. We will say that a Pair object is more than another if the sum of x and y is more than the sum of the other objects x and y.

The Comparable interface has just one method, compareTo. This should return a positive int if the object is more than the other, zero if it is equal, and a negative int if it is less.

So we must code our Pair class to do this method:

class Pair implements Comparable { int x, y; // a pair of ints

Pair(int a, int b) { // the constructor x = a;

y = b;

}

void show() { // display values System.out.println(x + " " + y);

}

public int compareTo(Object ob) { // implements the Comparable method Pair other = (Pair) ob;

if ((x + y) > (other.x + other.y)) { return 1;

}

if ((x + y) == (other.x + other.y)) { return 0;

}

return -1;

}

Code to create and sort the array is:

Pair[] data = new Pair[3]; // make an array data[0] = new Pair(3, 2); // put 3 elements in data[1] = new Pair(2, 2);

data[2] = new Pair(1, 2);

Arrays.sort(data); // sort // see what we've got

for (int i = 0; i < data.length; i++) { data[i].show();

}

The output is:

1 2 2 2 3 2 Exercise

Change the compareTo implementation so that one Pair is more than another if the average of x and y is greater. Test it.

In document Java (Page 115-121)