Java calendar.month返回周日的月

时间:2018-06-06 19:43:37

标签: java calendar

我有一个具有年和周字段的SQL数据库,我需要获取月份数据。当我试图检索它时,它给了我一个月后的一个月。例如,从2019.01.28-2019.02.01周开始,我得到月份编号2.

有什么问题?

(加上信息:我也试过了其他day_of_week)

以下是代码:

rs = stmt.executeQuery("SELECT * FROM " + sqlDatabase.beosztas() + " WHERE id = \'" + id + "\'");`
        ResultSetMetaData md = rs.getMetaData();
        while (rs.next()) {
            year = rs.getInt(2);
            week = rs.getInt(3);
            cal.set(Calendar.YEAR, year);
            cal.set(Calendar.WEEK_OF_YEAR, week);
            cal.set(Calendar.DAY_OF_WEEK, 1);
            if (count == 0) {
                month = cal.get(Calendar.MONTH) + 1;
            }
            count++;
        }

3 个答案:

答案 0 :(得分:1)

Calendar.DAY_OF_WEEK从星期日开始,而不是星期一。所以在你的情况下,它正常返回周日的月份。如果您想将日期设置为星期一,只需使用:

cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

使用日历时应该小心。 Calendar.MONTH是从0开始的索引,Calendar.DAY_OF_WEEK是从1开始的索引。

因此,您应该使用日历中定义的常量,如Calendar.MONDAY或Calendar.JUNE,以确保您使用正确的月份或日期而不会出错。

为了友好地使用Calendar,常量更好。 想要定义2018-02-18的日期:

Calendar cal = Calendar.getInstance();
cal.set(2018, 2, 18); // wrong. here the date will be 2018-03-18
cal.set(2018, Calendar.FEBRUARY, 18); // correct

答案 1 :(得分:1)

DAY_OF_WEEK 1并不代表一周的第一天。

正如DAY_OF_WEEK的javadoc所说:

  

获取和设置的字段编号,表示星期几。此字段包含值SUNDAYMONDAYTUESDAYWEDNESDAYTHURSDAYFRIDAYSATURDAY

SUNDAY常量的值为1,因此DAY_OF_WEEK 1表示星期日。

要指定一周的第一天,您需要致电getFirstDayOfWeek()

  

获取一周的第一天;例如,美国SUNDAY,法国MONDAY

所以:

int year = 2019;
int week = 5;

Calendar cal = Calendar.getInstance(Locale.US);
cal.clear();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.WEEK_OF_YEAR, week);
cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
System.out.println(cal.getTime());

cal = Calendar.getInstance(Locale.FRANCE);
cal.clear();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.WEEK_OF_YEAR, week);
cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
System.out.println(cal.getTime());

输出

Sun Jan 27 00:00:00 EST 2019
Mon Jan 28 00:00:00 EST 2019

在这两种情况下,你都会获得一月份。

第14周的输出

Sun Mar 31 00:00:00 EDT 2019
Mon Apr 01 00:00:00 EDT 2019

这里的地方很重要,你会得到哪个月。

答案 2 :(得分:1)

grid calendar showing the standard ISO 8601 weeks of 2019 January-February

tl; dr

2019年第5周确实包括从一月到二月的几天,具体取决于您对周的定义。

YearWeek.parse( "2019-W05" ).atDay( DayOfWeek.MONDAY ).toString()
  

2019-01-28

…和…

YearWeek.parse( "2019-W05" ).atDay( DayOfWeek.SUNDAY ).toString()
  

2019-02-03

您忽略了解释周的定义。上面使用标准ISO 8601 week。几周甚至几个月都是日历周。

周?

您对一周的定义是什么? #1周从1月1日开始吗?还是一周从1月1日之前的某个星期几开始?还是第一周是新年的第一周?或者,根据ISO 8601 standard's week,每周是否从星期一开始,第1周包含新日历年的第一个星期四,而一年则由52或53个完整的星期组成,可能最后一个星期或日历年的前几天结束于下一个/上一个基于周的年份?

我将接受ISO 8601培训。参见此list for 2019

2018-W52    December 24, 2018   December 30, 2018
2019-W01    December 31, 2018   January 6, 2019
2019-W02    January 7, 2019     January 13, 2019
2019-W03    January 14, 2019    January 20, 2019
2019-W04    January 21, 2019    January 27, 2019
2019-W05    January 28, 2019    February 3, 2019
2019-W06    February 4, 2019    February 10, 2019

避免使用旧的日期时间类

您正在使用的Calendar类很糟糕,由不了解日期时间处理的复杂性和微妙性的人员设计。与Java捆绑在一起的旧的日期时间类是新的遗产,由JSR 310中定义的 java.time 取代。

Calendar的许多问题中,一周的定义因地区而异。您的代码忽略了语言环境的关键问题。因此,JVM的当前默认语言环境是隐式应用的。这意味着您的结果在运行时可能会有所不同。永远不要使用此类的许多原因之一。

java.time

现代解决方案涉及:

  • Java 8及更高版本中内置的 java.time
  • ThreeTen-Extra库中的YearWeek
  • 用于将日期时间值表示为文本的ISO 8601标准。
  

具有年和周字段的SQL数据库

我建议您改用一个文本字段。年份和星期均使用标准ISO 8601格式:yyyy-Www,例如2010-W01。请注意,这种格式如何导致字母排序也按时间顺序排列。

使用YearWeek类解析此类值。

YearWeek yearWeek = YearWeek.parse( "2019-W05" ) ;

如果您坚持将以周为单位的年数与周数分开,请使用此工厂方法来获取YearWeek对象。

YearWeek yearWeek = YearWeek.of( 2019 , 5 ) ;  // Pass number of the week-based-year and of the week. 

生成ISO 8601字符串。

String output = yearWeek.toString() ;

获取该周的第一天,总是一个星期一。

LocalDate start = yearWeek.atDay( DayOfWeek.MONDAY ) ;

最后一天,通常是星期日。

LocalDate stop = yearWeek.atDay( DayOfWeek.SUNDAY ) ;

生成标准ISO 8601格式的文本。

String report = "Week " + yearWeek + " = " + start + "/" + stop ;
  

2019-W05周= 2019-01-28 / 2019-02-03

因此您可以看到2019年的第5周确实从1月28日(第1个月)到2月3日(第2个月)运行。


关于 java.time

java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore