Skip to content

Commit

Permalink
[WIP]
Browse files Browse the repository at this point in the history
  • Loading branch information
msangel committed Jan 5, 2025
1 parent b14efe5 commit 0931d5f
Show file tree
Hide file tree
Showing 21 changed files with 432 additions and 170 deletions.
11 changes: 10 additions & 1 deletion ruby/cases_date.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,18 @@
# assertEqual("", render({"null" => "bad"}, "{{null}}"))
# assertEqual("", render({"empty" => "bad"}, "{{empty}}"))
# assertEqual("", render({"blank" => "bad"}, "{{blank}}"))
assertEqual("2007-11-01...", render({"a" => t }, "{{ a | truncate: 13 }}"))
# assertEqual("2007-11-01...", render({"a" => t }, "{{ a | truncate: 13 }}"))

if isJekyll
pp render({"a" => '2004-12-31'}, "{{ a | date: '%Y-%m-%d %H:%M:%S %z'}}") # "2004-12-31 00:00:00 +0200"
pp render({"a" => '31 December'}, "{{ a | date: '%Y-%m-%d %H:%M:%S %z'}}") # "2025-12-31 00:00:00 +0200"
pp render({"a" => '12:00'}, "{{ a | date: '%Y-%m-%d %H:%M:%S %z'}}") # "2025-01-04 12:00:00 +0200"
pp render({"a" => 'Friday'}, "{{ a | date: '%Y-%m-%d %H:%M:%S %z'}}") # Friday
pp render({"a" => 'Friday 12/24'}, "{{ a | date: '%Y-%m-%d %H:%M:%S %z'}}") # "2025-12-24 00:00:00 +0200"
pp render({"a" => '2004-12-31 11:23:58 Z'}, "{{ a | date: '%Y-%m-%d %H:%M:%S %z'}}") # "2004-12-31 11:23:58 +0000"
pp render({"a" => 'September 1969'}, "{{ a | date: '%Y-%m-%d %H:%M:%S %z'}}") # "1969-09-01 00:00:00 +0300"
pp render({"a" => '06 Nov 04'}, "{{ a | date: '%Y-%m-%d %H:%M:%S %z'}}") # "2004-11-06 00:00:00 +0200"
pp render({"a" => '1994-11-06T08'}, "{{ a | date: '%Y-%m-%d %H:%M:%S %z'}}") # "1994-11-06 00:00:00 +0200"

# target is string representation, source is iterated as collection(and so = match in "year" part)
assertEqual("target is string representation: 2007-11-01 15:25:00 +0900", render({"a" => [{ "time" => t }], "b" => "2007"}, "target is string representation: {{ a | where: 'time', b | map: 'time'}}"))
Expand Down
43 changes: 29 additions & 14 deletions src/main/java/liqp/filters/date/BasicDateParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
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;
Expand Down Expand Up @@ -97,16 +98,6 @@ public static ZonedDateTime getFullDateIfPossible(TemporalAccessor temporal, Zon
if (temporal instanceof Instant) {
return ZonedDateTime.ofInstant((Instant) temporal, defaultZone);
}
TemporalField[] copyThese = new TemporalField[]{
YEAR,
MONTH_OF_YEAR,
DAY_OF_MONTH,
HOUR_OF_DAY,
MINUTE_OF_HOUR,
SECOND_OF_MINUTE,
NANO_OF_SECOND
};


ZoneId zoneId = temporal.query(TemporalQueries.zone());
if (zoneId == null) {
Expand All @@ -115,6 +106,16 @@ public static ZonedDateTime getFullDateIfPossible(TemporalAccessor temporal, Zon

final LocalDateTime now = LocalDateTime.now(zoneId);

TemporalField[] copyThese = new TemporalField[]{
NANO_OF_SECOND,
SECOND_OF_MINUTE,
MINUTE_OF_HOUR,
HOUR_OF_DAY,
DAY_OF_MONTH,
MONTH_OF_YEAR,
YEAR,
};

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))));
Expand All @@ -124,11 +125,25 @@ public static ZonedDateTime getFullDateIfPossible(TemporalAccessor temporal, Zon
}
}


LocalDateTime res = now.with(TemporalAdjusters.ofDateAdjuster(date -> date));
LocalDateTime res = now;
boolean zeroField = true;
for (TemporalField tf: copyThese) {
if (temporal.isSupported(tf)) {
res = res.with(tf, temporal.get(tf));
if (zeroField && temporal.isSupported(tf)) {
zeroField = false;
}
if (zeroField) {
if (temporal.isSupported(tf)) {
long minimum = temporal.range(tf).getMinimum();
res = res.with(tf, minimum);
} else {
res = res.with(tf, tf.range().getMinimum());
}
} else {
if (temporal.isSupported(tf)) {
res = res.with(tf, temporal.get(tf));
} else {
res = res.with(tf, now.get(tf));
}
}
}
return res.atZone(zoneId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public class DatePatternRecognizingContext {

public final Locale locale;
public Boolean hasYear;
public Boolean hasEra;
public Boolean hasMonth;
public Boolean hasDate;
public Boolean weekDay;
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/liqp/filters/date/fuzzy/FuzzyDateParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,12 @@ private List<String> newList(String pattern) {
private GuessingResult getGuessingResult(Stream<String> guessingStream, String normalized, Locale locale, ZoneId defaultZone) {
return guessingStream
.map(pattern -> {
TemporalAccessor temporalAccessor = parseUsingPattern(normalized, pattern, locale);
TemporalAccessor temporalAccessor = null;
try {
temporalAccessor = parseUsingPattern(normalized, pattern, locale);
} catch (Exception e) {
// ignore
}
if (temporalAccessor != null) {
GuessingResult result = new GuessingResult();
result.pattern = pattern;
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/liqp/filters/date/fuzzy/Part.java
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,18 @@ public String toString() {
'}';
}
}
class RecognizedYearWithoutEraPart extends RecognizedPart {
public RecognizedYearWithoutEraPart(int start, int end, List<String> patterns, String source) {
super(start, end, patterns, source);
}

@Override
public String toString() {
return "RecognizedYearWithoutEraPart{" +
"start=" + start +
", end=" + end +
", pattern='" + patterns + '\'' +
'}';
}
}
}
56 changes: 49 additions & 7 deletions src/main/java/liqp/filters/date/fuzzy/PartExtractor.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
package liqp.filters.date.fuzzy;

import static liqp.LValue.isBlank;

import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import liqp.filters.date.fuzzy.Part.NewPart;
import liqp.filters.date.fuzzy.Part.RecognizedMonthNamePart;
import liqp.filters.date.fuzzy.Part.RecognizedPart;
import liqp.filters.date.fuzzy.Part.RecognizedYearWithoutEraPart;
import liqp.filters.date.fuzzy.extractors.PartExtractorResult;

public abstract class PartExtractor {

/**
* for debugging purposes
*/
protected final String name;

public PartExtractor(String name) {
this.name = name;
}

public PartExtractorResult extract(String source, List<Part> parts, int i) {
throw new UnsupportedOperationException("Not supported yet.");
}
Expand Down Expand Up @@ -51,28 +63,58 @@ protected LookupResult getLookupResult(List<Part> parts, int i, PartExtractorRes

parts.remove(i);

int recognizedEnd = part.start() + per.end;
if (per.end != source.length()) {
NewPart after = new NewPart(part.start() + per.end, part.end(), source.substring(per.end));
NewPart after = new NewPart(recognizedEnd, part.end(), source.substring(per.end));
parts.add(i, after);
}

RecognizedPart recognized;
if (per.isMonthName) {
recognized = new RecognizedMonthNamePart(part.start() + per.start, part.start() + per.end, per.formatterPatterns, source.substring(
per.start, per.end));
int recognizedStart = part.start() + per.start;
String recognizedSource = source.substring(per.start, per.end);
if (per.yearWithoutEra) {
recognized = new RecognizedYearWithoutEraPart(recognizedStart, recognizedEnd, per.formatterPatterns, recognizedSource);
} else if (per.isMonthName) {
recognized = new RecognizedMonthNamePart(recognizedStart, recognizedEnd, per.formatterPatterns, recognizedSource);
} else {
recognized = new RecognizedPart(part.start() + per.start, part.start() + per.end, per.formatterPatterns, source.substring(
per.start, per.end));
recognized = new RecognizedPart(recognizedStart, recognizedEnd, per.formatterPatterns, recognizedSource);
}
parts.add(i, recognized);

if (per.start != 0) {
NewPart before = new NewPart(
part.start(), part.start() + per.start, source.substring(0, per.start));
part.start(), recognizedStart, source.substring(0, per.start));
parts.add(i, before);
}

return new LookupResult(per.extractorName, parts, true);
}

protected int getIndexByPartType(List<Part> parts, Class<? extends Part> partType) {
for (int i = 0; i < parts.size(); i++) {
Part part = parts.get(i);
if (partType.isInstance(part)) {
return i;
}
}
return -1;
}

protected LookupResult locatePart(List<Part> parts, PartExtractor extractor, int index) {
Part part = parts.get(index);
if (part instanceof RecognizedPart) {
return new LookupResult(this.name, parts, false);
}
if (part instanceof NewPart) {
NewPart newPart = (NewPart) part;
String source = newPart.source();
if (!isBlank(source) && extractor != null) {
PartExtractorResult result = extractor.extract(source, parts, index);
if (result.found) {
return getLookupResult(parts, index, result);
}
}
}
return null;
}
}
44 changes: 26 additions & 18 deletions src/main/java/liqp/filters/date/fuzzy/PartRecognizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

import static liqp.filters.date.fuzzy.Part.PunctuationPart.punctuationChars;
import static liqp.filters.date.fuzzy.extractors.Extractors.allYMDPatternExtractor;
import static liqp.filters.date.fuzzy.extractors.Extractors.eraAfterYearExtractor;
import static liqp.filters.date.fuzzy.extractors.Extractors.fullWeekdaysExtractor;
import static liqp.filters.date.fuzzy.extractors.Extractors.monthDateExtractor;
import static liqp.filters.date.fuzzy.extractors.Extractors.monthExtractor;
import static liqp.filters.date.fuzzy.extractors.Extractors.monthNameExtractor;
import static liqp.filters.date.fuzzy.extractors.Extractors.plainYearExtractor;
import static liqp.filters.date.fuzzy.extractors.Extractors.regularTimeExtractor;
import static liqp.filters.date.fuzzy.extractors.Extractors.shortWeekdaysExtractor;
Expand All @@ -13,12 +14,8 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import liqp.filters.date.fuzzy.Part.NewPart;
import liqp.filters.date.fuzzy.Part.PunctuationPart;
import liqp.filters.date.fuzzy.Part.RecognizedMonthNamePart;
import liqp.filters.date.fuzzy.Part.RecognizedPart;
import liqp.filters.date.fuzzy.Part.UnrecognizedPart;
import liqp.filters.date.fuzzy.extractors.PartExtractorResult;

public class PartRecognizer {

Expand All @@ -38,13 +35,6 @@ List<Part> recognizePart(List<Part> parts, DatePatternRecognizingContext ctx) {
ctx.weekDay = false;
}

if (notSet(ctx.hasYear)) {
LookupResult result = lookup(parts, yearWithEraExtractor.get(ctx.locale));
if (result.found) {
ctx.hasYear = true;
return result.parts;
}
}
if (notSet(ctx.hasTime)) {
LookupResult result = lookup(parts, regularTimeExtractor.get(ctx.locale));
if (result.found) {
Expand All @@ -61,20 +51,30 @@ List<Part> recognizePart(List<Part> parts, DatePatternRecognizingContext ctx) {
ctx.hasDate = true;
return result.parts;
}
result = lookup(parts, yearWithEraExtractor.get(ctx.locale));
if (result.found) {
ctx.hasYear = true;
ctx.hasEra = true;
return result.parts;
}
result = lookup(parts, plainYearExtractor.get(ctx.locale));
if (result.found) {
ctx.hasYear = true;
return result.parts;
}
}

if (notSet(ctx.hasYear)) {
LookupResult result = lookup(parts, plainYearExtractor.get(ctx.locale));
if (isTrue(ctx.hasYear) && notSet(ctx.hasEra)) {
LookupResult result = lookup(parts, eraAfterYearExtractor.get(ctx.locale));
if (result.found) {
ctx.hasYear = true;
ctx.hasEra = true;
return result.parts;
}
// last "year check" and since we are here - there is no year
ctx.hasYear = false;
ctx.hasEra = false;
}

if (notSet(ctx.hasMonth)) {
LookupResult result = lookup(parts, monthExtractor.get(ctx.locale));
LookupResult result = lookup(parts, monthNameExtractor.get(ctx.locale));
if (result.found) {
ctx.hasMonth = true;
return result.parts;
Expand All @@ -90,6 +90,14 @@ List<Part> recognizePart(List<Part> parts, DatePatternRecognizingContext ctx) {
}
ctx.hasDate = false;
}
//
// if (notSet(ctx.hasYear)) {
// LookupResult result = lookup(parts, twoDigitYearExtractor.get(ctx.locale));
// if (result.found) {
// ctx.hasYear = true;
// return result.parts;
// }
// }

return markAsUnrecognized(parts);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import static liqp.filters.date.fuzzy.extractors.AnyYMDPatternExtractor.pD;
import static liqp.filters.date.fuzzy.extractors.AnyYMDPatternExtractor.pM;
import static liqp.filters.date.fuzzy.extractors.AnyYMDPatternExtractor.pMn;
import static liqp.filters.date.fuzzy.extractors.AnyYMDPatternExtractor.pY2;
import static liqp.filters.date.fuzzy.extractors.AnyYMDPatternExtractor.pY4;
import static liqp.filters.date.fuzzy.extractors.AnyYMDPatternExtractor.pp;
import static liqp.filters.date.fuzzy.extractors.AnyYMDPatternExtractor.pp1;
import static liqp.filters.date.fuzzy.extractors.AnyYMDPatternExtractor.pp2;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -16,39 +18,44 @@ public class AllYMDPatternExtractor extends PartExtractor {
private final List<AnyYMDPatternExtractor> extractors = new ArrayList<>();

public AllYMDPatternExtractor() {
super("AllYMDPatternExtractor");
extractors.add(new AnyYMDPatternExtractor("iSO8601Y4MDPatternExtractor",
pY4(), pp("-"), pM(), pp("-"), pD())); // yyyy-MM-dd
pY4(), pp1("-"), pM(), pp2("-"), pD())); // yyyy-MM-dd

extractors.add(new AnyYMDPatternExtractor("americanY4MDPatternExtractor",
pM(), pp("/"), pD(), pp("/"), pY4())); // MM/dd/yyyy
pM(), pp1("/"), pD(), pp2("/"), pY4())); // MM/dd/yyyy
// next are top-rated locale formats, according to gpt
extractors.add(new AnyYMDPatternExtractor("indianY4MDPatternExtractor",
pD(), pp("-"), pM(), pp("-"), pY4())); // d-M-yyyy
pD(), pp1("-"), pM(), pp2("-"), pY4())); // d-M-yyyy
extractors.add(new AnyYMDPatternExtractor("chineseY4MDPatternExtractor",
pY4(), pp("/"), pM(), pp("/"), pD())); // yyyy/M/d
pY4(), pp1("/"), pM(), pp2("/"), pD())); // yyyy/M/d
extractors.add(new AnyYMDPatternExtractor("englishY4MDPatternExtractor",
pD(), pp("/"), pM(), pp("/"), pY4())); // d/M/yyyy
pD(), pp1("/"), pM(), pp2("/"), pY4())); // d/M/yyyy
extractors.add(new AnyYMDPatternExtractor("slavicY4MDPatternExtractor",
pD(), pp("."), pM(), pp("."), pY4())); // dd.MM.yyyy
pD(), pp1("."), pM(), pp2("."), pY4())); // dd.MM.yyyy
extractors.add(new AnyYMDPatternExtractor("coldEuropeY4MDPatternExtractor",
pY4(), pp("-"), pM(), pp("-"), pD())); // yyyy-MM-dd
pY4(), pp1("-"), pM(), pp2("-"), pD())); // yyyy-MM-dd
extractors.add(new AnyYMDPatternExtractor("espanaY4MDPatternExtractor",
pY4(), pp("-"), pM(), pp("-"), pD())); // yyyy/MM/dd
pY4(), pp1("-"), pM(), pp2("-"), pD())); // yyyy/MM/dd

extractors.add(new AnyYMDPatternExtractor("americanY2MDPatternExtractor",
pM(), pp("/"), pD(), pp("/"), pY2())); // MM/dd/yy
pM(), pp1("/"), pD(), pp2("/"), pY2())); // MM/dd/yy
extractors.add(new AnyYMDPatternExtractor("indianY2MDPatternExtractor",
pD(), pp("-"), pM(), pp("-"), pY2())); // d-M-yy
pD(), pp1("-"), pM(), pp2("-"), pY2())); // d-M-yy
extractors.add(new AnyYMDPatternExtractor("chineseY2MDPatternExtractor",
pY2(), pp("/"), pM(), pp("/"), pD())); // yy/M/d
pY2(), pp1("/"), pM(), pp2("/"), pD())); // yy/M/d
extractors.add(new AnyYMDPatternExtractor("englishY2MDPatternExtractor",
pD(), pp("/"), pM(), pp("/"), pY2())); // d/M/yy
pD(), pp1("/"), pM(), pp2("/"), pY2())); // d/M/yy
extractors.add(new AnyYMDPatternExtractor("slavicY2MDPatternExtractor",
pD(), pp("."), pM(), pp("."), pY2())); // dd.MM.yy
pD(), pp1("."), pM(), pp2("."), pY2())); // dd.MM.yy
extractors.add(new AnyYMDPatternExtractor("coldEuropeY2MDPatternExtractor",
pY2(), pp("-"), pM(), pp("-"), pD())); // yy-MM-dd
pY2(), pp1("-"), pM(), pp2("-"), pD())); // yy-MM-dd
extractors.add(new AnyYMDPatternExtractor("espanaY2MDPatternExtractor",
pY2(), pp("-"), pM(), pp("-"), pD())); // yy/MM/dd
pY2(), pp1("-"), pM(), pp2("-"), pD())); // yy/MM/dd
extractors.add(new AnyYMDPatternExtractor("RFC822Y4MDPatternExtractor",
pD(), pp1(" "), pMn(), pp2(" "), pY4())); // dd MMMM yyyy
extractors.add(new AnyYMDPatternExtractor("RFC822Y2MDPatternExtractor",
pD(), pp1(" "), pMn(), pp2(" "), pY2())); // dd MMMM yy
}

@Override
Expand All @@ -59,6 +66,6 @@ public PartExtractorResult extract(String source, List<Part> parts, int i) {
return result;
}
}
return new PartExtractorResult("AllYMDPatternExtractor");
return new PartExtractorResult(this.name);
}
}
Loading

0 comments on commit 0931d5f

Please sign in to comment.