Working with Java Date and Calendar API



Working with Java Date, Calendar API

The following code tries to demonstrate main usage of Java Date, and Calendar API.

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class DateCalendarTest {
    public static void testSimpleDateFormat() throws ParseException {
       // If no timezone is set, it would use the default timezone.
       DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm");
       // String to Date
       Date date = df.parse("2011/04/16 26:65");
       df.setLenient(true); // allow string like 26:65 etc, default is true
       // Date to String
       String sre = df.format(new Date());
       // this would use the default format of the user's computer
       df = DateFormat.getDateInstance();
       // It also provides some alternative styles for dates.
       df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
       df = DateFormat.getDateInstance(DateFormat.LONG);
       df = DateFormat.getTimeInstance();
    }
    public static void testCalendar() {
       // this would create a calendar with current time and time zone.
       Calendar calendar = Calendar.getInstance();
       Date date = calendar.getTime();
       // Be aware that months start with January equal to 0, month of the
       // following time is May.
       calendar = new GregorianCalendar(2011, 04, 16);
       // A better way to create that date would be:
       calendar = new GregorianCalendar(2011, Calendar.APRIL, 16, 23, 31, 00);
       calendar.add(GregorianCalendar.DATE, 90);
       calendar.add(GregorianCalendar.MONTH, 1);
       // calculate difference between times
       System.err.println(calendar.getTime());
    }
    public static void compareDate(Calendar calendar1, Calendar calendar2) {
       long days, hours, minutes, seconds;
       long diff = calendar1.getTimeInMillis() - calendar2.getTimeInMillis();
       long millisADay = 24 * 60 * 60 * 1000;
       days = diff / millisADay;
       diff = diff - (days * millisADay);
       hours = diff / 3600;
       diff = diff - (hours * 3600);
       minutes = diff / 60;
       diff = diff - (minutes * 60);
       seconds = diff;
       System.out.println(days + " days(s) " + hours + " hour(s) " + minutes
               + " minute(s) " + seconds + " second(s)");
    }
    public static void testTimeZone() {
       // displays the ID of the current default time zone
       System.out.println(TimeZone.getDefault().getID()); // Asia/Shanghai
       // You can change system property - user.timezone to alter the default time zone.
    }
    public static void testSqlTime() {
       // convert a java.sql.timestamp to a java.util.Date
       java.sql.Timestamp t = new java.sql.Timestamp(new Date().getTime());
       // 1 Milli = 1x10^6 Nanos
       Date d = new Date(t.getTime() + (t.getNanos() / 1000000));
       DateFormat df = new SimpleDateFormat("MM/dd/yy hh:mm:ss.SSS a");
       System.out.println(df.format(d)); // Right! At least we have the millis
    }
    /**
     * This is a program to demonstrate how to group the days between startDate
     * and endDate by week
     */
    public static void runWeeklyReport(Date startDate, Date endDate) {    Calendar startCalendar = Calendar.getInstance();
       startCalendar.setTime(startDate);
       Calendar endCalendar = Calendar.getInstance();
       endCalendar.setTime(endDate);
       while (startCalendar.before(endCalendar)) {
           Date weekStartDate = startCalendar.getTime();
           int dayOfWeek = startCalendar.get(Calendar.DAY_OF_WEEK);
           if (dayOfWeek != Calendar.SUNDAY) {
              startCalendar.add(Calendar.DAY_OF_WEEK, 7 - dayOfWeek + 1);
              startCalendar.set(Calendar.HOUR, 23);
              startCalendar.set(Calendar.MINUTE, 59);
              startCalendar.set(Calendar.SECOND, 59);
           }
           if (startCalendar.before(endCalendar)) {
              Date weekEndDate = startCalendar.getTime();
              subrutine(weekStartDate, weekEndDate);
           } else {
              break;
           }
           // Go to next week
           startCalendar.add(Calendar.SECOND, 1);
       }
    }
private static void subrutine(Date weekStartDate, Date weekEndDate) {
       System.err.println(weekStartDate + ":" + weekEndDate);
    }
}
Caveat
1. Months start with January equal to 0:
new GregorianCalendar(2011, 04, 16); the month would be set to May, not April, better to use the defined constants: Calendar.JANUARY.
2. The first day of week is SUNDAY, Calendar.SUNDAY = 1.

java.sql.Date, java.sql.Time, java.sql.Timestamp are subclasses of java.util.Date.

So don't use instance variables or static instance variables to store a SimpleDateFormat - in this way, you have to synchronize its access.
Instead, the simple and safe way is to create a new SimpleDateFormat object each time - modern jvms don't have any problem allocating short lived objects.

Validation
By default SimpleDateFormat is lenient, it is tolerant to some formatting errors. It will try to figure out the date by applying some heuristics to the given text.
So the following date would be interpreted as 2011/06/10 03:05:00.
Date date = df.parse("2011/04/100 26:65:00");

If you want to strictly validate user input, set the SimpleDateFormat non-lenient by: sdf.setLenient(false);

Many methods in java.util.Date are deprecated, but it doesn't mean java.util.Date is dead. In stead, we should use java.util.Date, Calendar together, use Date objects to hold, store or communicate a date-time value. Use a Calendar object to manipulate a date-time value. Of course don't use the deprecated methods of java.util.Date.

What then is the role of java.util.Date?
A java.util.Date is a value object, and is a variation of the Memento or Token pattern.
It simply holds state - a long integer value of milliseconds since 1970-01-01 00:00:00.00 GMT. This is a very compact way to represent a date and time value, thus fits the idea of the Memento pattern very well.

You should use a java.util.Date as a value object to hold timestamps when you need to move such values between different parts of your software.

What then is the role of Calendar?
GregorianCalendar is many tens of times larger than the much simplier java.util.Date as it holds many additional information as part of its extensive internal state.

So don't use Calendar as a data transfer object.
Calendar is a variation of a strategy pattern, There are various implementations of calendar available including GregorianCalendar , JapaneseImperialCalendar. ChineseCalendar, HebrewCalendar are available from the IBM ICU4J Project.

Resources

Labels

adsense (5) Algorithm (69) Algorithm Series (35) Android (7) ANT (6) bat (8) Big Data (7) Blogger (14) Bugs (6) Cache (5) Chrome (19) Code Example (29) Code Quality (7) Coding Skills (5) Database (7) Debug (16) Design (5) Dev Tips (63) Eclipse (32) Git (5) Google (33) Guava (7) How to (9) Http Client (8) IDE (7) Interview (88) J2EE (13) J2SE (49) Java (186) JavaScript (27) JSON (7) Learning code (9) Lesson Learned (6) Linux (26) Lucene-Solr (112) Mac (10) Maven (8) Network (9) Nutch2 (18) Performance (9) PowerShell (11) Problem Solving (11) Programmer Skills (6) regex (5) Scala (6) Security (9) Soft Skills (38) Spring (22) System Design (11) Testing (7) Text Mining (14) Tips (17) Tools (24) Troubleshooting (29) UIMA (9) Web Development (19) Windows (21) xml (5)