Skip to content

Commit 657d268

Browse files
author
pcampalani
committed
Smarter understanding of indexed time dimensions in WCS catalogue.
1 parent beff346 commit 657d268

File tree

2 files changed

+106
-7
lines changed

2 files changed

+106
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.openeo.spring.loaders;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
import java.util.stream.Collectors;
6+
7+
/**
8+
* Official abbreviations of units of measure.
9+
*
10+
* @see <a href="https://ncics.org/portfolio/other-resources/udunits2/">UDUNITS2 Database</a>
11+
*/
12+
public enum TimeUnit {
13+
DAY("d"),
14+
YEAR("yr");
15+
16+
private final String abbrv;
17+
18+
private TimeUnit(String abbrv) {
19+
this.abbrv = abbrv;
20+
}
21+
22+
/**
23+
* Get the abbreviation of this unit of measure.
24+
*/
25+
public String getAbbrv() {
26+
return abbrv;
27+
}
28+
29+
/**
30+
* Returns a list of abbreviations of all available units of measure.
31+
*/
32+
public static List<String> getAllAbbrv() {
33+
return Arrays.asList(TimeUnit.values()).stream()
34+
.map(u -> u.getAbbrv())
35+
.collect(Collectors.toList());
36+
}
37+
}

src/main/java/org/openeo/spring/loaders/WCSCollectionsLoader.java

+69-7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.net.URISyntaxException;
1414
import java.net.URL;
1515
import java.time.OffsetDateTime;
16+
import java.time.ZoneOffset;
1617
import java.time.format.DateTimeFormatter;
1718
import java.time.format.DateTimeParseException;
1819
import java.util.ArrayList;
@@ -732,6 +733,10 @@ else if (TEMPORAL_AXIS_LABELS.contains(label)) {
732733
extent.add(BigDecimal.valueOf(Double.parseDouble(minT)));
733734
extent.add(BigDecimal.valueOf(Double.parseDouble(maxT)));
734735
}
736+
// units of the time dimension
737+
if (label.toUpperCase().equals(TimeUnit.YEAR.name())) {
738+
dim.setUnit(TimeUnit.YEAR.getAbbrv());
739+
}
735740
dim.setExtent(extent);
736741
cubeDimensions.put(label, dim);
737742
}
@@ -896,15 +901,15 @@ else if (TEMPORAL_AXIS_LABELS.contains(label)) {
896901
// TODO what to put when there is no time axis in the original coverage?
897902
CollectionTemporalExtent temporalExtent = new CollectionTemporalExtent();
898903
List<List<OffsetDateTime>> intervals = new ArrayList<>();
899-
904+
List<OffsetDateTime> interval = new ArrayList<>();
905+
DateTimeFormatter fmt = OffsetDateTimeSerializer.FORMATTER;
906+
900907
if (hasTimeCrs) {
901908
// 1+ time dimensions:
902909
for (DimensionTemporal dim : timeDims) {
903910
String minT = dim.getExtent().get(0);
904911
String maxT = dim.getExtent().get(1);
905-
906-
List<OffsetDateTime> interval = new ArrayList<>();
907-
DateTimeFormatter fmt = OffsetDateTimeSerializer.FORMATTER;
912+
908913
try {
909914
//STAC requires format: https://www.rfc-editor.org/rfc/rfc3339#section-5.6
910915
interval.add(OffsetDateTime.parse(minT, fmt));
@@ -917,9 +922,29 @@ else if (TEMPORAL_AXIS_LABELS.contains(label)) {
917922
}
918923

919924
log.debug("Time interval : " + interval);
920-
921925
intervals.add(interval);
922926
}
927+
} else {
928+
// fetch other dimension with temporal type:
929+
List<DimensionOther> otherTimeDims = cubeDimensions.values().stream()
930+
.filter(dim -> dim instanceof DimensionOther)
931+
.filter(dim -> TimeUnit.getAllAbbrv().contains(((DimensionOther)dim).getUnit()))
932+
.map(dim -> (DimensionOther) dim)
933+
.collect(Collectors.toList());
934+
935+
switch (otherTimeDims.size()) {
936+
case 0:
937+
log.warn("No time dimension found in coverage {}.", coverageID);
938+
break;
939+
case 1:
940+
DimensionOther tDim = otherTimeDims.get(0);
941+
interval.addAll(toTimeExtent(tDim));
942+
intervals.add(interval);
943+
break;
944+
default:
945+
log.warn("Multiple \"other\" time dimension found.");
946+
break;
947+
}
923948
}
924949
temporalExtent.setInterval(intervals);
925950
collectionExtent.setTemporal(temporalExtent);
@@ -1036,18 +1061,26 @@ else if (TEMPORAL_AXIS_LABELS.contains(label)) {
10361061
String tempStep = metadataElement.getChildText("Temporal_Step", gmlNS);
10371062
if (null != tempStep) {
10381063
if (!hasTimeCrs) {
1039-
log.warn("Temporal step provided but time axis not found in coverage {}.", coverageID);
1040-
10411064
// fetch other dimension with temporal type:
10421065
List<DimensionOther> otherTimeDims = cubeDimensions.values().stream()
10431066
.filter(dim -> TypeEnum.TEMPORAL.equals(dim.getType()))
10441067
.filter(dim -> dim instanceof DimensionOther)
10451068
.map(dim -> (DimensionOther) dim)
10461069
.collect(Collectors.toList()); //Java 9: .toList());
1070+
otherTimeDims.addAll(cubeDimensions.values().stream()
1071+
.filter(dim -> dim instanceof DimensionOther)
1072+
.filter(dim -> TimeUnit.getAllAbbrv().contains(((DimensionOther)dim).getUnit()))
1073+
.map(dim -> (DimensionOther) dim)
1074+
.collect(Collectors.toList()));
10471075

10481076
for (DimensionOther dim : otherTimeDims) {
10491077
dim.setStep(tempStep);
10501078
}
1079+
1080+
if (otherTimeDims.isEmpty()) {
1081+
log.warn("Temporal step provided but time dimension not found in coverage {}.", coverageID);
1082+
// (..or heuristic for converting other to time is incomplete)
1083+
}
10511084
} else {
10521085
DimensionTemporal dim = timeDims.get(0);
10531086
dim.setStep(tempStep);
@@ -1364,4 +1397,33 @@ else if (TEMPORAL_AXIS_LABELS.contains(label)) {
13641397

13651398
return currentCollection;
13661399
}
1400+
1401+
/**
1402+
* Converts the numeric extent of a dimension of type "other" but
1403+
* with temporal meaning, to time extent (heuristic).
1404+
*
1405+
* @return from/to timestamp of the given time dimension.
1406+
*/
1407+
private static final List<OffsetDateTime> toTimeExtent(DimensionOther dim) {
1408+
if (TypeEnum.TEMPORAL != dim.getType()) {
1409+
log.warn("Input dimension is not temporal");
1410+
//return null;
1411+
// lenient because if type is TEMPORAL the dimension is serialized as TemporalDim anyway in STAC!
1412+
}
1413+
1414+
List<OffsetDateTime> timeExtent = null;
1415+
1416+
if (dim.getUnit().equals(TimeUnit.YEAR.getAbbrv())) {
1417+
int yFrom = dim.getExtent().get(0).toBigInteger().intValue();
1418+
int yUntl = dim.getExtent().get(1).toBigInteger().intValue();
1419+
OffsetDateTime from = OffsetDateTime.of(yFrom, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC);
1420+
OffsetDateTime untl = OffsetDateTime.of(yUntl, 12, 31, 23, 59, 59, 0, ZoneOffset.UTC);
1421+
timeExtent = Arrays.asList(from, untl);
1422+
} else {
1423+
log.error("No time decoding implemented for unit: {}", dim.getUnit());
1424+
}
1425+
1426+
return timeExtent;
1427+
}
1428+
13671429
}

0 commit comments

Comments
 (0)