【问题标题】:How to get corresponding quarter of previous year in Scala如何在Scala中获得上一年的相应季度
【发布时间】:2021-02-04 09:48:39
【问题描述】:

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

ex- 20202 应该是 20192

【问题讨论】:

  • d.take(4).toInt - 1 + "" + d(4)。如果那个讨厌的" 困扰你:s"${d.take(4).toInt - 1}${d(4)}"
  • 我想用一些日期时间格式化程序来解决这个问题,但是这个可以达到目的:) 谢谢!!! :)
  • ThreeTen Extra 项目有一个 YearQuarter 类正好适合您的目的。

标签: java scala date apache-spark localdate


【解决方案1】:

其他答案的替代方法是使用我的库Time4J 及其类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 多种语言的国际化,甚至基于样式。

间隔示例:

    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

【讨论】:

  • Meno Hochschild - 我们大多数人都在 SO 上从你那里学到了一些关于日期时间主题的东西。我刚刚测试了你的功能丰富的库,它就像一个魅力。
  • System.out.println(quarterInPreviousYear); 之后添加System.out.println(f.format(quarterInPreviousYear)); 对初学者会有帮助。
  • @ArvindKumarAvinash 感谢您的反馈。表达式System.out.println(quarterInPreviousYear); 间接使用了toString() 方法,该方法产生了类似ISO 的样式(“2019-Q2”)。但当然,使用格式化程序进行打印更灵活。
  • 谢谢这个:)
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    更新(感谢Ole V.V.

    下面给出的是纯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})", "$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. 替换字符串$1-$2 指定group(1)-group(2)

    【讨论】:

    • @OleV.V. - 感谢您的反馈。我曾尝试过DateTimeFormatter.ofPattern("yyyyQ"),但它不起作用,因此我不得不使用正则表达式进行替换。我已更新答案以纳入您的第二个建议。
    • 模式 yyyyQ 将在我的 lib Time4J 中工作,请参阅我的答案。
    【解决方案4】:

    我想用一些日期时间格式化程序来解决这个问题,...

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

        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

    正确数据类型的优势

    您能否解释一下使用 DateTime 可能有哪些优势? 这种情况下简单的字符串操作和转换为int?

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

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

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

    链接

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

    【讨论】:

    • 哇!这是纯粹使用 Java-8 的绝佳解决方案。
    • 恕我直言,不是很好,@ArvindKumarAvinash,但可行。不管怎样,谢谢你!我最近在工作中做了类似的事情,以逃避说服 10 名队友添加 ThreeTen Extra 的麻烦,但在编写代码后,我不再确定我在那里做出了正确的决定。
    • 您能否解释一下在这种情况下使用 DateTime 相对于简单的字符串操作和转换为 int 有哪些优势?
    • 感谢 Ole 和 Arvind。但正如@jrook 所问的那样有什么特别的优势
    • @jrook - 使用日期时间 API 的优点是您可以使用日期时间操作的所有功能,例如如果您想添加/减去月、年、日等,或者您想处理时区信息等。当您进行简单的字符串操作和转换为 int 时,您将永远无法获得这些东西。
    猜你喜欢
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 2016-07-29
    • 2018-10-19
    • 2016-12-31
    • 1970-01-01
    • 2020-04-28
    • 2021-12-26
    相关资源
    最近更新 更多