关于Java:使用GregorianCalendar 与SimpleDateFormat格式

Using GregorianCalendar with SimpleDateFormat

所以我一直在绞尽脑汁做这个(应该是)简单的练习,让程序把一个日期字符串转换成一个公历日历对象,格式化它,并在完成后将它作为字符串返回。

这是一个程序的最后一点,它从一个文件中接收一堆文本,将其分解成单独的记录,然后将这些记录分解成单独的数据块,并将它们分配给一个Person对象。

我已经在多个地方检查了代码,代码执行了它应该执行的操作,直到我调用了格式函数,它抛出了IllegalArgumentException。GergorianCalendar对象被分配了它应该被分配的值(尽管再次打印它是一个完整的另一个故事,如下所示…),但是格式将不接受对象进行格式化。

不幸的是,老师不太确定如何使用公历日历和simpledateformat(还指派我们与他们合作),并说"只需谷歌它"…我试过了,但没发现有什么帮助。

到目前为止,我得到的代码是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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;
    }
}

我得到的错误是:

1
2
3
4
5
6
7
8
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)

还有一件事,我是不是在使用公历??当我打印出该对象的值时(应该得到正确的日期?)我明白这一点:

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=?]

月份值的年、月和日都是正确的,因为它们是我在创建它时传递给它的数字。

想法,建议,我是不是很亲近?

编辑

原始问题已经解决了(谢谢你,混蛋!)但我仍然无法正确打印,因为这两个功能没有链接,并且要求从Person对象中打印出一个Gregoricalendar日期值(因为birthdate是Gregoricalendar)。

更新代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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;
    }

}

最后编辑

好吧,看起来我是个白痴,不需要将两个dateutil函数链接在一起,而是串联使用它们。首先,将生日转换为公历日历并存储在Person对象中。然后在打印语句中,只需告诉程序在打印时格式化该日期。问题解决了。现在所有的工作都是按照规范进行的,我觉得这太愚蠢了,因为在最后一天,我就像一条鱼一样在水里挣扎着,和dateutil一起努力让他们同时工作。

谢谢你的帮助,让我们的约会顺利进行!


SimpleDateFormat#format方法以Date作为参数。通过调用getTime方法,可以从Calendar中获得Date

1
2
3
4
5
6
public static String format(GregorianCalendar calendar){
    SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy");
    fmt.setCalendar(calendar);
    String dateFormatted = fmt.format(calendar.getTime());
    return dateFormatted;
}

还要注意,月份从0开始,所以您可能是指:

1
int month = Integer.parseInt(splitDate[1]) - 1;


为什么会这样复杂?

1
2
3
4
5
6
7
8
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;
}


simpledateformat,顾名思义,格式化日期。不是日历。因此,如果要使用simpledateformat格式化公历日历,必须首先将日历转换为日期:

1
dateFormat.format(calendar.getTime());

您看到的是日历的toString()表示。它的预期用途是调试。它不用于在GUI中显示日期。为此,请使用(简单)日期格式。

最后,要从字符串转换为日期,您还应该使用(简单的)日期格式(它的parse()方法),而不是像您所做的那样拆分字符串。这将给您一个日期对象,您可以通过声明日期(Calendar.getInstance()和设置日期时间(calendar.setTime()来创建一个日历。

我的建议是:谷歌不是解决办法。阅读API文档是您需要做的。


DR

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

避免传统日期时间类

问题和其他答案现在已经过时了,使用了麻烦的旧日期时间类,这些类现在是遗留的,被java.time类所取代。

使用JavaTimes

你似乎只处理日期价值观。所以不要使用日期时间类。改为使用LocalDateLocalDate类表示没有时间和时区的仅日期值。

指定一个Locale来确定(a)用于翻译日、月等名称的人类语言;(b)决定缩写、大写、标点符号、分隔符等问题的文化规范。

解析字符串。

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

生成字符串。

1
String output = ld.format( f );

如果您得到的是数字而不是文本,则使用LocalDate.of

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

请在ideone.com上查看此代码。

input: 23-Mar-2017

ld.toString(): 2017-03-23

output: 23-Mar-2017

关于JavaTimes

JavaTimeFr框架是在Java 8和之后构建的。这些类取代了麻烦的旧遗留日期时间类,如java.util.DateCalendarSimpleDateFormat

现在处于维护模式的joda time项目建议迁移到java.time类。

要了解更多信息,请参阅Oracle教程。以及搜索堆栈溢出以获得许多示例和解释。规格为JSR 310。

使用符合JDBC4.2或更高版本的JDBC驱动程序,可以直接与数据库交换java.time对象。不需要字符串,也不需要Java.SQL.*类。

在哪里获取java.time类?

  • Java SE 8、Java SE 9及以后
    • 内置的。
    • 标准JAVA API的一部分与捆绑实现。
    • Java 9添加了一些小的特性和修复。
  • Java SE 6和Java SE 7
    • 大部分JavaTimeActudio都被移植到TealEnter后端的Java 6和7中。
  • 安卓
    • java.time类的Android包实现的更高版本。
    • 对于早期的android,threetenabp项目适应threeten backport(如上所述)。看看如何使用三连珠……

threeten额外项目使用额外的类扩展java.time。这个项目是将来可能添加到java.time的一个试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等等。


  • 你在这里输入的是两位数的年份。第一世纪。公历始于16世纪。我想,你今年应该再增加2000个。

  • 新公历日历函数中的月份(年、月、日)以0为基础。从那里的月份中减去1。

  • 将第二个函数的主体更改为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
        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;
  • 调试之后,您将看到,仅仅是gregoricalendar不能是fmt.format()的参数;

    实际上,没有人需要将公历作为输出,即使要求您返回"字符串"。

    将格式函数的头改为

    1
    public static String format(Date date)

    做出适当的改变。fmt.format()会欣然接受日期对象。

  • 总是在出现意外的异常之后,自己捕捉它,不要让Java机器来做它。这样你就能理解问题了。