Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
276 views
in Technique[技术] by (71.8m points)

java - Calendar.getTime IllegalArgumentException [重复](Calendar.getTime IllegalArgumentException [duplicate])

import java.util.Calendar;

public class WeekYear {
    static String input = "202001";
    //static String format = "YYYYMM";

    public static void main(String[] args) throws ParseException {
        Calendar lCal = Calendar.getInstance();
        System.out.println(lCal.isLenient());
        lCal.setLenient(false);
        lCal.set(Calendar.YEAR, new Integer(input.substring(0, 4)).intValue());
        lCal.set(Calendar.WEEK_OF_YEAR, new Integer(input.substring(4, 6)).intValue());
        //lCal.setMinimalDaysInFirstWeek(5);
        System.out.println(lCal.isLenient());
        System.out.println(lCal.getTime());

        //lCal.set(Calendar.YEAR, new Integer(input.substring(0, 4)).intValue());
        //lCal.set(Calendar.WEEK_OF_YEAR, new Integer(input.substring(4, 6)).intValue());
        //System.out.println(lCal.getTime());
    }
}

When this code is executed on Nov 22nd, 2020 I get an IllegalArgumentException from Calendar.getTime(). (在2020年11月22日执行此代码时,我从Calendar.getTime()获得了IllegalArgumentException。) But when executed on Nov 27, 2020 it works fine. (但是在2020年11月27日执行时,它可以正常工作。)

The documentation says: (该文件说:)

The setLenient(boolean leniency) method in Calendar class is used to specify whether the interpretation of the date and time is to be lenient or not. (Calendar类中的setLenient(boolean leniency)方法用于指定日期和时间的解释是否宽松。) Parameters: The method takes one parameter leniency of the boolean type that refers to the mode of the calendar. (参数:该方法采用一种boolean类型的参数leniency ,该leniency类型引用日历的模式。)

Any explanation? (有什么解释吗?)

  ask by Gopinathan translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

tl;dr (tl; dr)

Never use Calendar , now legacy, supplanted by java.time classes such as ZonedDateTime . (永远不要使用由Java.time类(例如ZonedDateTime取代的Calendar (现已遗留)。)

Use a purpose-built class, YearWeek from the ThreeTen-Extra project, to track standard ISO 8601 weeks . (使用一个专用类, YearWeekThreeTen-额外的项目,跟踪标准ISO8601周 。)

Custom formatter (自定义格式器)

Define a DateTimeFormatter object to match your non-standard input string. (定义一个DateTimeFormatter对象以匹配您的非标准输入字符串。)

org.threeten.extra.YearWeek
.parse(
    "202001" ,
    new DateTimeFormatterBuilder()
    .parseCaseInsensitive()
    .appendValue( IsoFields.WEEK_BASED_YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
    .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2)
    .toFormatter()
)
.toString()

2020-W01 (2020-W01)

Standard formatter (标准格式器)

Or manipulate your input string to comply with the ISO 8601 standard format , inserting a -W in the middle between the week-based-year and the week. (或操纵您的输入字符串以符合ISO 8601标准格式 ,在基于周的年份和星期之间的中间插入-W 。) The java.time classes and the ThreeTen-Extra classes all use the ISO 8601 formats by default when parsing/generating strings. (解析/生成字符串时,默认情况下, java.time类和ThreeTen-Extra类均使用ISO 8601格式。)

String input = "202001";
String inputModified = input.substring( 0 , 4 ) + "-W" + input.substring( 4 );
YearWeek yearWeek = YearWeek.parse( inputModified ) ;

yearWeek.toString(): 2020-W01 (yearWeek.toString():2020-W01)

Avoid legacy date-time classes (避免使用旧的日期时间类)

Do not waste your time trying to understand Calendar . (不要浪费时间尝试了解Calendar 。) This terrible class was supplanted years ago by the modern java.time classes defined in JSR 310. (几年前,这个可怕的类被JSR 310中定义的现代java.time类所取代。)

Definition of week (周的定义)

You must specify your definition of a week. (您必须指定一周的定义。) Do you mean week number 1 contains the first day of the year? (您是说第1周包含一年的第一天吗?) Or week # 1contains a certain day of the week? (还是第1周包含一周中的某天?) Or week # 1 is the first calendar week to consist entirely of dates in the new year? (还是#1周是第一个完全包含新年日期的日历周?) Or perhaps an industry-specific definition of week? (还是特定于行业的周定义?) Some other definition? (还有其他定义吗?)

One of the confusing things about Calendar is that its definition of a week shifts by Locale . (关于Calendar的令人困惑的事情之一是,它对周的定义因Locale 。) This one of many reasons to avoid that legacy class. (这是避免该传统类的许多原因之一。)

Week-based year (基于周的年份)

Depending on your definition of week, the year of a week may not be the calendar year of some dates on that week. (根据您对周的定义,一周中的年份可能不是该周中某些日期的日历年。) A week-based year may overlap with calendar years. (基于星期的年份可能与日历年份重叠。)

Standard weeks and week-based year (标准周和周基年)

For example, the standard ISO 8601 week defines a week as: (例如, 标准ISO 8601星期一周定义为:)

  • Starting on Monday, and (从星期一开始,并且)
  • Week # 1 contains the first Thursday of the calendar year. (第1周包含日历年的第一个星期四。)

So there are 52 or 53 whole weeks in every week-based year. (因此,每个每周的年度有52或53个整周。) Of course, that means some dates from the previous and/or following calendar years may appear in the first/last weeks of our week-based year. (当然,这意味着上一个日历年和/或下一个日历年的某些日期可能会出现在我们基于周的年份的第一周/最后一周。)

org.threeten.extra.YearWeek

One problem is that you are trying to represent a year-week with a class that represents a moment, a date with time of day in the context of a time zone. (一个问题是,您试图用一个代表时刻的类来代表一年中的一周,这个时刻在时区的上下文中具有日期。)

Instead, use a purpose-built class. (而是使用专门构建的类。) You can find one in the ThreeTen-Extra library, YearWeek . (您可以在ThreeTen-ExtraYearWeek找到一个。) This library extends the functionality of the java.time classes built into Java 8 and later. (该库扩展了Java 8及更高版本中内置的java.time类的功能。)

With that class I would think that we could define a DateTimeFormatter to parse your input using the formatting pattern YYYYww where the YYYY means a 4-digit year of week-based-year, and the ww means the two-digit week number. (在该类中,我认为我们可以定义一个DateTimeFormatter来使用格式模式YYYYww解析您的输入,其中YYYY表示基于星期的年份的4位数字,而ww表示两位的星期数。) Like this: (像这样:)

// FAIL
String input = "202001" ; 
DateTimeFormatter f = DateTimeFormatter.ofPattern( "YYYYww" ) ;
YearWeek yearWeek = YearWeek.parse( input , f ) ;

But using that formatter throws an DateTimeParseException for reasons that escape me. (但是使用该格式化程序会引发DateTimeParseException ,这是出于逃避我的原因。)

Exception in thread "main" java.time.format.DateTimeParseException: Text '202001' could not be parsed: Unable to obtain YearWeek from TemporalAccessor: {WeekOfWeekBasedYear[WeekFields[SUNDAY,1]]=1, WeekBasedYear[WeekFields[SUNDAY,1]]=2020},ISO of type java.time.format.Parsed (线程“主”中的异常java.time.format.DateTimeParseException:无法解析文本“ 202001”:无法从TemporalAccessor获取YearWeek:{WeekOfWeekBasedYear [WeekFields [SUNDAY,1]] = 1,WeekBasedYear [WeekFields [SUNDAY,1] ]] = 2020},ISO类型为java.time.format.Parsed的ISO)

(…)

Caused by: java.time.DateTimeException: Unable to obtain YearWeek from TemporalAccessor: {WeekOfWeekBasedYear[WeekFields[SUNDAY,1]]=1, WeekBasedYear[WeekFields[SUNDAY,1]]=2020},ISO of type java.time.format.Parsed (由以下原因引起:java.time.DateTimeException:无法从TemporalAccessor获取YearWeek:{WeekOfWeekBasedYear [WeekFields [SUNDAY,1]] = 1,WeekBasedYear [WeekFields [SUNDAY,1]] = 2020},ISO类型为java.time.format 。解析)

(…)

Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: WeekBasedYear (原因:java.time.temporal.UnsupportedTemporalTypeException:不支持的字段:WeekBasedYear)

Alternatively, we can use DateTimeFormatterBuilder to build up a DateTimeFormatter from parts. (或者,我们可以使用DateTimeFormatterBuilder建立一个DateTimeFormatter从零件。) By perusing the OpenJDK source code for Java 13 for DateTimeFormatter.ISO_WEEK_DATE I was able to cobble together this formatter that seems to work. (通过仔细阅读适用于DateTimeFormatter.ISO_WEEK_DATE Java 13 OpenJDK源代码 ,我可以将这个似乎有效的格式化程序拼凑在一起。)

DateTimeFormatter f =  
        new DateTimeFormatterBuilder()
        .parseCaseInsensitive()
        .appendValue( IsoFields.WEEK_BASED_YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
        .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2)
        .toFormatter()
;

Using that: (使用:)

String input = "202001" ; 
YearWeek yearWeek = YearWeek.parse( input , f ) ;

ISO 8601 (ISO 8601)

Educate the publisher of your data about the ISO 8601 standard defining formats for repr


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...