Skip to content

Commit

Permalink
[WIP]
Browse files Browse the repository at this point in the history
  • Loading branch information
vkhrystiuk-ks committed Dec 18, 2024
1 parent aeab22e commit 428f1f3
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 64 deletions.
5 changes: 2 additions & 3 deletions src/main/java/liqp/LValue.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package liqp;

import static liqp.filters.date.Parser.getZonedDateTimeFromTemporalAccessor;
import static liqp.filters.date.Parser.getFullDateIfPossible;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -214,7 +213,7 @@ public static TemporalAccessor asTemporal(Object value, TemplateContext context)
public static ZonedDateTime asRubyDate(Object value, TemplateContext context) {
ZonedDateTime time = ZonedDateTime.now();
if (value instanceof TemporalAccessor) {
time = getZonedDateTimeFromTemporalAccessor((TemporalAccessor) value, context.getParser().defaultTimeZone);
time = getFullDateIfPossible((TemporalAccessor) value, context.getParser().defaultTimeZone);
} else if (CustomDateFormatRegistry.isCustomDateType(value)) {
time = CustomDateFormatRegistry.getFromCustomType(value);
}
Expand Down
62 changes: 48 additions & 14 deletions src/main/java/liqp/filters/date/BasicDateParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQueries;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Function;

import static java.time.temporal.ChronoField.*;

Expand All @@ -35,7 +38,7 @@ protected ZonedDateTime parseUsingCachedPatterns(String str, Locale locale, Zone
for(String pattern : cachedPatterns) {
try {
TemporalAccessor temporalAccessor = parseUsingPattern(str, pattern, locale);
return getZonedDateTimeFromTemporalAccessor(temporalAccessor, defaultZone);
return getFullDateIfPossible(temporalAccessor, defaultZone);
} catch (Exception e) {
// ignore
}
Expand All @@ -55,10 +58,10 @@ protected TemporalAccessor parseUsingPattern(String normalized, String pattern,


/**
* Follow ruby rules: if some datetime part is missing,
* the default is taken from `now` with default zone
* Follow ruby rules: if some datetime part is missing, the default is taken from `now` with
* default zone
*/
public static ZonedDateTime getZonedDateTimeFromTemporalAccessor(TemporalAccessor temporal, ZoneId defaultZone) {
public static ZonedDateTime getFullDateIfPossible(TemporalAccessor temporal, ZoneId defaultZone) {
if (temporal == null) {
return ZonedDateTime.now(defaultZone);
}
Expand All @@ -68,13 +71,6 @@ public static ZonedDateTime getZonedDateTimeFromTemporalAccessor(TemporalAccesso
if (temporal instanceof Instant) {
return ZonedDateTime.ofInstant((Instant) temporal, defaultZone);
}

ZoneId zoneId = temporal.query(TemporalQueries.zone());
if (zoneId == null) {
zoneId = defaultZone;
}

LocalDateTime now = LocalDateTime.now(zoneId);
TemporalField[] copyThese = new TemporalField[]{
YEAR,
MONTH_OF_YEAR,
Expand All @@ -84,11 +80,49 @@ public static ZonedDateTime getZonedDateTimeFromTemporalAccessor(TemporalAccesso
SECOND_OF_MINUTE,
NANO_OF_SECOND
};


ZoneId zoneId = temporal.query(TemporalQueries.zone());
if (zoneId == null) {
zoneId = defaultZone;
}

final LocalDateTime now = LocalDateTime.now(zoneId);

if ("java.time.format.Parsed".equals(temporal.getClass().getName())) {
Map<TemporalField, Function<TemporalAccessor, LocalDateTime>> factories = new HashMap<>();
factories.put(DAY_OF_WEEK, t -> now.with(TemporalAdjusters.previousOrSame(DayOfWeek.from(t))));
TemporalAccessor onlyField = onlyField(temporal, factories, copyThese);
if (onlyField != null) {
return getFullDateIfPossible(onlyField, zoneId);
}
}


LocalDateTime res = now.with(TemporalAdjusters.ofDateAdjuster(date -> date));
for (TemporalField tf: copyThese) {
if (temporal.isSupported(tf)) {
now = now.with(tf, temporal.get(tf));
res = res.with(tf, temporal.get(tf));
}
}
return now.atZone(zoneId);
return res.atZone(zoneId);
}

private static TemporalAccessor onlyField(TemporalAccessor temporal, Map<TemporalField, Function<TemporalAccessor, LocalDateTime>> factories,
TemporalField[] butThese) {
if (factories == null || factories.isEmpty()) {
return null;
}
for (TemporalField tf: butThese) {
if (temporal.isSupported(tf)) {
return null;
}
}
for (Map.Entry<TemporalField, Function<TemporalAccessor, LocalDateTime>> entry: factories.entrySet()) {
if (temporal.isSupported(entry.getKey())) {
return entry.getValue().apply(temporal);
}
}
return null;
}
}
8 changes: 4 additions & 4 deletions src/main/java/liqp/filters/date/fuzzy/FuzzyDateParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ public ZonedDateTime parse(String normalized, Locale locale, ZoneId defaultZone)
if (defaultZone == null) {
defaultZone = ZoneId.systemDefault();
}
ZonedDateTime zonedDateTime = parseUsingCachedPatterns(normalized, locale, defaultZone);
if (zonedDateTime != null) {
return zonedDateTime;
ZonedDateTime date = parseUsingCachedPatterns(normalized, locale, defaultZone);
if (date != null) {
return date;
}

String pattern = guessPattern(normalized, locale);
Expand All @@ -58,7 +58,7 @@ public ZonedDateTime parse(String normalized, Locale locale, ZoneId defaultZone)
return null;
}
storePattern(pattern);
return getZonedDateTimeFromTemporalAccessor(temporalAccessor, defaultZone);
return getFullDateIfPossible(temporalAccessor, defaultZone);
}

String guessPattern(String normalized, Locale locale) {
Expand Down
13 changes: 9 additions & 4 deletions src/main/java/liqp/filters/date/fuzzy/PartRecognizer.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package liqp.filters.date.fuzzy;

import static liqp.LValue.isBlank;
import static liqp.filters.date.fuzzy.extractors.Extractors.ISO8601YMDPatternExtractor;
import static liqp.filters.date.fuzzy.extractors.Extractors.englishDateExtractor;
import static liqp.filters.date.fuzzy.extractors.Extractors.fullMonthExtractor;
import static liqp.filters.date.fuzzy.extractors.Extractors.fullWeekdaysExtractor;
import static liqp.filters.date.fuzzy.extractors.Extractors.plainYearExtractor;
Expand All @@ -11,13 +11,11 @@
import static liqp.filters.date.fuzzy.extractors.Extractors.yearWithEraExtractor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import liqp.filters.date.fuzzy.Part.NewPart;
import liqp.filters.date.fuzzy.Part.PunctuationPart;
import liqp.filters.date.fuzzy.Part.RecognizedPart;
import liqp.filters.date.fuzzy.Part.NewPart;
import liqp.filters.date.fuzzy.Part.UnrecognizedPart;
import liqp.filters.date.fuzzy.extractors.PartExtractorResult;

Expand Down Expand Up @@ -64,6 +62,13 @@ List<Part> recognizePart(List<Part> parts, DatePatternRecognizingContext ctx) {
ctx.hasDay = true;
return result.parts;
}
result = lookup(parts, englishDateExtractor.get(ctx.locale));
if (result.found) {
ctx.hasYear = true;
ctx.hasMonth = true;
ctx.hasDay = true;
return result.parts;
}
}

if (notSet(ctx.hasYear)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package liqp.filters.date.fuzzy.extractors;

import java.util.regex.Matcher;

class EnglishDMYPatternExtractor extends RegexPartExtractor {
public EnglishDMYPatternExtractor() {
super("(?:^|.*?\\D)"
+ "(?<day>0?[1-9]|[12][0-9]|3[01])"
+ "/"
+ "(?<month>0?[1-9]|1[0-2])"
+ "/"
+ "(?<year>\\d{2}|\\d{4})"
+ "(?:$|\\D.*?)", null);
}


@Override
public PartExtractorResult extract(String source) {
Matcher matcher = pattern.matcher(source);
if (matcher.find()) {
PartExtractorResult result = new PartExtractorResult();
result.found = true;
result.start = matcher.start("day");
result.end = matcher.end("year");
result.formatterPattern = getPattern(matcher);
return result;
}
return new PartExtractorResult();
}

private String getPattern(Matcher matcher) {
StringBuilder sbfp = new StringBuilder();
if (matcher.group("day").length() == 1) {
sbfp.append("d");
} else {
sbfp.append("dd");
}
sbfp.append("/");
if (matcher.group("month").length() == 1) {
sbfp.append("M");
} else {
sbfp.append("MM");
}
sbfp.append("/");
if (matcher.group("year").length() == 2) {
sbfp.append("yy");
} else {
sbfp.append("yyyy");
}
return sbfp.toString();
}
}
18 changes: 13 additions & 5 deletions src/main/java/liqp/filters/date/fuzzy/extractors/Extractors.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,25 @@ public PartExtractor get(Locale locale) {
*
*/
ISO8601YMDPatternExtractor {
private final PartExtractor partExtractor = new RegexPartExtractor("(?:^|.*?\\D)"
+ "(\\d{4}-\\d{2}-\\d{2})"
+ "(?:$|\\D.*?)", "yyyy-MM-dd");
private final PartExtractor partExtractor = new ISO8601YMDPatternExtractor();
@Override
public PartExtractor get(Locale locale) {
return partExtractor;
}
}
},

englishDateExtractor {
private final PartExtractor partExtractor = new EnglishDMYPatternExtractor();
@Override
public PartExtractor get(Locale locale) {
return partExtractor;
}
},
;

public abstract PartExtractor get(Locale locale);
//

//
// /**
// * [Mon, ]17 Sep 2019 12:34[:56] [+HHMM/GMT]
// * weekDay is optional
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package liqp.filters.date.fuzzy.extractors;

import java.util.regex.Matcher;

class ISO8601YMDPatternExtractor extends RegexPartExtractor {

public ISO8601YMDPatternExtractor() {
super("(?:^|.*?\\D)"
+ "(?<year>\\d{4})-(?<month>0?[1-9]|1[0-2])-(?<date>0?[1-9]|[12][0-9]|3[01])"
+ "(?:$|\\D.*?)", null);
}

@Override
public PartExtractorResult extract(String source) {
Matcher matcher = pattern.matcher(source);
if (matcher.find()) {
PartExtractorResult result = new PartExtractorResult();
result.found = true;
result.start = matcher.start("year");
result.end = matcher.end("date");
result.formatterPattern = getPattern(matcher);
return result;
}
return new PartExtractorResult();
}

private String getPattern(Matcher matcher) {
StringBuilder sbfp = new StringBuilder("yyyy");
sbfp.append("-");
if (matcher.group("month").length() == 1) {
sbfp.append("M");
} else {
sbfp.append("MM");
}
sbfp.append("-");
if (matcher.group("date").length() == 1) {
sbfp.append("d");
} else {
sbfp.append("dd");
}
return sbfp.toString();
}
}
Loading

0 comments on commit 428f1f3

Please sign in to comment.