Using GregorianCalendar with SimpleDateFormat
Asked Answered
A

5

34

So, I've been racking my brain over this (should-be) simple exercise to make the program turn a date string into a GregorianCalendar object, format it, and return it again as a string when it's done.

This is the last little bit of a program that takes in a chuck of text from a file, breaks it down into individual records, then breaks the records into individual pieces of data and assigns them to a person object.

I've checked the code in multiple places and the code does exactly what it's supposed to be doing up until I call the format function, which throws an IllegalArgumentException. The GergorianCalendar object is assigned the values it is supposed to be assigned (though printing it is, again, a whole other story as seen below…), yet the format will not accept the object for formatting.

Unfortunately, the instructor wasn't too sure of how to use the GregorianCalendar and SimpleDateFormat (yet assigned us to work with them) and said: "Just Google it…" I tried, and nothing I've found has helped.

The code I have so far is:

public class DateUtil {

    public static GregorianCalendar convertFromDMY(String dd_mm_yy) throws ParseException{

        // this actually works, got rid of the original code idea
        String[] splitDate = dd_mm_yy.split("-");
        int days = Integer.parseInt(splitDate[0]);
        int month = Integer.parseInt(splitDate[1]);
        int year = Integer.parseInt(splitDate[2]);

        // Dates are going in right, checked in print statement,
        // but the object is not getting formatted…
        GregorianCalendar dateConverted = new GregorianCalendar(year, month, days);
        format(dateConverted);
        return dateConverted;
    }

    public static String format(GregorianCalendar date){

        SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
        String dateFormatted = fmt.format(date);
        return dateFormatted;
    }
}

The error I get is:

Exception in thread "main" java.lang.IllegalArgumentException: Cannot format given Object >as a Date

    at java.text.DateFormat.format(DateFormat.java:281)
    at java.text.Format.format(Format.java:140)
    at lab2.DateUtil.format(DateUtil.java:26) 
    at lab2.DateUtil.convertFromDMY(DateUtil.java:19)
    at lab2.Lab2.createStudent(Lab2.java:75)
    at lab2.Lab2.main(Lab2.java:34)

And another thing, am I even using the GregorianCalendar right?? When I print out that object's value (should be getting a date, right?) I get this:

java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Vancouver",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=189,lastRule=java.util.SimpleTimeZone[id=America/Vancouver,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=1985,MONTH=4,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=22,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]

The year, month and day_of_month values are all correct as they are the numbers I passed into the creation of it.

Thoughts, suggestions, am I even close?

Edit

Original issues cleared up (thank you assylias!), but I still can't print properly because the two functions aren't linked and the requirements are to have a GregorianCalendar date value printed out from the person object (as birthdate is a GregorianCalendar).

Updated code:

public class DateUtil {

    static SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");

    public static GregorianCalendar convertFromDMY(String dd_mm_yy) throws ParseException{

        // this actually works, got rid of the original code idea
        String[] splitDate = dd_mm_yy.split("-");
        int days = Integer.parseInt(splitDate[0]);
        int month = (Integer.parseInt(splitDate[1]) - 1);
        int year = Integer.parseInt(splitDate[2]);

        // dates go in properly
        GregorianCalendar dateConverted = new GregorianCalendar(year, month, days);
        String finalDate = format(dateConverted);
        return ;
    }

    public static String format(GregorianCalendar date) throws ParseException{

       fmt.setCalendar(date);
        String dateFormatted = fmt.format(date.getTime());
        System.out.println(dateFormatted);
        return dateFormatted;
    }

}

Last edit

OK, so it seems that I'm an idiot and DIDN'T need to link the two DateUtil functions together, but use them in tandem. First, convert the birthdate to a GregorianCalendar and store it in the person object. Then, in the print statement, just simply tell the program to format that date as it's being printed. Problem was solved. All works according to specifications now, and I feel that much stupider because I was flailing like a fish out of water for the last day or so with the DateUtil class, trying to get them to work at the same time.

Thanks for the help all on getting the date go in properly!

Agranulocytosis answered 31/5, 2012 at 8:27 Comment(1)
FYI, to format code on StackOverflow, start a line with 4 (or more) spaces. Use > only for non-code quotes.Jovial
J
60

SimpleDateFormat.format() method takes a Date as a parameter. You can get a Date from a Calendar by calling its getTime() method:

public static String format(GregorianCalendar calendar) {
    SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
    fmt.setCalendar(calendar);
    String dateFormatted = fmt.format(calendar.getTime());

    return dateFormatted;
}

Also note that the months start at 0, so you probably meant:

int month = Integer.parseInt(splitDate[1]) - 1;
Jovial answered 31/5, 2012 at 8:33 Comment(10)
You might also want to set the calendar in the SimpleDateFormat, so that it knows to use that rather than a different calendar system.Conscience
lol i thought there was something to date, but i fooled around with it for a while and couldn't make it work so i gave up on it =P i'll report back in a fewAgranulocytosis
ok yeah so that fixed the error, i feel like an idiot for not distinguishing between a date and a calendar >< only issue is that when printing the date out now i still get that long line for GergorianCalendar data rather than an actual dateAgranulocytosis
and i fixed that by playing around with the print statement, the toString() was not right as pointed out by JB Nizet below. thanks all!Agranulocytosis
Not sure what changes you have made, but in the code of your question this statement: format(dateConverted); does nothing (i.e. your code would do exactly the same thing if you removed that line).Jovial
well i got it printing out the year, month or day of each individual person object lol but not all at the same time so ALMOST. so close yet so far lolAgranulocytosis
when i print of the string in the format function it works like a charm, but getting the two functions to work together is not happening for me right now =[ the guidelines for this exercise are so vagueAgranulocytosis
@Agranulocytosis That's what my previous comment was about. The format method creates a formatted string which you never use in the convertFromDMY method. You should have something like String formattedDate = format(dateConverted); in convertFromDMY for example.Jovial
"SimpleDateFormat#format method takes a Date as a parameter" Sorry, you are wrong. It takes Object. But if the object is not considered good, it throws IllegalArgumentException.Nitro
yeah, i see what you mean, it was just sitting there. the updated code is up there now, I'm not sure what to return since the issue is gonna be the same if i return a gregoriancalendar. it'll print out that long line again, not the actual date i'm getting from the string =/Agranulocytosis
E
6

Why such complications?

public static GregorianCalendar convertFromDMY(String dd_mm_yy) throws ParseException 
{
    SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
    Date date = fmt.parse(dd_mm_yy);
    GregorianCalendar cal = GregorianCalendar.getInstance();
    cal.setTime(date);
    return cal;
}
Erida answered 31/5, 2012 at 8:34 Comment(4)
it was a requirement that there have to be those 2 functions =/ nothing is ever simple lolAgranulocytosis
Well you can split this into 2 methods (not functions) if you wish :)Erida
the line about the return statement provides an error of "cannot convert from void to GregorianCalendar"Agranulocytosis
@RejectionHurts: I fixed the code. You need to split it on two lines.Darr
D
3

A SimpleDateFormat, as its name indicates, formats Dates. Not a Calendar. So, if you want to format a GregorianCalendar using a SimpleDateFormat, you must convert the Calendar to a Date first:

dateFormat.format(calendar.getTime());

And what you see printed is the toString() representation of the calendar. It's intended usage is debugging. It's not intended to be used to display a date in a GUI. For that, use a (Simple)DateFormat.

Finally, to convert from a String to a Date, you should also use a (Simple)DateFormat (its parse() method), rather than splitting the String as you're doing. This will give you a Date object, and you can create a Calendar from the Date by instanciating it (Calendar.getInstance()) and setting its time (calendar.setTime()).

My advice would be: Googling is not the solution here. Reading the API documentation is what you need to do.

Darr answered 31/5, 2012 at 8:38 Comment(0)
N
2
  1. You are putting there a two-digits year. The first century. And the Gregorian calendar started in the 16th century. I think you should add 2000 to the year.

  2. Month in the function new GregorianCalendar(year, month, days) is 0-based. Subtract 1 from the month there.

  3. Change the body of the second function as follows:

        String dateFormatted = null;
        SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
        try {
            dateFormatted = fmt.format(date);
        }
        catch ( IllegalArgumentException e){
            System.out.println(e.getMessage());
        }
        return dateFormatted;
    

After debugging, you'll see that simply GregorianCalendar can't be an argument of the fmt.format();.

Really, nobody needs GregorianCalendar as output, even you are told to return "a string".

Change the header of your format function to

public static String format(final Date date) 

and make the appropriate changes. fmt.format() will take the Date object gladly.

  1. Always after an unexpected exception arises, catch it yourself, don't allow the Java machine to do it. This way, you'll understand the problem.
Nitro answered 31/5, 2012 at 9:21 Comment(3)
unfortunately i can't make the last change you suggested as it states those are the functions to use, can't change them =/ i did fix the -1 already, totally forgot that, the year is not a problem it seems, and the body of my format function works properly now that assylias' changes have been implemented =P i added a print statement into the format function just to see, and they print out according to the exercise requirements. ill update the above codeAgranulocytosis
The year is a problem - there was no gregorian calendar in the first century AC. Correct function will check the input for the date being after gregorian calendar was firstly set.Nitro
Of course, you can make transfer GregorianCalendar.getTime() inside the function, too. For example, fmt.format(date.getTime()). But it is also extremely bad to name GregorianCalendar variable as Date variable. Names should sit with their types.Nitro
C
2

tl;dr

LocalDate.parse(
    "23-Mar-2017" ,
    DateTimeFormatter.ofPattern( "dd-MMM-uuuu" , Locale.US ) 
)

Avoid legacy date-time classes

The Question and other Answers are now outdated, using troublesome old date-time classes that are now legacy, supplanted by the java.time classes.

Using java.time

You seem to be dealing with date-only values. So do not use a date-time class. Instead use LocalDate. The LocalDate class represents a date-only value without time-of-day and without time zone.

Specify a Locale to determine (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, separators, and such.

Parse a string.

String input = "23-Mar-2017" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MMM-uuuu" , Locale.US ) ;
LocalDate ld = LocalDate.parse( input , f );

Generate a string.

String output = ld.format( f );

If you were given numbers rather than text for the year, month, and day-of-month, use LocalDate.of.

LocalDate ld = LocalDate.of( 2017 , 3 , 23 );  // ( year , month 1-12 , day-of-month )

See this code run live at IdeOne.com.

input: 23-Mar-2017

ld.toString(): 2017-03-23

output: 23-Mar-2017


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Citric answered 13/5, 2017 at 2:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.