【问题标题】:Java Calendar - First day of week VS actual minimumJava 日历 - 一周的第一天 VS 实际最小值
【发布时间】:2020-07-14 07:30:34
【问题描述】:

我正在测试我们的一个日期管理框架,它应该重置一些 Calendar 字段(使用 actual minimum)。

但是,当changing first day of weekCalendar 总是返回 SUNDAY (1) 作为 actual minimumday of weeks。是bug吗?

MVCE:

import java.util.*;

public class Main {
  public static void main(String[] args) {
    System.out.printf("Java specification: %s%n", System.getProperty("java.vm.specification.version"));
    System.out.printf("Java version: %s%n", System.getProperty("java.specification.version"));
    System.out.printf("VM version: %s%n", System.getProperty("java.vm.version"));

    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));

    int[] days = { 1, 5, 7 };
    for (int day : days) {
      cal.setTimeInMillis(0L);
      cal.setFirstDayOfWeek(day);
      System.out.printf("expected: %d, actual: %d%n", day, cal.getActualMinimum(Calendar.DAY_OF_WEEK));
    }
  }
}

【问题讨论】:

  • 这不是错误。星期几取决于您的环境的区域设置。 en_US 将一周的第一天设置为星期日。重复:stackoverflow.com/questions/269486/…
  • 我改变了一周的第一天...
  • 我认为一周的第一天与实际最小值不同。你有 getFirstDayOfWeek() 方法。

标签: java calendar


【解决方案1】:

您应该使用 cal.getFirstDayOfWeek() 代替 cal.getActualMinimum(Calendar.DAY_OF_WEEK)

因为 cal.getActualMinimum(Calendar.DAY_OF_WEEK) 会一直返回 sunday 查看getActualMinimum(Calendar.DAY_OF_WEEK) 在java源码中的实现

  public int getActualMinimum(int field) {
        if (field == DAY_OF_MONTH) {
            GregorianCalendar gc = getNormalizedCalendar();
            int year = gc.cdate.getNormalizedYear();
            if (year == gregorianCutoverYear || year == gregorianCutoverYearJulian) {
                long month1 = getFixedDateMonth1(gc.cdate, gc.calsys.getFixedDate(gc.cdate));
                BaseCalendar.Date d = getCalendarDate(month1);
                return d.getDayOfMonth();
            }
        }
        return getMinimum(field);
    }

而 getMinimum 是:-

   public int getMinimum(int field) {
        return MIN_VALUES[field];
    }

和 MIN_VALUES 数组定义为:-

 static final int MIN_VALUES[] = {
        BCE,            // ERA
        1,              // YEAR
        JANUARY,        // MONTH
        1,              // WEEK_OF_YEAR
        0,              // WEEK_OF_MONTH
        1,              // DAY_OF_MONTH
        1,              // DAY_OF_YEAR
        SUNDAY,         // DAY_OF_WEEK
        1,              // DAY_OF_WEEK_IN_MONTH
        AM,             // AM_PM
        0,              // HOUR
        0,              // HOUR_OF_DAY
        0,              // MINUTE
        0,              // SECOND
        0,              // MILLISECOND
        -13*ONE_HOUR,   // ZONE_OFFSET (UNIX compatibility)
        0               // DST_OFFSET
    };

【讨论】:

  • 好的,我正在考虑将最小值作为滚动的值,而不仅仅是你可以通过 get/set 获得的值。
【解决方案2】:

Answer by K M PATEL 是正确的。

问题和答案都使用过时的类。与最早版本的 Java 捆绑在一起的旧日期时间类已被 java.time 类所取代。

标准定义

DayOfWeekenum 根据ISO 8601 标准定义一周,Monday 为 1,Sunday 为 7。

您可以向DayOfWeek 对象询问这个 1-7 的数字。

int dayOfWeekNumber = DayOfWeek.WEDNESDAY.getValue();

但不要在您的代码周围传递此数字。而是传递DayOfWeek 对象以享受type-safety 的好处并保证有效值。

本地化定义

对于星期几、星期几和星期几字段的本地化定义,请使用 WeekFields 类。

WeekFields weekFields_US = WeekFields.of ( Locale.US );
DayOfWeek firstDayOfWeek = weekFields_US.getFirstDayOfWeek ();

转储到控制台。

System.out.println ( "weekFields_US: " + weekFields_US + " | firstDayOfWeek: " + firstDayOfWeek );

weekFields_US: WeekFields[SUNDAY,1] | firstDayOfWeek:星期日

定义您自己的周变化

我建议坚持指定Locale 对象来定义星期。但如果你坚持,你可以定义自己的一周变化。致电 WeekFields.of 并指定 (a) 一周的第一天,以及 (b) 定义一年中的第一周或一个月的第一周的最少天数。

首先,为了比较,使用 IsoFields 类中包含的标准 ISO 8601 定义获取星期几。

// Using standard IsoFields.
LocalDate localDate = LocalDate.of ( 2016 , 2 , 3 ); // Feb 3 2016 = Wednesday
DayOfWeek dow = DayOfWeek.from ( localDate );
int ordinalNumberDayOfWeek = dow.getValue ();

转储到控制台。

System.out.println ( "localDate: " + localDate + " | dow: " + dow + " | ordinalNumberDayOfWeek: " + ordinalNumberDayOfWeek );

本地日期:2016-02-03 |道琼斯指数:星期三 | ordinalNumberDayOfWeek: 3

现在切换到定义我们自己的WeekFields 对象,并再次询问星期几。上面我们看到了3,因为 2016 年 2 月 3 日是星期三,所以 Monday-Tuesday-Wednesday 呈现一个三。下面我们看到4 因为周日-周一-周二-周三。

// Define our own WeekFields to use in place of IsoFields.
WeekFields weekFields_SUNDAY_1 = WeekFields.of ( DayOfWeek.SUNDAY , 1 );
int ordinalNumberDayOfWeek_SundayBasedWeek = localDate.get ( weekFields_SUNDAY_1.dayOfWeek () );

转储到控制台。

System.out.println ( "ordinalNumberDayOfWeek_SundayBasedWeek: " + ordinalNumberDayOfWeek_SundayBasedWeek );

ordinalNumberDayOfWeek_SundayBasedWeek:4

(示例基于 JodaStephen 的 this Answer


查看类似问题,java get week of year for given a date


关于java.time

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

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

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

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

从哪里获取 java.time 类?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-26
    • 1970-01-01
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多