如何获得给定季度的月份

问题描述 投票:2回答:4

我正在尝试从某个季度获得月数。使用下面的代码,我从LocalDate.now()实例成功获取了当前季度的月份名称。

我怎么会从四分之一的String(例如“ Q1”)中得到四分之一的月?

int monthInt = Month.from(LocalDate.now()).firstMonthOfQuarter().getValue();
      for (int j = 1; j <= 3; j++) { //for each month in quarter
          System.out.println(Month.of(monthInt).name()); //January, February, March
          monthInt++;
      }
java date java-time localdate java-date
4个回答
1
投票

我们可以通过查看getFromIsoFields.QUARTER_OF_YEAR声明来了解JDK如何计算季度:

public long getFrom(TemporalAccessor temporal) {
    if (isSupportedBy(temporal) == false) {
        throw new UnsupportedTemporalTypeException("Unsupported field: QuarterOfYear");
    }
    long moy = temporal.getLong(MONTH_OF_YEAR);
    return ((moy + 2) / 3);
}

注意它如何使用公式quarter = (moy + 2) / 3。因此,要查找一个季度的开始月份,我们只需要按照moy-moy = quarter * 3 - 2进行重新排列。

您可以编写这样的方法:

private static List<String> monthNamesFromQuarter(int quarter) {
    // you can do the validation of quarter yourself
    int start = quarter * 3 - 2;
    return IntStream.range(start, start + 3)
            .mapToObj(Month::of)
            .map(Month::name)
            .collect(Collectors.toList());
}

2
投票

我建议我们构建每个季度包含的月份的地图,并在需要某个季度字符串的月份时进行简单的地图查找。流管道和适当的DateTimeFormatter只需几行即可构建这样的地图:

static Map<String, List<Month>> monthsPerQuarter = Arrays.stream(Month.values())
        .collect(Collectors.groupingBy(
                DateTimeFormatter.ofPattern("QQQ", Locale.ENGLISH)::format));

IMO的最大优点是我们不需要自己做数学。尽管数学从四分之一数字转换为月数字对于编写它的人来说似乎很简单,但它不仅容易出错,而且对于许多读者来说也不清楚并且难以解读。

现在我们可以像这样查找示例:

    System.out.println(monthsPerQuarter.get("Q3"));

输出为:

[JULY, AUGUST, SEPTEMBER]

如果您需要单独的月份:

    monthsPerQuarter.get("Q4").forEach(System.out::println);
OCTOBER
NOVEMBER
DECEMBER

如果您的季度原来是一个介于1到4之间的数字,则可以改用此地图:

static Map<Integer, List<Month>> monthsPerQuarter = Arrays.stream(Month.values())
        .collect(Collectors.groupingBy(m -> m.get(IsoFields.QUARTER_OF_YEAR)));

我推荐使用map方法的原因是:从Month转换为四分之一字符串很容易,但是java.time没有提供从四分之一字符串转换为月份的简单方法。仅出于演示目的,而不是我建议的方式,您可以这样做:

    DateTimeFormatter quarterFormatter = new DateTimeFormatterBuilder()
            .appendPattern("QQQ")
            // Any year will do since all years have the same 4 quarters @ the same 3 months
            .parseDefaulting(ChronoField.YEAR, 2000)
            .parseDefaulting(IsoFields.DAY_OF_QUARTER, 1)
            .toFormatter(Locale.ENGLISH);

    String qString = "Q1";
    Month firstMonthOfQuarter = Month.from(quarterFormatter.parse(qString));
    IntStream.range(0, 3)
            .mapToObj(firstMonthOfQuarter::plus)
            .forEach(System.out::println);
JANUARY
FEBRUARY
MARCH

它是11行代码,而不是4行,我看不到任何增益。


1
投票

对于quarter > firstmonth,规则是

Q1 -> 1
Q2 -> 4
Q3 -> 7
Q4 -> 10

With math : quarterValue *3 -2

因此在Java中应用它:

String quarter = "Q1";
int monthInt = Integer.parseInt(quarter.replaceAll("\\D", "")) * 3 - 2;
for (int j = 0; j < 3; j++) {
    System.out.println(Month.of(monthInt + j).name());
}

List<String> quarters = Arrays.asList("Q1", "Q2", "Q3", "Q4");
for (String quarter : quarters) {
    System.out.print(quarter);
    int monthInt = Integer.parseInt(quarter.replaceAll("\\D", "")) * 3 - 2;
    for (int j = 0; j < 3; j++) {
        System.out.print(" " + Month.of(monthInt + j).name());
    }
    System.out.println();
}

Q1 JANUARY FEBRUARY MARCH
Q2 APRIL MAY JUNE
Q3 JULY AUGUST SEPTEMBER
Q4 OCTOBER NOVEMBER DECEMBER

0
投票

tl; dr

使用org.threeten.extra.YearQuarter类。

YearQuarter                         // Represent an entire quarter of a specific year.
.now( ZoneId.of( "Asia/Tokyo" ) )   // Determine the current quarter as seen via the wall-clock time used by the people of a particular region (a time zone). 
.with(                              // Move to another quarter.
    Quarter.valueOf( "Q1" )         // Or, `Quarter.of( 1 )` if starting with an integer number rather than a `String` object.
)                                   // Returns another `YearQuarter` object, rather than modifying the original.
.atDay( 1 )                         // Returns a `LocalDate` object.
.getMonth()                         // Returns a `Month` enum object.
.getDisplayName(                    // Automatically localize the name of the month. 
    TextStyle.FULL ,                // How long or abbreviated do you want the translation.
    Locale.US                       // Or Locale.CANADA_FRENCH and so on. 
)                                   // Returns a `String` object.

一月

[[TenTen-Extra中的[YearQuarter]

ThreeTen-Extra库中有一个可能对您的工作有用的类:YearQuarter

获取当前季度。我们需要一个时区来确定当前日期,从而确定当前季度。在任何给定时刻,日期都会随时区在全球范围内变化。

YearQuarter

但是您想通过分析字符串来确定四分之一。

如果您的字符串风格类似于ZoneId z = ZoneId.of( "Africa/Tunis" ) ; YearQuarter currentYearQuarter = YearQuarter.now( z ) ; (标准实际上并未指定四分之一),则ISO 8601可以YYYY-Qq

YearQuarter

如果您只有四分之一部分而没有年份,请使用directly parse枚举。如果您输入的字符串是String input = "2020-Q1" ;
YearQuarter yearQuarter = YearQuarter.parse( input ) ;
等,请使用Quarter检索匹配的枚举对象。 

Quarter

如果使用数字而不是字符串,即Q1valueOfvalueOfString input = "Q1" ;
Quarter quarter = Quarter.valueOf( input ) ;
,则使用静态方法1。顺便说一句,在您自己的代码中,您应该传递这些2对象,而不仅仅是一个整数或字符串,以使您的代码更具自记录性,提供类型安全性并确保有效值。

3

将那个4实例应用于我们当前的Quarter.of实例以获得另一个Quarter实例。这些类使用int input = 1 ; // Domain: 1, 2, 3, 4. 
Quarter quarter = Quarter.of( input ) ;
模式,因此我们不修改现有实例,而是生成新实例。

Quarter

yearQuarter.toString():2019-Q1

从该年季度开始获取第一个日期(YearQuarter),年月(YearQuarter)和immutable objects枚举对象。

YearQuarter yearQuarter = currentYearQuarter.with( quarter ) ;

生成包含月份的LocalDate名称的字符串。

LocalDate

一月


关于

java.time

YearMonth框架内置于Java 8及更高版本中。这些类取代了麻烦的旧YearMonth日期时间类,例如MonthMonthLocalDate firstDate = yearQuarter.atDay( 1 ) ; YearMonth yearMonth1 = YearMonth.from( firstDate ) ; YearMonth yearMonth2 = yearMonth1.plusMonths( 1 ) ; YearMonth yearMonth3 = yearMonth1.plusMonths( 2 ) ;

要了解更多信息,请参见automatically localized。并在Stack Overflow中搜索许多示例和说明。规格为Locale locale = Locale.US ; // Or Locale.CANADA_FRENCH and so on. String output1 = yearMonth1.getMonth().getDisplayName( TextStyle.FULL , locale ) ;

java.time项目现在位于legacy中,建议迁移到java.util.Date类。

您可以直接与数据库交换

java.time

对象。使用兼容java.util.Date或更高版本的Calendar。不需要字符串,不需要Calendar类。从哪里获取java.time类?

  • [Joda-Timemaintenance mode
    • << java.time的大多数功能>在java.time中被反向移植到Java 6和7。
  • JDBC driver
  • [[java.time
  • 类的Android捆绑包实现的最新版本。
      对于较早的Android(<26),JDBC 4.2项目改编为java.sql.*(如上所述)。参见Java SE 8
  • Java SE 9项目使用其他类扩展了java.time。该项目为将来可能向java.time添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Java SE 10Java SE 11Java SE 6Java SE 7
  • © www.soinside.com 2019 - 2024. All rights reserved.