【问题标题】:Why does my GregorianCalendar object return the wrong day of week?为什么我的 GregorianCalendar 对象返回错误的星期几?
【发布时间】:2013-10-08 19:06:00
【问题描述】:

我的问题看起来非常简单。我从一个 GregorianCalendar 对象制作了一个日历图形用户界面,并使用它的方法来计算不同月份的正确天数,以及不同日期对应的工作日。

但是平日是一贯的休息一天。日历声称 2013 年 7 月 1 日是“2”,在我所在的地区,这意味着星期二。星期一应该是“1”。 “简单!”我想,然后输入: c.setFirstDayOfWeek(Calendar.MONDAY);但是没有反应。

所以我在 stackoverflow 上搜索答案,但遇到我问题的每个人似乎都忘记了一月是 0,而不是 1。我没有。所以现在我被卡住了。

作为一个简化的代码,我做了一个非常短的代码片段,并带有相应的输出:

    GregorianCalendar c = new GregorianCalendar();
    c.setFirstDayOfWeek(Calendar.MONDAY);
    c.set(Calendar.MONTH, 6);
    c.set(Calendar.DAY_OF_MONTH, 1);
    c.set(Calendar.YEAR, 2013);

    SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-YYYY");
    System.out.println(sdf.format(c.getTime()));
    System.out.println(c.get(Calendar.DAY_OF_WEEK));

输出是:

01-07-2013

2

我拒绝在我的代码中输入“-1”,以错误地纠正明显错误的症状。帮助表示赞赏。

【问题讨论】:

  • 2 是星期一... 1 是星期日... 另外,setFirstDayOfWeek,根据文档:The first week of a month or year is defined as the earliest seven day period beginning on getFirstDayOfWeek() and containing at least getMinimalDaysInFirstWeek() days of that month or year。那里没有obvious mistake。只是本地化问题...
  • 谢谢。到目前为止,我已经不再尝试将星期一设置为一周的第一天。编辑我的其他代码以期望星期天是第 1 号似乎更简单,无论它在我看来多么不合逻辑。感谢您告诉我我的错误是我对 setFirstDayOfWeek() 方法的解释。这可能是我自己很难找到的。我希望我能接受它作为答案,但它似乎只是作为评论发布。
  • 对于这个问题的任何新读者,我建议您不要使用GregorianCalendarCalendarSimpleDateFormat。这些类设计不良且早已过时(最后一个尤其​​是出了名的麻烦)。而是使用LocalDateWeekFieldsDateTimeFormatter,均来自java.time, the modern Java date and time API
  • 我拒绝输入“-1”。同样减去 1 对 1 = 星期日也无济于事,因为你会在你想要 7 的地方得到 0。

标签: java date calendar gregorian-calendar


【解决方案1】:

是的,Java 中的日期处理是有问题的...

  • 月份从 0(一月)开始
  • 星期几从SUNDAY 为 1,SATURDAY 为 7 (Ideone fiddle) 开始
  • c.setFirstDayOfWeek(Calendar.MONDAY);和名字所暗示的有点不同

    一个月或一年的第一周定义为从 getFirstDayOfWeek() 开始并至少包含该月或该年的 getMinimalDaysInFirstWeek() 天的最早 7 天时间段

您可以通过始终使用 Calendar 类中定义的常量来摆脱麻烦,并且甚至不尝试从这些常量的数字表示中推断出任何含义,或者Calendar.get(int)方法返回的结果...

【讨论】:

  • 这也是一个非常好的答案+1。六个月以来,我一直在使用日历对象,并且学到了很多东西,感谢像你这样的人。我喜欢你回答中最后一段的措辞。
【解决方案2】:

我拒绝在我的代码中输入“-1”,以错误地纠正明显错误的症状。

错误是您假设Calendar.get(Calendar.DAY_OF_WEEK) 已本地化。它不是。星期几和数字之间的映射是固定的;如果需要,使用Calendar.getFirstDayOfWeek() 确定人类对“一周的第一天”的理解;如果您真的想向用户显示“2”,我会感到惊讶......您肯定想向他们显示一周中的名称

任何涉及一周开始的计算都应该使用getFirstDayOfWeek

【讨论】:

  • 这正是我从之前的评论中设法得到的。真棒答案!谢谢。作为额外的评论;我将整数值解析为另一个 WeekDay 枚举值,这样我就可以用我的母语获得工作日的名称。再次感谢。
  • @KjetilNordin:理想情况下,使用DateFormatSymbols.getInstance(locale).getWeekdays()
  • 我也相信用户不想在星期一看到1。但是他们可能想要一个月历,例如,其中每一天的偏移量与一周中的天数成正比。 getFirstDayOfWeek() 充其量只能提供部分帮助。 java.time 是现代 Java 日期和时间 API,明显比 Calendar 提供更好的支持。
【解决方案3】:

java.time

java.util 日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用,改用modern Date-Time API*

一周的第一天是Localedependent

演示:

import java.time.format.TextStyle;
import java.time.temporal.WeekFields;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // ############## First day of week ##############
        System.out.println(WeekFields.of(Locale.UK).getFirstDayOfWeek().getDisplayName(TextStyle.FULL, Locale.ENGLISH));
        System.out.println(WeekFields.of(Locale.US).getFirstDayOfWeek().getDisplayName(TextStyle.FULL, Locale.ENGLISH));
    }
}

输出:

Monday
Sunday

ONLINE DEMO

如何获取星期几?

import java.time.LocalDate;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2013, Month.JULY, 1);
        System.out.println(date);

        // ############ Day of week ############
        System.out.println(date.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.ENGLISH));
        // Alternatively,
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEEE", Locale.ENGLISH);
        System.out.println(date.format(dtf));
    }
}

我的系统在欧洲/伦敦时区的输出:

2013-07-01
Monday
Monday

ONLINE DEMO

通过 Trail: Date Time 了解有关 modern Date-Time API* 的更多信息。

您的代码和期望出了什么问题?

  • 与您的期望不同的是,您假设 c.get(Calendar.DAY_OF_WEEK) 会为您提供一周的第一天,而它返回 the value representing MONDAY,因为它是 2013 年 7 月 1 日星期一。

  • 您的代码有问题的是使用Y周年)而不是y)。请查看this discussion 以了解有关此差异的更多信息。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 和 7 . 如果您正在为一个 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

【讨论】:

    【解决方案4】:

    java.time

    我建议您使用现代 Java 日期和时间 API java.time 进行日期工作。 Arvind Kumar Avinash 已经在一个答案中展示了它的一个很好的应用 (+1)。

    我理解您的问题的方式是您希望星期一成为一周的第一天,并且您想知道某个日期是一周中的哪一天(例如,2013 年 7 月 1 日)。星期一 = 1,星期二 = 2,以此类推,直到星期日 = 7。

        LocalDate ld = LocalDate.of(2013, Month.JULY, 1);
        
        // Monday is first day of week; which number day of the week is ld then?
        int numberDayOfTheWeek = ld.get(WeekFields.ISO.dayOfWeek()); // 1 through 7
        System.out.println(numberDayOfTheWeek);
    

    输出是:

    1

    将星期一作为一周的第一天符合 ISO 8601(日期和时间的国际标准)。所以内置的WeekFields.ISO 使用这个编号。 WeekFields.ISO.dayOfWeek() 给了我们一个 TemporalField,然后我们用它来查询 LocalDate 对象的星期几。

    我们可以使用WeekFields.of(DayOfWeek.MONDAY, 1) 代替WeekFields.ISO 来指定星期一是一周的第一天。 of() 的第二个参数是从 1 到 7 的第一周(一年或一个月)中的最小天数,我们在这里不使用,所以我们使用哪个数字并不重要。

    链接

    【讨论】:

    • 伟大的补充!感谢您发布它。
    【解决方案5】:

    这是 Java 中的警告之一,

    DAY_OF_WEEK,

    此字段取值 SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、 周五和周六。

    当您的程序打印 2 时,它告诉您星期几是星期一。这个常数值与一周的开始无关。如果一周的第一天是星期天,它恰好与一周中的某一天相同 - 但如果一周的第一天被重新定义,它不会改变。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-16
      • 1970-01-01
      • 2020-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多