如何在Scala中获取上一年的相应季度

How to get corresponding quarter of previous year in Scala

我有一个格式为“20202”[“yyyyQ”] 的日期字符串。有没有办法得到上一年对应的季度?

ex- 20202 应该是 20192

这是一个简短的 Scastie 展示了一种方法。

val d = "20202"
(d.substring(0,4).toInt - 1).toString + d.substring(4)  // 20192: String

更新(感谢

下面给出的是纯粹的DateTimeFormatter解决方案:

import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.IsoFields;

import org.threeten.extra.YearQuarter;

public class Main {
    public static void main(String[] args) {
        // Given string
        String str = "20202";

        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                                .appendValue(ChronoField.YEAR, 4)
                                .appendValue(IsoFields.QUARTER_OF_YEAR, 1)
                                .toFormatter();

        // Parse the converted string
        YearQuarter yearQuarter = YearQuarter.parse(str, dtf);
        System.out.println(yearQuarter.format(dtf));

        // A year ago
        System.out.println(yearQuarter.minusYears(1).format(dtf));
    }
}

输出:

20202
20192

原回答:

我建议您使用 ThreeTenExtra 库。您必须处理的唯一问题是将给定的字符串转换为 yyyy-Q 格式,您可以使用正则表达式轻松完成此操作,如下所示:

import java.time.format.DateTimeFormatter;

import org.threeten.extra.YearQuarter;

public class Main {
    public static void main(String[] args) {
        // Given string
        String str = "20202";

        // Convert the given string into yyyy-Q format
        str = str.replaceAll("(\d{4})(\d{1,2})", "-");

        // Parse the converted string
        YearQuarter yearQuarter = YearQuarter.parse(str, DateTimeFormatter.ofPattern("yyyy-Q"));

        // Define output format
        DateTimeFormatter outputFormat = DateTimeFormatter.ofPattern("uuuuQ");
        System.out.println(yearQuarter.format(outputFormat));

        // A year ago
        System.out.println(yearQuarter.minusYears(1).format(outputFormat));
    }
}

输出:

20202
20192

正则表达式的解释:

  1. (\d{4})(\d{1,2}) 指定两组:第一组有 4 个数字,第二组有一个或两个数字
  2. 替换字符串-指定group(1)-group(2)

I thought of using some Date time formatter to solve this, …

做!我会立即更喜欢 Arvind Kumar Avinash 使用 ThreeTen Extra 库的 YearQuarter 的解决方案。如果您发现将外部库添加到您的项目(或者您的团队或老板这么认为)是多余的,我们也可以不用它,只是不太优雅。这是一个 Java 解决方案,我认为您可以将其翻译成 Scala:

    DateTimeFormatter quarterFormatter = new DateTimeFormatterBuilder()
            .appendValue(ChronoField.YEAR, 4)
            .appendValue(IsoFields.QUARTER_OF_YEAR, 1)
            .parseDefaulting(IsoFields.DAY_OF_QUARTER, 1)
            .toFormatter();
    
    String quarterString = "20202";
    
    YearMonth firstMonthOfQuarter
            = YearMonth.parse(quarterString, quarterFormatter);
    YearMonth firstMonthOfQuarterLastYear = firstMonthOfQuarter.minusYears(1);
    String quarterPreviousYearString
            = firstMonthOfQuarterLastYear.format(quarterFormatter);
    
    System.out.println(quarterPreviousYearString);

输出是期望的:

20192

正确数据类型的优点

Could you please explain what advantages usage of DateTime may have in this case over simple string manipulation and conversion to int?

编辑:当您需要从输入中读取一些数字(例如 ID 号)并在输出中再次打印时,您是将其读入 int 还是 String?大多数使用int(或longBigInteger)。为什么?你的问题类似。

使用 YearQuarterYearMonth 的优势包括(可能不限于):

  • Self-explanatory 代码: val d = "20202" 并没有说明这段数据的含义。 YearQuarter 类型的变量非常清楚地告诉 reader 这个变量保存一年的四分之一。 YearMonth 是标准 Java 库中的最佳近似值,并且已经不太清楚为什么我们在这里使用它,但仍然比 String.
  • 有很大的优势
  • 免费验证: 通过使用格式化程序解析字符串,如果字符串不表示有效的季度,我们一定会通过异常得到通知.
  • 进一步验证便宜:如果您想要进一步验证,例如该季度必须在 2019 年第二季度之后,但不能在未来,这很简单直接 java.time(它也可以用字符串来完成,但是代码将很难阅读,除非你用几行注释解释你要做什么)。
  • 为未来的需求做好准备:如果有一天你需要对这个季度做更多的事情,比如找到这个季度的第一天和最后一天或前一个季度它,这将是在公园散步,因为 class 提供了一组非常丰富的操作。

Link

Oracle tutorial: Date Time 解释如何使用 java.time.

其他答案的替代方法是使用我的库 Time4J and its class CalendarQuarter。示例:

    String input = "20202";

    ChronoFormatter<CalendarQuarter> f =
        ChronoFormatter.ofPattern(
            "yyyyQ", 
            PatternType.CLDR, 
            Locale.ENGLISH, 
            CalendarQuarter.chronology());
    CalendarQuarter cq = f.parse(input);
    CalendarQuarter quarterInPreviousYear = cq.minus(Years.ONE);
    System.out.println(quarterInPreviousYear); // 2019-Q2

此解决方案的两个主要优点是:

  • 日历季度也是间隔,因此很容易每天对其进行迭代。
  • 支持 90 多种语言的国际化,甚至 style-based。

间隔示例:

    for (PlainDate date : quarterInPreviousYear) {
        System.out.println(date);
    }

输出:

> 2019-04-01 
> 2019-04-02 
> 2019-04-03
> ...

丹麦语打印示例:

    ChronoFormatter<CalendarQuarter> printer =
        ChronoFormatter.ofPattern(
            "QQQQ y", 
            PatternType.CLDR, 
            new Locale("da"), 
            CalendarQuarter.chronology());
    System.out.println(printer.print(quarterInPreviousYear)); // 2. kvartal 2019