sdmxdl.util.parser.PeriodParsers Maven / Gradle / Ivy
package sdmxdl.util.parser;
import nbbrd.io.text.Parser;
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.nullness.qual.NonNull;
import sdmxdl.Frequency;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@lombok.experimental.UtilityClass
public class PeriodParsers {
@NonNull
public Parser onStandardFreq(@NonNull Frequency freq) {
switch (freq) {
case ANNUAL:
return ANNUAL;
case HALF_YEARLY:
return HALF_YEARLY;
case QUARTERLY:
return QUARTERLY;
case MONTHLY:
return MONTHLY;
case WEEKLY:
return WEEKLY;
case DAILY:
return DAILY;
case HOURLY:
return HOURLY;
case DAILY_BUSINESS:
return DAILY_BUSINESS;
case MINUTELY:
return MINUTELY;
case UNDEFINED:
return UNDEFINED;
default:
throw new RuntimeException();
}
}
private final Parser YEAR_MONTH = onDatePattern("yyyy-MM");
private final Parser YEAR_MONTH_DAY = onDatePattern("yyyy-MM-dd");
private final Parser ANNUAL = onDatePattern("yyyy").orElse(onDatePattern("yyyy'-01'")).orElse(onDatePattern("yyyy'-A1'"));
private final Parser HALF_YEARLY = onYearFreqPos("S", 2).orElse(YEAR_MONTH);
private final Parser QUARTERLY = onYearFreqPos("Q", 4).orElse(YEAR_MONTH);
private final Parser MONTHLY = onYearFreqPos("M", 12).orElse(YEAR_MONTH);
private final Parser WEEKLY = YEAR_MONTH_DAY;
private final Parser DAILY = YEAR_MONTH_DAY;
// FIXME: needs other pattern for time
private final Parser HOURLY = YEAR_MONTH_DAY;
private final Parser DAILY_BUSINESS = YEAR_MONTH_DAY;
private final Parser MINUTELY = YEAR_MONTH_DAY;
private final Parser UNDEFINED = YEAR_MONTH;
@NonNull
public Parser onDatePattern(@NonNull String pattern) {
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern(pattern)
.parseStrict()
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.toFormatter(Locale.ROOT);
return Parser.onDateTimeFormatter(formatter, LocalDateTime::from);
}
@NonNull
public Parser onYearFreqPos(@NonNull String freqCode, @NonNegative int freq) {
return new YearFreqPos(freqCode, freq);
}
private static final class YearFreqPos implements Parser {
private final Pattern regex;
private final int freq;
public YearFreqPos(String freqCode, int freq) {
this.regex = Pattern.compile("(\\d+)-?" + freqCode + "(\\d+)");
this.freq = freq;
}
@Override
public LocalDateTime parse(CharSequence input) {
if (input == null) {
return null;
}
Matcher m = regex.matcher(input);
return m.matches() ? toDate(Integer.parseInt(m.group(1)), freq, Integer.parseInt(m.group(2)) - 1) : null;
}
private LocalDateTime toDate(int year, int freq, int pos) {
return ((pos < 0) || (pos >= freq)) ? null : LocalDate.of(year, pos * (12 / freq) + 1, 1).atStartOfDay();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy