我正在尝试从某个季度获得月数。使用下面的代码,我从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++;
}
我们可以通过查看getFrom
的IsoFields.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());
}
我建议我们构建每个季度包含的月份的地图,并在需要某个季度字符串的月份时进行简单的地图查找。流管道和适当的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行,我看不到任何增益。
对于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
使用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.
一月
YearQuarter
]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
如果使用数字而不是字符串,即Q1
或valueOf
或valueOf
或String 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
日期时间类,例如Month
,Month
和LocalDate 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类? SimpleDateFormat
,SimpleDateFormat
,Oracle Tutorial,JSR 310和更高版本-具有捆绑实施的标准Java API的一部分。