Skip to content
Open
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
39 changes: 29 additions & 10 deletions src/main/java/org/yamcs/jsle/CcsdsTime.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Optional;
import java.util.ServiceLoader;

import ccsds.sle.transfer.service.common.types.ConditionalTime;
import ccsds.sle.transfer.service.common.types.Time;
Expand All @@ -20,10 +22,24 @@ public class CcsdsTime implements Comparable<CcsdsTime> {

final private int numDays;

/** An optional reference to a time provider, if supplied by the surrounding application. */
private static Optional<TimeProvider> timeProvider = ServiceLoader.load(TimeProvider.class).findFirst();

final private long picosecInDay;
final static DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_INSTANT;
final static DateTimeFormatter FORMATTER_SEC = new DateTimeFormatterBuilder().appendInstant(0).toFormatter();

/**
* Sets the time provider to a specific optional implementation. Default scope
* for unit testing. This method can be used to set a time provider that is not
* found by the service loader.
*
* @param timeProvider an optional time provider
*/
static void setTimeProvider(Optional<TimeProvider> timeProvider) {
CcsdsTime.timeProvider = timeProvider;
}

public CcsdsTime(int numDays, long picosecInDay) {
this.numDays = numDays;
this.picosecInDay = picosecInDay;
Expand Down Expand Up @@ -81,15 +97,19 @@ public static CcsdsTime fromCcsdsPico(byte[] ds) {

/**
* Gets the current time
*
*
* @return the current time
*/
static public CcsdsTime now() {
return fromJavaMillis(System.currentTimeMillis());
public static CcsdsTime now() {
if (timeProvider.isPresent()) {
return timeProvider.get().getSystemTime();
} else {
return fromJavaMillis(System.currentTimeMillis());
}
}

/**
* Converts a java time in milliseconds
* Converts a java time in milliseconds.
*
* @param javaTime
* @return
Expand All @@ -101,8 +121,8 @@ static public CcsdsTime fromJavaMillis(long javaTime) {
}

/**
* Converts a java time in milliseconds
*
* Converts a java time in milliseconds and picoseconds.
*
* @param javaTime
* @return
*/
Expand Down Expand Up @@ -250,8 +270,6 @@ public long toJavaMillisec() {
return ((long) numDays - NUM_DAYS_1958_1970) * MS_IN_DAY + picosecInDay / 1000_000_000;
}



@Override
public int compareTo(CcsdsTime o) {
int x = Integer.compare(numDays, o.numDays);
Expand All @@ -260,15 +278,16 @@ public int compareTo(CcsdsTime o) {
}
return x;
}

/**
* Formats the time with up to nanosecond resolution
*/
@Override
public String toString() {
Instant inst = Instant.ofEpochSecond(((long) numDays - NUM_DAYS_1958_1970) * SEC_IN_DAY, picosecInDay / 1000);
return FORMATTER.format(inst);
}

/**
* Converts to ISO8860 string with 12 digits picoseconds after dot
* @return
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/org/yamcs/jsle/TimeProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.yamcs.jsle;

/**
* Defines an interface that time providers must implement.
*/
public interface TimeProvider {

/**
* Gets the current system time as a <Code>CcsdsTime</code>.
*
* @return the system time, as a CCSDS time
*/
CcsdsTime getSystemTime();

}
73 changes: 66 additions & 7 deletions src/test/java/org/yamcs/jsle/CcsdsTimeTest.java
Original file line number Diff line number Diff line change
@@ -1,47 +1,106 @@
package org.yamcs.jsle;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.time.Instant;
import java.util.Optional;

import org.junit.After;
import org.junit.Test;
import org.yamcs.jsle.CcsdsTime;

import io.netty.buffer.ByteBufUtil;

public class CcsdsTimeTest {

@After
public void cleanup() {
CcsdsTime.setTimeProvider(Optional.empty());
}

@Test
public void test1() {
long t = Instant.parse("1958-01-01T00:00:00Z").toEpochMilli();
byte[] b = CcsdsTime.fromJavaMillis(t).getDaySegmented();
assertEquals("0000000000000000", ByteBufUtil.hexDump(b));

assertEquals(t, CcsdsTime.fromJavaMillis(t).toJavaMillisec());
}

@Test
public void test2() {
String hex = "5764045eb6d00061";

CcsdsTime t = CcsdsTime.fromCcsds(ByteBufUtil.decodeHexDump(hex));
assertEquals(hex, ByteBufUtil.hexDump(t.getDaySegmented()));
}

@Test
public void test3() {
CcsdsTime t = CcsdsTime.fromUnix(3601, 3_000_000);
assertEquals("1970-01-01T01:00:01.003Z", t.toString());
}

@Test
public void test4() {
CcsdsTime t = CcsdsTime.fromUnix(1588711800, 1_000_000);
assertEquals("2020-05-05T20:50:00.001Z", t.toString());
}

@Test
public void test5() {
CcsdsTime t = new CcsdsTime(1, 301123456789012L);
assertEquals("1958-01-02T00:05:01.123456789012Z", t.toStringPico());
}

/**
* Tests that the default time provider gives the current system time.
*/
@Test
public void testDefaultProvider() {
CcsdsTime time1 = CcsdsTime.fromJavaMillis(System.currentTimeMillis());
CcsdsTime now = CcsdsTime.now();
CcsdsTime time2 = CcsdsTime.fromJavaMillis(System.currentTimeMillis());
assertTrue(time1.compareTo(now) <= 0);
assertTrue(now.compareTo(time2) <= 0);
}

/**
* Tests that the time provider can be overridden by one providing
* a simulated time.
*/
@Test
public void testSimulatedTimeProvider() {
MockTimeProvider mockProvider = new MockTimeProvider();
CcsdsTime.setTimeProvider(Optional.of(mockProvider));
CcsdsTime fixedTime = CcsdsTime.fromJavaMillis(12345);
mockProvider.setSystemTime(12345);
CcsdsTime now = CcsdsTime.now();
assertEquals(0, fixedTime.compareTo(now));
}

/**
* Implements a time provider that returns a time set by
* a method call.
*/
private static class MockTimeProvider implements TimeProvider {

private long time;

@Override
public CcsdsTime getSystemTime() {
return CcsdsTime.fromJavaMillis(time);
}

/**
* Sets the time that should be returned.
*
* @param time a time in UNIX milliseconds
*/
public void setSystemTime(long time) {
this.time = time;
}

}

}