Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gortools/src/test/java/gorsat/UTestGorWrite.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public void testWritePathWithExistingVersionedLinkFile() throws IOException {

Assert.assertTrue(Files.readString(workDirPath.resolve("dbsnp3.gor.link")).startsWith(
defaultV1LinkFileHeader
+ workDirPath.resolve("dbsnp.gor") + "\t0\t\t0\n"
+ workDirPath.resolve("dbsnp.gor") + "\t1970-01-01T00:00:00Z\t\t0\n"
+ workDirPath.resolve("dbsnp2.gor") + "\t"));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.gorpipe.gor.driver.linkfile;

import org.gorpipe.exceptions.GorResourceException;
import org.gorpipe.util.DateUtils;
import org.gorpipe.util.Strings;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
Expand Down Expand Up @@ -55,13 +57,13 @@ private static LinkFileEntryV1 parseLine(String line) {
}
return new LinkFileEntryV1(
parts[0].trim(),
parts.length > 1 && !Strings.isNullOrEmpty(parts[1]) ? Long.parseLong(parts[1]) : 0,
parts.length > 1 && !Strings.isNullOrEmpty(parts[1]) ? DateUtils.parseDateISOEpoch(parts[1], true).toEpochMilli() : 0,
parts.length > 2 ? parts[2] : "",
parts.length > 3 && !Strings.isNullOrEmpty(parts[3]) ? Integer.parseInt(parts[3]) : 0
);
}

public String format() {
return url + "\t" + timestamp + "\t" + md5 + "\t" + serial;
return url + "\t" + Instant.ofEpochMilli(timestamp) + "\t" + md5 + "\t" + serial;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ private Optional<Credentials> computeCred(CredentialsProvider creds, String look
return Optional.ofNullable(cred);
}
}
log.debug("No credentials available for {}", lookup);
log.warn("No credentials available for {}", lookup);
return Optional.empty();
} catch (IOException e) {
throw new RuntimeException(e);
Expand Down
14 changes: 3 additions & 11 deletions model/src/main/scala/gorsat/Commands/CommandParseUtilities.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import org.gorpipe.exceptions.GorParsingException
import org.gorpipe.gor.driver.meta.DataType
import org.gorpipe.gor.model.GorCommand
import org.gorpipe.gor.util.{DataUtil, StringUtil}
import org.gorpipe.util.DateUtils

import scala.collection.mutable
import scala.collection.mutable.ListBuffer
Expand Down Expand Up @@ -260,18 +261,9 @@ object CommandParseUtilities {
}

def epochValueOfOption(args: Array[String], name: String): Long = {
var optionValue: String = stringValueOfOption(args, name)
val optionValue: String = stringValueOfOption(args, name)
try {
if (optionValue.contains("-")) {
if (!optionValue.contains("T")) {
optionValue = optionValue + "T00:00:00Z"
} else if (!optionValue.contains("Z")) {
optionValue = optionValue + "Z"
}
java.time.Instant.parse(optionValue).toEpochMilli
} else {
optionValue.toLong
}
DateUtils.parseDateISOEpoch(optionValue, true).toEpochMilli
} catch {
case e: Throwable => throw new GorParsingException(s"Value $optionValue supplied with option $name is not a valid iso date/epoch", e)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ public class LinkFileTest {
## SERIAL = 0
## VERSION = 1
#FILE\tTIMESTAMP\tMD5\tSERIAL
source/v1/ver1.gorz\t1734304890790\tABCDEAF13422\t1
source/v1/ver2.gorz\t1734305124533\t334DEAF13422\t2
source/v1/ver1.gorz\t2024-12-15T11:21:30.790Z\tABCDEAF13422\t1
source/v1/ver2.gorz\t2024-12-15T23:25:24.533Z\t334DEAF13422\t2
""";
// 2024-12-15T11:21:30.790Z = 1734261690790
// 2024-12-15T23:25:24.533Z = 1734305124533L
private final String v0LinkFileContent = "source/v0/verx.gorz\n";
private final String simpleFile = "source/y.gorz";
protected Path workPath;
Expand Down Expand Up @@ -79,10 +81,10 @@ public void testGetTimedPath() {
LinkFile linkFile = LinkFile.load(mockSource, v1LinkFileContent);
linkFile.appendEntry(simpleFile, "NEWMD5SUM");

assertEquals(null, linkFile.getEntryUrl(1734304890790L - 100));
assertEquals("/mnt/csa/projects/test/source/v1/ver1.gorz", linkFile.getEntryUrl(1734304890790L + 100));
assertEquals(null, linkFile.getEntryUrl(1734261690790L - 1000));
assertEquals("/mnt/csa/projects/test/source/v1/ver1.gorz", linkFile.getEntryUrl(1734261690790L + 1000));
assertEquals("/mnt/csa/projects/test/source/v1/ver2.gorz", linkFile.getEntryUrl(1734305124533L));
assertEquals("/mnt/csa/projects/test/source/v1/ver2.gorz", linkFile.getEntryUrl(1734305124533L + 100));
assertEquals("/mnt/csa/projects/test/source/v1/ver2.gorz", linkFile.getEntryUrl(1734305124533L + 1000));
assertEquals("/mnt/csa/projects/test/" + simpleFile, linkFile.getEntryUrl(System.currentTimeMillis()));
}

Expand Down
77 changes: 77 additions & 0 deletions util/src/main/java/org/gorpipe/util/DateUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.gorpipe.util;

import java.time.Instant;
import java.time.YearMonth;

public class DateUtils {

/**
* Parse a date string in ISO 8601 format or epoch milliseconds.
*
* Supports partial ISO 8601 dates by appending missing time or timezone information.
*
* @param dateStr the date string to parse
* @param roundUp
* @return the parsed Instant
* @throws IllegalArgumentException if the date string is not in a valid format
*/
public static Instant parseDateISOEpoch(String dateStr, boolean roundUp) {
try {
try {
long epochCandidate = Long.parseLong(dateStr);
if (epochCandidate < 3000) {
// Assume this is a single year.
return parseDateISO(dateStr, roundUp);
} else {
return Instant.ofEpochMilli(epochCandidate);
}
} catch (Exception ignored) {
return parseDateISO(dateStr, roundUp);
}
} catch(Exception e) {
throw new IllegalArgumentException(String.format("Value %s supplied is not a valid iso date/epoch", dateStr), e);
}
}

/**
* Parse a date string in ISO 8601 format.
*
* Supports partial ISO 8601 dates by appending missing time or timezone information.
*
* @param dateStr the date string to parse
* @param roundUp
* @return the parsed Instant
* @throws IllegalArgumentException if the date string is not in a valid format
*/
public static Instant parseDateISO(String dateStr, boolean roundUp) {
try {
int len = dateStr.length();
if (len == 4) {
// Assume this is a single year.
dateStr += roundUp ? "-12-31T23:59:59Z" : "-01-01T00:00:00Z";
} else if (len == 7) {
// Assume this is a year and month.
int year = Integer.parseInt(dateStr.substring(0, 4));
int month = Integer.parseInt(dateStr.substring(5, 7));
dateStr += roundUp ? String.format("-%sT23:59:59Z", YearMonth.of(year, month).lengthOfMonth()) : "-01T00:00:00Z";
} else if (len == 10) {
// Assume this is a full date without time.
dateStr += roundUp ? "T23:59:59Z" : "T00:00:00Z";
} else if (len == 13 && dateStr.charAt(10) == 'T') {
// Assume this is a date and time without seconds or timezone.
dateStr += roundUp ? ":59:59Z" : ":00:00Z";
} else if (len == 16 && dateStr.charAt(10) == 'T') {
// Assume this is a date and time without seconds or timezone.
dateStr += roundUp ? ":59Z" : ":00Z";
} else if (!dateStr.endsWith("Z")) {
// Assume this is a date and time without timezone.
dateStr += "Z";
}

return Instant.parse(dateStr);
} catch(Exception e) {
throw new IllegalArgumentException(String.format("Value %s supplied is not a valid iso date/epoch", dateStr), e);
}
}

}
67 changes: 67 additions & 0 deletions util/src/test/java/org/gorpipe/util/UTestDateUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.gorpipe.util;

import org.junit.Assert;
import org.junit.Test;

public class UTestDateUtils {

@Test
public void testParseDateISOEpochFull() {
Assert.assertEquals("2023-10-05T14:48:00Z", DateUtils.parseDateISOEpoch("2023-10-05T14:48:00Z", false).toString());
Assert.assertEquals("2023-10-05T14:48:00Z", DateUtils.parseDateISOEpoch("2023-10-05T14:48:00Z", true).toString());
}

@Test
public void testParseDateISOEpochDateTimeNoZone() {
Assert.assertEquals("2023-10-05T14:48:00Z", DateUtils.parseDateISOEpoch("2023-10-05T14:48:00", false).toString());
Assert.assertEquals("2023-10-05T14:48:00Z", DateUtils.parseDateISOEpoch("2023-10-05T14:48:00", true).toString());
}

@Test
public void testParseDateISOEpochMillis() {
Assert.assertEquals("2023-11-14T22:13:20Z", DateUtils.parseDateISOEpoch("1700000000000", false).toString());
Assert.assertEquals("2023-11-14T22:13:20Z", DateUtils.parseDateISOEpoch("1700000000000", true).toString());
}

@Test
public void testParseDateISOEpochYearOnly() {
Assert.assertEquals("2023-01-01T00:00:00Z", DateUtils.parseDateISOEpoch("2023", false).toString());
Assert.assertEquals("2023-12-31T23:59:59Z", DateUtils.parseDateISOEpoch("2023", true).toString());
}

@Test
public void testParseDateIsoEpochYearMonthOnly() {
Assert.assertEquals("2023-06-01T00:00:00Z", DateUtils.parseDateISOEpoch("2023-06", false).toString());
Assert.assertEquals("2023-06-30T23:59:59Z", DateUtils.parseDateISOEpoch("2023-06", true).toString());
Assert.assertEquals("2023-02-28T23:59:59Z", DateUtils.parseDateISOEpoch("2023-02", true).toString());
}

@Test
public void testParseDateISOEpochDateOnly() {
Assert.assertEquals("2023-10-05T00:00:00Z", DateUtils.parseDateISOEpoch("2023-10-05", false).toString());
Assert.assertEquals("2023-10-05T23:59:59Z", DateUtils.parseDateISOEpoch("2023-10-05", true).toString());
}

@Test
public void testParseDateIsoEpochHoursOnly() {
Assert.assertEquals("2023-06-15T06:00:00Z", DateUtils.parseDateISOEpoch("2023-06-15T06", false).toString());
Assert.assertEquals("2023-06-15T06:59:59Z", DateUtils.parseDateISOEpoch("2023-06-15T06", true).toString());
}

@Test
public void testParseDateIsoEpochHoursMinutesOnly() {
Assert.assertEquals("2023-06-15T06:30:00Z", DateUtils.parseDateISOEpoch("2023-06-15T06:30", false).toString());
Assert.assertEquals("2023-06-15T06:30:59Z", DateUtils.parseDateISOEpoch("2023-06-15T06:30", true).toString());
}

@Test
public void testParseDateInvalidFormat() {
try {
DateUtils.parseDateISOEpoch("invalid-date", false);
Assert.fail();
} catch (IllegalArgumentException e) {
assert e.getMessage().contains("is not a valid iso date/epoch");
}
}

}
Loading